PluginProbe ʕ •ᴥ•ʔ
Meta Box / 5.9.9
Meta Box v5.9.9
trunk 4.1.10 4.1.11 4.10 4.10.1 4.10.2 4.10.3 4.10.4 4.11 4.11.1 4.11.2 4.12.1 4.12.4 4.12.5 4.12.6 4.13.0 4.13.1 4.13.2 4.13.3 4.13.4 4.14.0 4.14.1 4.14.10 4.14.11 4.14.2 4.14.4 4.14.5 4.14.6 4.14.7 4.14.8 4.14.9 4.15.0 4.15.1 4.15.2 4.15.3 4.15.4 4.15.5 4.15.6 4.15.7 4.15.8 4.15.9 4.16.0 4.16.1 4.16.2 4.16.3 4.17.0 4.17.1 4.17.2 4.17.3 4.18.0 4.18.1 4.18.2 4.18.3 4.18.4 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.3 4.3.1 4.3.10 4.3.11 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.8 4.3.9 4.4.0 4.4.1 4.4.3 4.5 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.5.6 4.5.7 4.6 4.7 4.7.1 4.7.2 4.7.3 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.9 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.6 4.9.7 4.9.8 5.0.0 5.0.1 5.1.0 5.1.1 5.1.2 5.10.0 5.10.1 5.10.10 5.10.11 5.10.12 5.10.13 5.10.14 5.10.15 5.10.16 5.10.17 5.10.18 5.10.19 5.10.2 5.10.3 5.10.4 5.10.5 5.10.6 5.10.7 5.10.8 5.10.9 5.11.0 5.11.1 5.11.2 5.11.3 5.11.4 5.12.0 5.2.0 5.2.1 5.2.10 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.10 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.3.8 5.3.9 5.4.0 5.4.1 5.4.2 5.4.3 5.4.4 5.4.5 5.4.6 5.4.7 5.4.8 5.5.0 5.5.1 5.6.0 5.6.1 5.6.10 5.6.11 5.6.12 5.6.13 5.6.14 5.6.15 5.6.16 5.6.17 5.6.18 5.6.2 5.6.3 5.6.4 5.6.5 5.6.6 5.6.7 5.6.8 5.6.9 5.7.0 5.7.1 5.7.2 5.7.3 5.7.4 5.7.5 5.8.0 5.8.1 5.8.2 5.9.0 5.9.1 5.9.10 5.9.11 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9
meta-box / js / media.js
meta-box / js Last commit date
jqueryui 4 years ago select2 6 years ago validation 2 years ago wp-color-picker-alpha 5 years ago autocomplete.js 6 years ago autosave.js 7 years ago button-group.js 3 years ago clone.js 2 years ago color.js 3 years ago date.js 1 year ago datetime.js 1 year ago file-input.js 4 years ago file-upload.js 2 years ago file.js 3 years ago icon.js 2 years ago image-advanced.js 4 years ago image-select.js 6 years ago image-upload.js 4 years ago input-list.js 1 year ago map-frontend.js 4 years ago map.js 2 years ago media.js 3 years ago modal.js 1 year ago oembed.js 2 years ago osm-frontend.js 5 years ago osm.js 2 years ago post.js 1 year ago range.js 4 years ago script.js 3 years ago select-advanced.js 2 years ago select-tree.js 5 years ago select.js 3 years ago slider.js 6 years ago taxonomy.js 1 year ago time.js 1 year ago user.js 1 year ago video.js 6 years ago wysiwyg.js 2 years ago
media.js
590 lines
1 ( function ( $, wp, _, rwmb, i18n ) {
2 'use strict';
3
4 var views = rwmb.views = rwmb.views || {},
5 models = rwmb.models = rwmb.models || {},
6 media = wp.media,
7 MediaFrame = media.view.MediaFrame,
8 MediaCollection, Controller, MediaField, MediaList, MediaItem, MediaButton, MediaStatus, EditMedia,
9 MediaDetails, MediaLibrary, MediaSelect;
10
11 MediaCollection = Backbone.Collection.extend( {
12 model: wp.media.model.Attachment,
13
14 initialize: function ( models, options ) {
15 this.controller = options.controller || new models.Controller;
16 this.on( 'add remove reset', function () {
17 var max = this.controller.get( 'maxFiles' );
18 this.controller.set( 'length', this.length );
19 this.controller.set( 'full', max > 0 && this.length >= max );
20 } );
21 },
22
23 add: function ( models, options ) {
24 var max = this.controller.get( 'maxFiles' ),
25 left = max - this.length;
26
27 if ( ! models || ( max > 0 && left <= 0 ) ) {
28 return this;
29 }
30 if ( ! models.hasOwnProperty( 'length' ) ) {
31 models = [models];
32 } else if ( models instanceof media.model.Attachments ) {
33 models = models.models;
34 }
35
36 models = _.difference( models, this.models );
37 if ( left > 0 ) {
38 models = _.first( models, left );
39 }
40
41 Backbone.Collection.prototype.add.call( this, models, options );
42 },
43
44 remove: function ( models, options ) {
45 // Don't remove models if event is not fired from MB plugin.
46 if( ! $( event.target ).closest( '.rwmb-field, [data-class="rwmb-field"]' ).length ) {
47 return;
48 }
49 models = Backbone.Collection.prototype.remove.call( this, models, options );
50 if ( this.controller.get( 'forceDelete' ) === true ) {
51 models = ! _.isArray( models ) ? [models] : models;
52 _.each( models, function ( model ) {
53 model.destroy();
54 } );
55 }
56 },
57
58 destroyAll: function () {
59 _.each( _.clone( this.models ), function ( model ) {
60 model.destroy();
61 } );
62 }
63 } );
64
65 /***
66 * Controller Model
67 * Manages data of media field and media models. Most of the media views will use this to manage the media
68 */
69 Controller = models.Controller = Backbone.Model.extend( {
70 //Default options
71 defaults: {
72 maxFiles: 0,
73 ids: [],
74 mimeType: '',
75 forceDelete: false,
76 maxStatus: true,
77 length: 0
78 },
79
80 //Initialize Controller model
81 initialize: function () {
82 // All numbers, no 0 ids
83 this.set( 'ids', _.without( _.map( this.get( 'ids' ), Number ), 0, - 1 ) );
84
85 // Create items collection
86 this.set( 'items', new MediaCollection( [], {controller: this} ) );
87
88 // Listen for destroy event on controller, delete all models when triggered
89 this.on( 'destroy', function () {
90 if ( this.get( 'forceDelete' ) ) {
91 this.get( 'items' ).destroyAll();
92 }
93 } );
94 }
95 } );
96
97 /***
98 * MediaField
99 * Sets up media field view and subviews
100 */
101 MediaField = views.MediaField = Backbone.View.extend( {
102 className: 'rwmb-media-view',
103 initialize: function ( options ) {
104 var that = this,
105 fieldName = options.input.name;
106 this.$input = $( options.input );
107
108 if ( 1 != this.$input.attr( 'data-single-image' ) ) {
109 fieldName += '[]';
110 }
111
112 this.controller = new Controller( _.extend(
113 {
114 fieldName: fieldName,
115 ids: this.$input.val().split( ',' )
116 },
117 this.$input.data( 'options' )
118 ) );
119
120 // Create views
121 this.createList();
122 this.createAddButton();
123 this.createStatus();
124
125 this.render();
126 this.loadInitialAttachments();
127
128 // Listen for destroy event on input
129 this.$input.on( 'remove', function () {
130 that.controller.destroy();
131 } );
132
133 var collection = this.controller.get( 'items' );
134 this.$input.on( 'media:reset', function() {
135 collection.reset();
136 } );
137
138 collection.on( 'all', _.debounce( function() {
139 var ids = collection.pluck( 'id' ).join( ',' );
140 that.$input.val( ids ).trigger( 'change', [that.$( '.rwmb-media-input' )] );
141 }, 500 ) );
142 },
143
144 loadInitialAttachments: function () {
145 if ( ! this.$input.val() ) {
146 return;
147 }
148 var models = this.$input.data( 'attachments' ).map( function( attachment ) {
149 return wp.media.model.Attachment.create( attachment );
150 } );
151 this.controller.get( 'items' ).add( models );
152 },
153
154 // Creates media list
155 createList: function () {
156 this.list = new MediaList( {controller: this.controller} );
157 },
158
159 // Creates button that adds media
160 createAddButton: function () {
161 this.addButton = new MediaButton( {controller: this.controller} );
162 },
163
164 // Creates status
165 createStatus: function () {
166 this.status = new MediaStatus( {controller: this.controller} );
167 },
168
169 // Render field and adds sub fields
170 render: function () {
171 // Empty then add parts
172 this.$el.empty().append(
173 this.list.el,
174 this.status.el,
175 this.addButton.el
176 );
177 }
178 } );
179
180 /***
181 * Media List
182 * lists media
183 */
184 MediaList = views.MediaList = Backbone.View.extend( {
185 tagName: 'ul',
186 className: 'rwmb-media-list',
187
188 initialize: function ( options ) {
189 this.controller = options.controller;
190 this.collection = this.controller.get( 'items' );
191 this.itemView = options.itemView || MediaItem;
192 this.getItemView = _.memoize( function ( item ) {
193 var itemView = new this.itemView( {
194 model: item,
195 controller: this.controller
196 } );
197
198 this.listenToItemView( itemView );
199
200 return itemView;
201 },
202 function ( item ) {
203 return item.cid;
204 }
205 );
206
207 this.listenTo( this.collection, 'add', this.addItemView );
208 this.listenTo( this.collection, 'remove', this.removeItemView );
209 this.listenTo( this.collection, 'reset', this.resetItemViews );
210
211 // Sort items using helper 'clone' to prevent trigger click on the image, which means reselect.
212 this.$el.sortable( {
213 helper : 'clone',
214 start: function ( event, ui ) {
215 ui.placeholder.height( ui.helper.outerHeight() );
216 ui.placeholder.width( ui.helper.outerWidth() );
217 },
218 update: function( event, ui ) {
219 ui.item.find( rwmb.inputSelectors ).first().trigger( 'mb_change' );
220 }
221 } );
222 },
223
224 listenToItemView: function ( itemView ) {
225 this.listenTo( itemView, 'click:remove', this.removeItem );
226 this.listenTo( itemView, 'click:switch', this.switchItem );
227 this.listenTo( itemView, 'click:edit', this.editItem );
228 },
229
230 addItemView: function ( item ) {
231 var index = this.collection.indexOf( item ),
232 itemEl = this.getItemView( item ).el,
233 $children = this.$el.children();
234
235 if ( 0 >= index ) {
236 this.$el.prepend( itemEl );
237 } else if ( $children.length <= index ) {
238 this.$el.append( itemEl )
239 } else {
240 $children.eq( index - 1 ).after( itemEl );
241 }
242 },
243
244 // Remove item view
245 removeItemView: function ( item ) {
246 this.getItemView( item ).$el.detach();
247 },
248
249 removeItem: function ( item ) {
250 this.collection.remove( item );
251 },
252
253 resetItemViews: function( items ){
254 var that = this;
255 _.each( that.models, that.removeItemView );
256 items.each( that.addItemView );
257 },
258
259 switchItem: function ( item ) {
260 if ( this._switchFrame ) {
261 this._switchFrame.dispose();
262 }
263 this._switchFrame = new MediaSelect( {
264 multiple: false,
265 editing: true,
266 library: {
267 type: this.controller.get( 'mimeType' )
268 },
269 edit: this.collection
270 } );
271
272 // Refresh content when frame opens
273 this._switchFrame.on( 'open', function() {
274 var frameContent = this._switchFrame.content.get();
275 if ( frameContent && frameContent.collection ) {
276 frameContent.collection.mirroring._hasMore = true;
277 frameContent.collection.more();
278 }
279 }, this );
280
281 this._switchFrame.on( 'select', function () {
282 var selection = this._switchFrame.state().get( 'selection' ),
283 collection = this.collection,
284 index = collection.indexOf( item );
285
286 if ( ! _.isEmpty( selection ) ) {
287 collection.remove( item );
288 collection.add( selection, {at: index} );
289 }
290 }, this );
291
292 this._switchFrame.open();
293 return false;
294 },
295
296 editItem: function ( item ) {
297 if ( this._editFrame ) {
298 this._editFrame.dispose();
299 }
300
301 // Trigger the media frame to open the correct item.
302 this._editFrame = new EditMedia( {
303 frame: 'edit-attachments',
304 controller: {
305 gridRouter: new wp.media.view.MediaFrame.Manage.Router()
306 },
307 library: this.collection,
308 model: item
309 } );
310
311 this._editFrame.open();
312 }
313 } );
314
315 /***
316 * MediaStatus view.
317 * Show number of selected/uploaded files and number of files remain if "maxStatus" parameter is true.
318 */
319 MediaStatus = views.MediaStatus = Backbone.View.extend( {
320 tagName: 'div',
321 className: 'rwmb-media-status',
322 template: wp.template( 'rwmb-media-status' ),
323
324 initialize: function ( options ) {
325 this.controller = options.controller;
326
327 // Auto hide if maxStatus is false
328 if ( ! this.controller.get( 'maxStatus' ) ) {
329 this.$el.hide();
330 return;
331 }
332
333 // Re-render if changes happen in controller
334 this.listenTo( this.controller.get( 'items' ), 'update', this.render );
335 this.listenTo( this.controller.get( 'items' ), 'reset', this.render );
336
337 // Render
338 this.render();
339 },
340
341 render: function () {
342 this.$el.html( this.template( this.controller.toJSON() ) );
343 }
344 } );
345
346 /***
347 * Media Button
348 * Selects and adds media to controller
349 */
350 MediaButton = views.MediaButton = Backbone.View.extend( {
351 tagName: 'div',
352 className: 'rwmb-media-add',
353 template: wp.template( 'rwmb-media-button' ),
354 events: {
355 'click .button': function () {
356 if ( this._frame ) {
357 this._frame.dispose();
358 }
359 var maxFiles = this.controller.get( 'maxFiles' );
360 this._frame = new MediaSelect( {
361 multiple: maxFiles > 1 || maxFiles <= 0 ? 'add' : false,
362 editing: true,
363 library: {
364 type: this.controller.get( 'mimeType' )
365 },
366 edit: this.collection
367 } );
368
369 // Refresh content when frame opens
370 this._frame.on( 'open', function() {
371 var frameContent = this._frame.content.get();
372 if ( frameContent && frameContent.collection ) {
373 frameContent.collection.mirroring._hasMore = true;
374 frameContent.collection.more();
375 }
376 }, this );
377
378 this._frame.on( 'select', function () {
379 var selection = this._frame.state().get( 'selection' );
380 if ( this.controller.get( 'addTo' ) === 'beginning' ) {
381 this.collection.add( selection.models, {at: 0} );
382 } else {
383 this.collection.add( selection.models );
384 }
385 }, this );
386
387 this._frame.open();
388 }
389 },
390 render: function () {
391 this.$el.html( this.template( {text: i18n.add} ) );
392 return this;
393 },
394
395 initialize: function ( options ) {
396 this.controller = options.controller;
397 this.collection = this.controller.get( 'items' );
398
399 // Auto hide if you reach the max number of media
400 this.listenTo( this.controller, 'change:full', function () {
401 this.$el.toggle( ! this.controller.get( 'full' ) );
402 } );
403
404 this.render();
405 }
406 } );
407
408 /***
409 * MediaItem
410 * View for individual media items
411 */
412 MediaItem = views.MediaItem = Backbone.View.extend( {
413 tagName: 'li',
414 className: 'rwmb-file',
415 template: wp.template( 'rwmb-media-item' ),
416 initialize: function ( options ) {
417 this.controller = options.controller;
418 this.collection = this.controller.get( 'items' );
419 this.render();
420 this.listenTo( this.model, 'change', this.render );
421
422 this.$el.data( 'id', this.model.cid );
423 },
424
425 events: {
426 'click .rwmb-image-overlay': function ( e ) {
427 e.preventDefault();
428 this.trigger( 'click:switch', this.model );
429 },
430 'click .rwmb-remove-media': function ( e ) {
431 e.preventDefault();
432 this.trigger( 'click:remove', this.model );
433 },
434 'click .rwmb-edit-media': function ( e ) {
435 e.preventDefault();
436 this.trigger( 'click:edit', this.model );
437 }
438 },
439
440 render: function () {
441 var data = this.model.toJSON();
442 data.controller = this.controller.toJSON();
443 this.$el.html( this.template( data ) );
444 return this;
445 }
446 } );
447
448 /**
449 * Extend media frames to make things work right
450 */
451
452 /**
453 * MediaDetails
454 * Custom version of TwoColumn view to prevent all video and audio from being unset
455 */
456 MediaDetails = views.MediaDetails = media.view.Attachment.Details.TwoColumn.extend( {
457 render: function () {
458 var that = this;
459 media.view.Attachment.Details.prototype.render.apply( this, arguments );
460 this.players = this.players || [];
461
462 media.mixin.unsetPlayers.call( this );
463
464 this.$( 'audio, video' ).each( function ( i, elem ) {
465 var el = media.view.MediaDetails.prepareSrc( elem );
466 that.players.push( new window.MediaElementPlayer( el, media.mixin.mejsSettings ) );
467 } );
468 }
469 } );
470
471 /**
472 * MediaLibrary
473 * Custom version of Library to exclude already selected media in a media frame
474 */
475 MediaLibrary = media.controller.Library.extend( {
476 defaults: _.defaults( {
477 multiple: 'add',
478 filterable: 'all',
479 priority: 100,
480 syncSelection: false
481 }, media.controller.Library.prototype.defaults ),
482
483 activate: function () {
484 var library = this.get( 'library' ),
485 edit = this.frame.options.edit;
486
487 if ( this.editLibrary && this.editLibrary !== edit ) {
488 library.unobserve( this.editLibrary );
489 }
490
491 // Accepts attachments that exist in the original library and
492 // that do not exist in gallery's library.
493 library.validator = function ( attachment ) {
494 return ! ! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && media.model.Selection.prototype.validator.apply( this, arguments );
495 };
496
497 // Reset the library to ensure that all attachments are re-added
498 // to the collection. Do so silently, as calling `observe` will
499 // trigger the `reset` event.
500 library.reset( library.mirroring.models, {silent: true} );
501 library.observe( edit );
502 this.editLibrary = edit;
503
504 media.controller.Library.prototype.activate.apply( this, arguments );
505 }
506 } );
507
508 /**
509 * MediaSelect
510 * Custom version of Select media frame that uses MediaLibrary
511 */
512 MediaSelect = views.MediaSelect = MediaFrame.Select.extend( {
513 /**
514 * Create the default states on the frame.
515 */
516 createStates: function () {
517 var options = this.options;
518
519 // Add reference so we know MediaFrame belongs to MB plugin.
520 this.$el.attr( 'data-class', 'rwmb-field' );
521
522 if ( this.options.states ) {
523 return;
524 }
525
526 // Add the default states.
527 this.states.add( [
528 // Main states.
529 new MediaLibrary( {
530 library: media.query( options.library ),
531 multiple: options.multiple,
532 priority: 20
533 } )
534 ] );
535 }
536 } );
537
538 /***
539 * EditMedia
540 * Custom version of EditAttachments frame to prevent all video and audio from being unset
541 */
542 EditMedia = views.EditMedia = MediaFrame.EditAttachments.extend( {
543 /**
544 * Content region rendering callback for the `edit-metadata` mode.
545 *
546 * @param {Object} contentRegion Basic object with a `view` property, which
547 * should be set with the proper region view.
548 */
549 editMetadataMode: function ( contentRegion ) {
550 contentRegion.view = new MediaDetails( {
551 controller: this,
552 model: this.model
553 } );
554
555 /**
556 * Attach a subview to display fields added via the
557 * `attachment_fields_to_edit` filter.
558 */
559 contentRegion.view.views.set( '.attachment-compat', new media.view.AttachmentCompat( {
560 controller: this,
561 model: this.model
562 } ) );
563 },
564 resetRoute: function() {}
565 } );
566
567 function initMediaField() {
568 var $this = $( this ),
569 view = $this.data( 'view' );
570
571 if ( view ) {
572 return;
573 }
574
575 view = new MediaField( { input: this } );
576
577 $this.siblings( '.rwmb-media-view' ).remove();
578 $this.after( view.el );
579 $this.data( 'view', view );
580 }
581
582 function init( e ) {
583 $( e.target ).find( '.rwmb-file_advanced' ).each( initMediaField );
584 }
585
586 rwmb.$document
587 .on( 'mb_ready', init )
588 .on( 'clone', '.rwmb-file_advanced', initMediaField );
589 } )( jQuery, wp, _, rwmb, i18nRwmbMedia );
590