1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
3 baseSettings = window._wpmejsSettings || {},
4 l10n = window._wpMediaViewsL10n || {};
10 mejsSettings: baseSettings,
12 removeAllPlayers: function() {
15 if ( window.mejs && window.mejs.players ) {
16 for ( p in window.mejs.players ) {
17 window.mejs.players[p].pause();
18 this.removePlayer( window.mejs.players[p] );
24 * Override the MediaElement method for removing a player.
25 * MediaElement tries to pull the audio/video tag out of
26 * its container and re-add it to the DOM.
28 removePlayer: function(t) {
29 var featureIndex, feature;
35 // invoke features cleanup
36 for ( featureIndex in t.options.features ) {
37 feature = t.options.features[featureIndex];
38 if ( t['clean' + feature] ) {
40 t['clean' + feature](t);
45 if ( ! t.isDynamic ) {
49 if ( 'native' !== t.media.pluginType ) {
53 delete window.mejs.players[t.id];
61 * Allows any class that has set 'player' to a MediaElementPlayer
62 * instance to remove the player when listening to events.
64 * Examples: modal closes, shortcode properties are removed, etc.
66 unsetPlayers : function() {
67 if ( this.players && this.players.length ) {
68 _.each( this.players, function (player) {
70 wp.media.mixin.removePlayer( player );
78 * Autowire "collection"-type shortcodes
80 wp.media.playlist = new wp.media.collection({
82 editTitle : l10n.editPlaylistTitle,
84 id: wp.media.view.settings.post.id,
95 * Shortcode modeling for audio
96 * `edit()` prepares the shortcode for the media modal
97 * `shortcode()` builds the new shortcode after update
102 coerce : wp.media.coerce,
105 id : wp.media.view.settings.post.id,
113 edit : function( data ) {
114 var frame, shortcode = wp.shortcode.next( 'audio', data ).shortcode;
118 state: 'audio-details',
119 metadata: _.defaults( shortcode.attrs.named, this.defaults )
125 shortcode : function( model ) {
128 _.each( this.defaults, function( value, key ) {
129 model[ key ] = this.coerce( model, key );
131 if ( value === model[ key ] ) {
136 content = model.content;
137 delete model.content;
139 return new wp.shortcode({
148 * Shortcode modeling for video
149 * `edit()` prepares the shortcode for the media modal
150 * `shortcode()` builds the new shortcode after update
155 coerce : wp.media.coerce,
158 id : wp.media.view.settings.post.id,
163 preload : 'metadata',
169 edit : function( data ) {
171 shortcode = wp.shortcode.next( 'video', data ).shortcode,
174 attrs = shortcode.attrs.named;
175 attrs.content = shortcode.content;
179 state: 'video-details',
180 metadata: _.defaults( attrs, this.defaults )
186 shortcode : function( model ) {
189 _.each( this.defaults, function( value, key ) {
190 model[ key ] = this.coerce( model, key );
192 if ( value === model[ key ] ) {
197 content = model.content;
198 delete model.content;
200 return new wp.shortcode({
208 media.model.PostMedia = require( './models/post-media.js' );
209 media.controller.AudioDetails = require( './controllers/audio-details.js' );
210 media.controller.VideoDetails = require( './controllers/video-details.js' );
211 media.view.MediaFrame.MediaDetails = require( './views/frame/media-details.js' );
212 media.view.MediaFrame.AudioDetails = require( './views/frame/audio-details.js' );
213 media.view.MediaFrame.VideoDetails = require( './views/frame/video-details.js' );
214 media.view.MediaDetails = require( './views/media-details.js' );
215 media.view.AudioDetails = require( './views/audio-details.js' );
216 media.view.VideoDetails = require( './views/video-details.js' );
218 },{"./controllers/audio-details.js":2,"./controllers/video-details.js":3,"./models/post-media.js":4,"./views/audio-details.js":5,"./views/frame/audio-details.js":6,"./views/frame/media-details.js":7,"./views/frame/video-details.js":8,"./views/media-details.js":9,"./views/video-details.js":10}],2:[function(require,module,exports){
220 * wp.media.controller.AudioDetails
222 * The controller for the Audio Details state
225 * @augments wp.media.controller.State
226 * @augments Backbone.Model
228 var State = wp.media.controller.State,
229 l10n = wp.media.view.l10n,
232 AudioDetails = State.extend({
235 toolbar: 'audio-details',
236 title: l10n.audioDetailsTitle,
237 content: 'audio-details',
238 menu: 'audio-details',
243 initialize: function( options ) {
244 this.media = options.media;
245 State.prototype.initialize.apply( this, arguments );
249 module.exports = AudioDetails;
251 },{}],3:[function(require,module,exports){
253 * wp.media.controller.VideoDetails
255 * The controller for the Video Details state
258 * @augments wp.media.controller.State
259 * @augments Backbone.Model
261 var State = wp.media.controller.State,
262 l10n = wp.media.view.l10n,
265 VideoDetails = State.extend({
268 toolbar: 'video-details',
269 title: l10n.videoDetailsTitle,
270 content: 'video-details',
271 menu: 'video-details',
276 initialize: function( options ) {
277 this.media = options.media;
278 State.prototype.initialize.apply( this, arguments );
282 module.exports = VideoDetails;
284 },{}],4:[function(require,module,exports){
286 * wp.media.model.PostMedia
288 * Shared model class for audio and video. Updates the model after
289 * "Add Audio|Video Source" and "Replace Audio|Video" states return
292 * @augments Backbone.Model
294 var PostMedia = Backbone.Model.extend({
295 initialize: function() {
296 this.attachment = false;
299 setSource: function( attachment ) {
300 this.attachment = attachment;
301 this.extension = attachment.get( 'filename' ).split('.').pop();
303 if ( this.get( 'src' ) && this.extension === this.get( 'src' ).split('.').pop() ) {
307 if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
308 this.set( this.extension, this.attachment.get( 'url' ) );
310 this.unset( this.extension );
314 changeAttachment: function( attachment ) {
315 this.setSource( attachment );
318 _.each( _.without( wp.media.view.settings.embedExts, this.extension ), function( ext ) {
324 module.exports = PostMedia;
326 },{}],5:[function(require,module,exports){
328 * wp.media.view.AudioDetails
331 * @augments wp.media.view.MediaDetails
332 * @augments wp.media.view.Settings.AttachmentDisplay
333 * @augments wp.media.view.Settings
334 * @augments wp.media.View
335 * @augments wp.Backbone.View
336 * @augments Backbone.View
338 var MediaDetails = wp.media.view.MediaDetails,
341 AudioDetails = MediaDetails.extend({
342 className: 'audio-details',
343 template: wp.template('audio-details'),
345 setMedia: function() {
346 var audio = this.$('.wp-audio-shortcode');
348 if ( audio.find( 'source' ).length ) {
349 if ( audio.is(':hidden') ) {
352 this.media = MediaDetails.prepareSrc( audio.get(0) );
362 module.exports = AudioDetails;
364 },{}],6:[function(require,module,exports){
366 * wp.media.view.MediaFrame.AudioDetails
369 * @augments wp.media.view.MediaFrame.MediaDetails
370 * @augments wp.media.view.MediaFrame.Select
371 * @augments wp.media.view.MediaFrame
372 * @augments wp.media.view.Frame
373 * @augments wp.media.View
374 * @augments wp.Backbone.View
375 * @augments Backbone.View
376 * @mixes wp.media.controller.StateMachine
378 var MediaDetails = wp.media.view.MediaFrame.MediaDetails,
379 MediaLibrary = wp.media.controller.MediaLibrary,
381 l10n = wp.media.view.l10n,
384 AudioDetails = MediaDetails.extend({
388 menu: 'audio-details',
389 content: 'audio-details',
390 toolbar: 'audio-details',
392 title: l10n.audioDetailsTitle,
396 initialize: function( options ) {
397 options.DetailsView = wp.media.view.AudioDetails;
398 options.cancelText = l10n.audioDetailsCancel;
399 options.addText = l10n.audioAddSourceTitle;
401 MediaDetails.prototype.initialize.call( this, options );
404 bindHandlers: function() {
405 MediaDetails.prototype.bindHandlers.apply( this, arguments );
407 this.on( 'toolbar:render:replace-audio', this.renderReplaceToolbar, this );
408 this.on( 'toolbar:render:add-audio-source', this.renderAddSourceToolbar, this );
411 createStates: function() {
413 new wp.media.controller.AudioDetails( {
420 title: l10n.audioReplaceTitle,
421 toolbar: 'replace-audio',
423 menu: 'audio-details'
428 id: 'add-audio-source',
429 title: l10n.audioAddSourceTitle,
430 toolbar: 'add-audio-source',
438 module.exports = AudioDetails;
440 },{}],7:[function(require,module,exports){
442 * wp.media.view.MediaFrame.MediaDetails
445 * @augments wp.media.view.MediaFrame.Select
446 * @augments wp.media.view.MediaFrame
447 * @augments wp.media.view.Frame
448 * @augments wp.media.View
449 * @augments wp.Backbone.View
450 * @augments Backbone.View
451 * @mixes wp.media.controller.StateMachine
453 var Select = wp.media.view.MediaFrame.Select,
454 l10n = wp.media.view.l10n,
457 MediaDetails = Select.extend({
461 menu: 'media-details',
462 content: 'media-details',
463 toolbar: 'media-details',
468 initialize: function( options ) {
469 this.DetailsView = options.DetailsView;
470 this.cancelText = options.cancelText;
471 this.addText = options.addText;
473 this.media = new wp.media.model.PostMedia( options.metadata );
474 this.options.selection = new wp.media.model.Selection( this.media.attachment, { multiple: false } );
475 Select.prototype.initialize.apply( this, arguments );
478 bindHandlers: function() {
479 var menu = this.defaults.menu;
481 Select.prototype.bindHandlers.apply( this, arguments );
483 this.on( 'menu:create:' + menu, this.createMenu, this );
484 this.on( 'content:render:' + menu, this.renderDetailsContent, this );
485 this.on( 'menu:render:' + menu, this.renderMenu, this );
486 this.on( 'toolbar:render:' + menu, this.renderDetailsToolbar, this );
489 renderDetailsContent: function() {
490 var view = new this.DetailsView({
492 model: this.state().media,
493 attachment: this.state().media.attachment
496 this.content.set( view );
499 renderMenu: function( view ) {
500 var lastState = this.lastState(),
501 previous = lastState && lastState.id,
506 text: this.cancelText,
510 frame.setState( previous );
516 separateCancel: new wp.media.View({
517 className: 'separator',
524 setPrimaryButton: function(text, handler) {
525 this.toolbar.set( new wp.media.view.Toolbar({
533 var controller = this.controller;
534 handler.call( this, controller, controller.state() );
535 // Restore and reset the default state.
536 controller.setState( controller.options.state );
544 renderDetailsToolbar: function() {
545 this.setPrimaryButton( l10n.update, function( controller, state ) {
547 state.trigger( 'update', controller.media.toJSON() );
551 renderReplaceToolbar: function() {
552 this.setPrimaryButton( l10n.replace, function( controller, state ) {
553 var attachment = state.get( 'selection' ).single();
554 controller.media.changeAttachment( attachment );
555 state.trigger( 'replace', controller.media.toJSON() );
559 renderAddSourceToolbar: function() {
560 this.setPrimaryButton( this.addText, function( controller, state ) {
561 var attachment = state.get( 'selection' ).single();
562 controller.media.setSource( attachment );
563 state.trigger( 'add-source', controller.media.toJSON() );
568 module.exports = MediaDetails;
570 },{}],8:[function(require,module,exports){
572 * wp.media.view.MediaFrame.VideoDetails
575 * @augments wp.media.view.MediaFrame.MediaDetails
576 * @augments wp.media.view.MediaFrame.Select
577 * @augments wp.media.view.MediaFrame
578 * @augments wp.media.view.Frame
579 * @augments wp.media.View
580 * @augments wp.Backbone.View
581 * @augments Backbone.View
582 * @mixes wp.media.controller.StateMachine
584 var MediaDetails = wp.media.view.MediaFrame.MediaDetails,
585 MediaLibrary = wp.media.controller.MediaLibrary,
586 l10n = wp.media.view.l10n,
589 VideoDetails = MediaDetails.extend({
593 menu: 'video-details',
594 content: 'video-details',
595 toolbar: 'video-details',
597 title: l10n.videoDetailsTitle,
601 initialize: function( options ) {
602 options.DetailsView = wp.media.view.VideoDetails;
603 options.cancelText = l10n.videoDetailsCancel;
604 options.addText = l10n.videoAddSourceTitle;
606 MediaDetails.prototype.initialize.call( this, options );
609 bindHandlers: function() {
610 MediaDetails.prototype.bindHandlers.apply( this, arguments );
612 this.on( 'toolbar:render:replace-video', this.renderReplaceToolbar, this );
613 this.on( 'toolbar:render:add-video-source', this.renderAddSourceToolbar, this );
614 this.on( 'toolbar:render:select-poster-image', this.renderSelectPosterImageToolbar, this );
615 this.on( 'toolbar:render:add-track', this.renderAddTrackToolbar, this );
618 createStates: function() {
620 new wp.media.controller.VideoDetails({
627 title: l10n.videoReplaceTitle,
628 toolbar: 'replace-video',
630 menu: 'video-details'
635 id: 'add-video-source',
636 title: l10n.videoAddSourceTitle,
637 toolbar: 'add-video-source',
644 id: 'select-poster-image',
645 title: l10n.videoSelectPosterImageTitle,
646 toolbar: 'select-poster-image',
648 menu: 'video-details'
654 title: l10n.videoAddTrackTitle,
655 toolbar: 'add-track',
657 menu: 'video-details'
662 renderSelectPosterImageToolbar: function() {
663 this.setPrimaryButton( l10n.videoSelectPosterImageTitle, function( controller, state ) {
664 var urls = [], attachment = state.get( 'selection' ).single();
666 controller.media.set( 'poster', attachment.get( 'url' ) );
667 state.trigger( 'set-poster-image', controller.media.toJSON() );
669 _.each( wp.media.view.settings.embedExts, function (ext) {
670 if ( controller.media.get( ext ) ) {
671 urls.push( controller.media.get( ext ) );
675 wp.ajax.send( 'set-attachment-thumbnail', {
678 thumbnail_id: attachment.get( 'id' )
684 renderAddTrackToolbar: function() {
685 this.setPrimaryButton( l10n.videoAddTrackTitle, function( controller, state ) {
686 var attachment = state.get( 'selection' ).single(),
687 content = controller.media.get( 'content' );
689 if ( -1 === content.indexOf( attachment.get( 'url' ) ) ) {
691 '<track srclang="en" label="English" kind="subtitles" src="',
692 attachment.get( 'url' ),
696 controller.media.set( 'content', content );
698 state.trigger( 'add-track', controller.media.toJSON() );
703 module.exports = VideoDetails;
705 },{}],9:[function(require,module,exports){
706 /* global MediaElementPlayer */
709 * wp.media.view.MediaDetails
712 * @augments wp.media.view.Settings.AttachmentDisplay
713 * @augments wp.media.view.Settings
714 * @augments wp.media.View
715 * @augments wp.Backbone.View
716 * @augments Backbone.View
718 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
722 MediaDetails = AttachmentDisplay.extend({
723 initialize: function() {
724 _.bindAll(this, 'success');
726 this.listenTo( this.controller, 'close', wp.media.mixin.unsetPlayers );
727 this.on( 'ready', this.setPlayer );
728 this.on( 'media:setting:remove', wp.media.mixin.unsetPlayers, this );
729 this.on( 'media:setting:remove', this.render );
730 this.on( 'media:setting:remove', this.setPlayer );
731 this.events = _.extend( this.events, {
732 'click .remove-setting' : 'removeSetting',
733 'change .content-track' : 'setTracks',
734 'click .remove-track' : 'setTracks',
735 'click .add-media-source' : 'addSource'
738 AttachmentDisplay.prototype.initialize.apply( this, arguments );
741 prepare: function() {
743 model: this.model.toJSON()
748 * Remove a setting's UI when the model unsets it
750 * @fires wp.media.view.MediaDetails#media:setting:remove
754 removeSetting : function(e) {
755 var wrap = $( e.currentTarget ).parent(), setting;
756 setting = wrap.find( 'input' ).data( 'setting' );
759 this.model.unset( setting );
760 this.trigger( 'media:setting:remove', this );
768 * @fires wp.media.view.MediaDetails#media:setting:remove
770 setTracks : function() {
773 _.each( this.$('.content-track'), function(track) {
774 tracks += $( track ).val();
777 this.model.set( 'content', tracks );
778 this.trigger( 'media:setting:remove', this );
781 addSource : function( e ) {
782 this.controller.lastMime = $( e.currentTarget ).data( 'mime' );
783 this.controller.setState( 'add-' + this.controller.defaults.id + '-source' );
786 loadPlayer: function () {
787 this.players.push( new MediaElementPlayer( this.media, this.settings ) );
788 this.scriptXhr = false;
792 * @global MediaElementPlayer
794 setPlayer : function() {
797 if ( this.players.length || ! this.media || this.scriptXhr ) {
801 if ( this.model.get( 'src' ).indexOf( 'vimeo' ) > -1 && ! ( 'Froogaloop' in window ) ) {
802 baseSettings = wp.media.mixin.mejsSettings;
803 this.scriptXhr = $.getScript( baseSettings.pluginPath + 'froogaloop.min.js', _.bind( this.loadPlayer, this ) );
812 setMedia : function() {
816 success : function(mejs) {
817 var autoplay = mejs.attributes.autoplay && 'false' !== mejs.attributes.autoplay;
819 if ( 'flash' === mejs.pluginType && autoplay ) {
820 mejs.addEventListener( 'canplay', function() {
829 * @returns {media.view.MediaDetails} Returns itself to allow chaining
832 AttachmentDisplay.prototype.render.apply( this, arguments );
834 setTimeout( _.bind( function() {
838 this.settings = _.defaults( {
839 success : this.success
840 }, wp.media.mixin.mejsSettings );
842 return this.setMedia();
845 resetFocus: function() {
846 this.$( '.embed-media-settings' ).scrollTop( 0 );
851 * When multiple players in the DOM contain the same src, things get weird.
853 * @param {HTMLElement} elem
854 * @returns {HTMLElement}
856 prepareSrc : function( elem ) {
857 var i = MediaDetails.instances++;
858 _.each( $( elem ).find( 'source' ), function( source ) {
861 source.src.indexOf('?') > -1 ? '&' : '?',
871 module.exports = MediaDetails;
873 },{}],10:[function(require,module,exports){
875 * wp.media.view.VideoDetails
878 * @augments wp.media.view.MediaDetails
879 * @augments wp.media.view.Settings.AttachmentDisplay
880 * @augments wp.media.view.Settings
881 * @augments wp.media.View
882 * @augments wp.Backbone.View
883 * @augments Backbone.View
885 var MediaDetails = wp.media.view.MediaDetails,
888 VideoDetails = MediaDetails.extend({
889 className: 'video-details',
890 template: wp.template('video-details'),
892 setMedia: function() {
893 var video = this.$('.wp-video-shortcode');
895 if ( video.find( 'source' ).length ) {
896 if ( video.is(':hidden') ) {
900 if ( ! video.hasClass( 'youtube-video' ) && ! video.hasClass( 'vimeo-video' ) ) {
901 this.media = MediaDetails.prepareSrc( video.get(0) );
903 this.media = video.get(0);
914 module.exports = VideoDetails;