|
1 /* eslint consistent-this: [ "error", "control" ] */ |
|
2 (function( component ) { |
|
3 'use strict'; |
|
4 |
|
5 var GalleryWidgetModel, GalleryWidgetControl, GalleryDetailsMediaFrame; |
|
6 |
|
7 /** |
|
8 * Custom gallery details frame. |
|
9 * |
|
10 * @since 4.9.0 |
|
11 * @class GalleryDetailsMediaFrame |
|
12 * @constructor |
|
13 */ |
|
14 GalleryDetailsMediaFrame = wp.media.view.MediaFrame.Post.extend( { |
|
15 |
|
16 /** |
|
17 * Create the default states. |
|
18 * |
|
19 * @since 4.9.0 |
|
20 * @returns {void} |
|
21 */ |
|
22 createStates: function createStates() { |
|
23 this.states.add([ |
|
24 new wp.media.controller.Library({ |
|
25 id: 'gallery', |
|
26 title: wp.media.view.l10n.createGalleryTitle, |
|
27 priority: 40, |
|
28 toolbar: 'main-gallery', |
|
29 filterable: 'uploaded', |
|
30 multiple: 'add', |
|
31 editable: true, |
|
32 |
|
33 library: wp.media.query( _.defaults({ |
|
34 type: 'image' |
|
35 }, this.options.library ) ) |
|
36 }), |
|
37 |
|
38 // Gallery states. |
|
39 new wp.media.controller.GalleryEdit({ |
|
40 library: this.options.selection, |
|
41 editing: this.options.editing, |
|
42 menu: 'gallery' |
|
43 }), |
|
44 |
|
45 new wp.media.controller.GalleryAdd() |
|
46 ]); |
|
47 } |
|
48 } ); |
|
49 |
|
50 /** |
|
51 * Gallery widget model. |
|
52 * |
|
53 * See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports. |
|
54 * |
|
55 * @since 4.9.0 |
|
56 * @class GalleryWidgetModel |
|
57 * @constructor |
|
58 */ |
|
59 GalleryWidgetModel = component.MediaWidgetModel.extend( {} ); |
|
60 |
|
61 /** |
|
62 * Gallery widget control. |
|
63 * |
|
64 * See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports. |
|
65 * |
|
66 * @since 4.9.0 |
|
67 * @class GalleryWidgetControl |
|
68 * @constructor |
|
69 */ |
|
70 GalleryWidgetControl = component.MediaWidgetControl.extend( { |
|
71 |
|
72 /** |
|
73 * View events. |
|
74 * |
|
75 * @since 4.9.0 |
|
76 * @type {object} |
|
77 */ |
|
78 events: _.extend( {}, component.MediaWidgetControl.prototype.events, { |
|
79 'click .media-widget-gallery-preview': 'editMedia' |
|
80 } ), |
|
81 |
|
82 /** |
|
83 * Initialize. |
|
84 * |
|
85 * @since 4.9.0 |
|
86 * @param {Object} options - Options. |
|
87 * @param {Backbone.Model} options.model - Model. |
|
88 * @param {jQuery} options.el - Control field container element. |
|
89 * @param {jQuery} options.syncContainer - Container element where fields are synced for the server. |
|
90 * @returns {void} |
|
91 */ |
|
92 initialize: function initialize( options ) { |
|
93 var control = this; |
|
94 |
|
95 component.MediaWidgetControl.prototype.initialize.call( control, options ); |
|
96 |
|
97 _.bindAll( control, 'updateSelectedAttachments', 'handleAttachmentDestroy' ); |
|
98 control.selectedAttachments = new wp.media.model.Attachments(); |
|
99 control.model.on( 'change:ids', control.updateSelectedAttachments ); |
|
100 control.selectedAttachments.on( 'change', control.renderPreview ); |
|
101 control.selectedAttachments.on( 'reset', control.renderPreview ); |
|
102 control.updateSelectedAttachments(); |
|
103 |
|
104 /* |
|
105 * Refresh a Gallery widget partial when the user modifies one of the selected attachments. |
|
106 * This ensures that when an attachment's caption is updated in the media modal the Gallery |
|
107 * widget in the preview will then be refreshed to show the change. Normally doing this |
|
108 * would not be necessary because all of the state should be contained inside the changeset, |
|
109 * as everything done in the Customizer should not make a change to the site unless the |
|
110 * changeset itself is published. Attachments are a current exception to this rule. |
|
111 * For a proposal to include attachments in the customized state, see #37887. |
|
112 */ |
|
113 if ( wp.customize && wp.customize.previewer ) { |
|
114 control.selectedAttachments.on( 'change', function() { |
|
115 wp.customize.previewer.send( 'refresh-widget-partial', control.model.get( 'widget_id' ) ); |
|
116 } ); |
|
117 } |
|
118 }, |
|
119 |
|
120 /** |
|
121 * Update the selected attachments if necessary. |
|
122 * |
|
123 * @since 4.9.0 |
|
124 * @returns {void} |
|
125 */ |
|
126 updateSelectedAttachments: function updateSelectedAttachments() { |
|
127 var control = this, newIds, oldIds, removedIds, addedIds, addedQuery; |
|
128 |
|
129 newIds = control.model.get( 'ids' ); |
|
130 oldIds = _.pluck( control.selectedAttachments.models, 'id' ); |
|
131 |
|
132 removedIds = _.difference( oldIds, newIds ); |
|
133 _.each( removedIds, function( removedId ) { |
|
134 control.selectedAttachments.remove( control.selectedAttachments.get( removedId ) ); |
|
135 }); |
|
136 |
|
137 addedIds = _.difference( newIds, oldIds ); |
|
138 if ( addedIds.length ) { |
|
139 addedQuery = wp.media.query({ |
|
140 order: 'ASC', |
|
141 orderby: 'post__in', |
|
142 perPage: -1, |
|
143 post__in: newIds, |
|
144 query: true, |
|
145 type: 'image' |
|
146 }); |
|
147 addedQuery.more().done( function() { |
|
148 control.selectedAttachments.reset( addedQuery.models ); |
|
149 }); |
|
150 } |
|
151 }, |
|
152 |
|
153 /** |
|
154 * Render preview. |
|
155 * |
|
156 * @since 4.9.0 |
|
157 * @returns {void} |
|
158 */ |
|
159 renderPreview: function renderPreview() { |
|
160 var control = this, previewContainer, previewTemplate, data; |
|
161 |
|
162 previewContainer = control.$el.find( '.media-widget-preview' ); |
|
163 previewTemplate = wp.template( 'wp-media-widget-gallery-preview' ); |
|
164 |
|
165 data = control.previewTemplateProps.toJSON(); |
|
166 data.attachments = {}; |
|
167 control.selectedAttachments.each( function( attachment ) { |
|
168 data.attachments[ attachment.id ] = attachment.toJSON(); |
|
169 } ); |
|
170 |
|
171 previewContainer.html( previewTemplate( data ) ); |
|
172 }, |
|
173 |
|
174 /** |
|
175 * Determine whether there are selected attachments. |
|
176 * |
|
177 * @since 4.9.0 |
|
178 * @returns {boolean} Selected. |
|
179 */ |
|
180 isSelected: function isSelected() { |
|
181 var control = this; |
|
182 |
|
183 if ( control.model.get( 'error' ) ) { |
|
184 return false; |
|
185 } |
|
186 |
|
187 return control.model.get( 'ids' ).length > 0; |
|
188 }, |
|
189 |
|
190 /** |
|
191 * Open the media select frame to edit images. |
|
192 * |
|
193 * @since 4.9.0 |
|
194 * @returns {void} |
|
195 */ |
|
196 editMedia: function editMedia() { |
|
197 var control = this, selection, mediaFrame, mediaFrameProps; |
|
198 |
|
199 selection = new wp.media.model.Selection( control.selectedAttachments.models, { |
|
200 multiple: true |
|
201 }); |
|
202 |
|
203 mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() ); |
|
204 selection.gallery = new Backbone.Model( mediaFrameProps ); |
|
205 if ( mediaFrameProps.size ) { |
|
206 control.displaySettings.set( 'size', mediaFrameProps.size ); |
|
207 } |
|
208 mediaFrame = new GalleryDetailsMediaFrame({ |
|
209 frame: 'manage', |
|
210 text: control.l10n.add_to_widget, |
|
211 selection: selection, |
|
212 mimeType: control.mime_type, |
|
213 selectedDisplaySettings: control.displaySettings, |
|
214 showDisplaySettings: control.showDisplaySettings, |
|
215 metadata: mediaFrameProps, |
|
216 editing: true, |
|
217 multiple: true, |
|
218 state: 'gallery-edit' |
|
219 }); |
|
220 wp.media.frame = mediaFrame; // See wp.media(). |
|
221 |
|
222 // Handle selection of a media item. |
|
223 mediaFrame.on( 'update', function onUpdate( newSelection ) { |
|
224 var state = mediaFrame.state(), resultSelection; |
|
225 |
|
226 resultSelection = newSelection || state.get( 'selection' ); |
|
227 if ( ! resultSelection ) { |
|
228 return; |
|
229 } |
|
230 |
|
231 // Copy orderby_random from gallery state. |
|
232 if ( resultSelection.gallery ) { |
|
233 control.model.set( control.mapMediaToModelProps( resultSelection.gallery.toJSON() ) ); |
|
234 } |
|
235 |
|
236 // Directly update selectedAttachments to prevent needing to do additional request. |
|
237 control.selectedAttachments.reset( resultSelection.models ); |
|
238 |
|
239 // Update models in the widget instance. |
|
240 control.model.set( { |
|
241 ids: _.pluck( resultSelection.models, 'id' ) |
|
242 } ); |
|
243 } ); |
|
244 |
|
245 mediaFrame.$el.addClass( 'media-widget' ); |
|
246 mediaFrame.open(); |
|
247 |
|
248 if ( selection ) { |
|
249 selection.on( 'destroy', control.handleAttachmentDestroy ); |
|
250 } |
|
251 }, |
|
252 |
|
253 /** |
|
254 * Open the media select frame to chose an item. |
|
255 * |
|
256 * @since 4.9.0 |
|
257 * @returns {void} |
|
258 */ |
|
259 selectMedia: function selectMedia() { |
|
260 var control = this, selection, mediaFrame, mediaFrameProps; |
|
261 selection = new wp.media.model.Selection( control.selectedAttachments.models, { |
|
262 multiple: true |
|
263 }); |
|
264 |
|
265 mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() ); |
|
266 if ( mediaFrameProps.size ) { |
|
267 control.displaySettings.set( 'size', mediaFrameProps.size ); |
|
268 } |
|
269 mediaFrame = new GalleryDetailsMediaFrame({ |
|
270 frame: 'select', |
|
271 text: control.l10n.add_to_widget, |
|
272 selection: selection, |
|
273 mimeType: control.mime_type, |
|
274 selectedDisplaySettings: control.displaySettings, |
|
275 showDisplaySettings: control.showDisplaySettings, |
|
276 metadata: mediaFrameProps, |
|
277 state: 'gallery' |
|
278 }); |
|
279 wp.media.frame = mediaFrame; // See wp.media(). |
|
280 |
|
281 // Handle selection of a media item. |
|
282 mediaFrame.on( 'update', function onUpdate( newSelection ) { |
|
283 var state = mediaFrame.state(), resultSelection; |
|
284 |
|
285 resultSelection = newSelection || state.get( 'selection' ); |
|
286 if ( ! resultSelection ) { |
|
287 return; |
|
288 } |
|
289 |
|
290 // Copy orderby_random from gallery state. |
|
291 if ( resultSelection.gallery ) { |
|
292 control.model.set( control.mapMediaToModelProps( resultSelection.gallery.toJSON() ) ); |
|
293 } |
|
294 |
|
295 // Directly update selectedAttachments to prevent needing to do additional request. |
|
296 control.selectedAttachments.reset( resultSelection.models ); |
|
297 |
|
298 // Update widget instance. |
|
299 control.model.set( { |
|
300 ids: _.pluck( resultSelection.models, 'id' ) |
|
301 } ); |
|
302 } ); |
|
303 |
|
304 mediaFrame.$el.addClass( 'media-widget' ); |
|
305 mediaFrame.open(); |
|
306 |
|
307 if ( selection ) { |
|
308 selection.on( 'destroy', control.handleAttachmentDestroy ); |
|
309 } |
|
310 |
|
311 /* |
|
312 * Make sure focus is set inside of modal so that hitting Esc will close |
|
313 * the modal and not inadvertently cause the widget to collapse in the customizer. |
|
314 */ |
|
315 mediaFrame.$el.find( ':focusable:first' ).focus(); |
|
316 }, |
|
317 |
|
318 /** |
|
319 * Clear the selected attachment when it is deleted in the media select frame. |
|
320 * |
|
321 * @since 4.9.0 |
|
322 * @param {wp.media.models.Attachment} attachment - Attachment. |
|
323 * @returns {void} |
|
324 */ |
|
325 handleAttachmentDestroy: function handleAttachmentDestroy( attachment ) { |
|
326 var control = this; |
|
327 control.model.set( { |
|
328 ids: _.difference( |
|
329 control.model.get( 'ids' ), |
|
330 [ attachment.id ] |
|
331 ) |
|
332 } ); |
|
333 } |
|
334 } ); |
|
335 |
|
336 // Exports. |
|
337 component.controlConstructors.media_gallery = GalleryWidgetControl; |
|
338 component.modelConstructors.media_gallery = GalleryWidgetModel; |
|
339 |
|
340 })( wp.mediaWidgets ); |