Make WordPress Core

Ticket #27437: 27437.2.diff

File 27437.2.diff, 58.2 KB (added by wonderboymusic, 11 years ago)
  • src/wp-includes/js/media-audiovideo.js

     
     1/* global _wpMediaViewsL10n */
     2
     3(function ($, _, Backbone) {
     4        var media = wp.media, l10n = typeof _wpMediaViewsL10n === 'undefined' ? {} : _wpMediaViewsL10n;
     5
     6        /**
     7         * @mixin
     8         */
     9        wp.media.mixin = {
     10
     11                /**
     12                 * Pauses every instance of MediaElementPlayer
     13                 */
     14                pauseAllPlayers: function () {
     15                        var p;
     16                        if ( window.mejs && window.mejs.players ) {
     17                                for ( p in window.mejs.players ) {
     18                                        window.mejs.players[p].pause();
     19                                }
     20                        }
     21                },
     22
     23                /**
     24                 * Utility to identify the user's browser
     25                 */
     26                ua: {
     27                        is : function (browser) {
     28                                var passes = false, ua = window.navigator.userAgent;
     29
     30                                switch ( browser ) {
     31                                        case 'oldie':
     32                                                passes = ua.match(/MSIE [6-8]/gi) !== null;
     33                                        break;
     34                                        case 'ie':
     35                                                passes = ua.match(/MSIE/gi) !== null;
     36                                        break;
     37                                        case 'ff':
     38                                                passes = ua.match(/firefox/gi) !== null;
     39                                        break;
     40                                        case 'opera':
     41                                                passes = ua.match(/OPR/) !== null;
     42                                        break;
     43                                        case 'safari':
     44                                                passes = ua.match(/safari/gi) !== null && ua.match(/chrome/gi) === null;
     45                                        break;
     46                                        case 'chrome':
     47                                                passes = ua.match(/safari/gi) && ua.match(/chrome/gi) !== null;
     48                                        break;
     49                                }
     50
     51                                return passes;
     52                        }
     53                },
     54
     55                /**
     56                 * Specify compatibility for native playback by browser
     57                 */
     58                compat :{
     59                        'opera' : {
     60                                audio: ['ogg', 'wav'],
     61                                video: ['ogg', 'webm']
     62                        },
     63                        'chrome' : {
     64                                audio: ['ogg', 'mpeg', 'x-ms-wma'],
     65                                video: ['ogg', 'webm', 'mp4', 'm4v', 'mpeg']
     66                        },
     67                        'ff' : {
     68                                audio: ['ogg', 'mpeg'],
     69                                video: ['ogg', 'webm']
     70                        },
     71                        'safari' : {
     72                                audio: ['mpeg', 'wav'],
     73                                video: ['mp4', 'm4v', 'mpeg', 'x-ms-wmv', 'quicktime']
     74                        },
     75                        'ie' : {
     76                                audio: ['mpeg'],
     77                                video: ['mp4', 'm4v', 'mpeg']
     78                        }
     79                },
     80
     81                /**
     82                 * Determine if the passed media contains a <source> that provides
     83                 *  native playback in the user's browser
     84                 *
     85                 * @param {jQuery} media
     86                 * @returns {Boolean}
     87                 */
     88                isCompatible: function ( media ) {
     89                        if ( ! media.find( 'source' ).length ) {
     90                                return false;
     91                        }
     92
     93                        var ua = this.ua, test = false, found = false, sources;
     94
     95                        if ( ua.is( 'oldIE' ) ) {
     96                                return false;
     97                        }
     98
     99                        sources = media.find( 'source' );
     100
     101                        _.find( this.compat, function (supports, browser) {
     102                                if ( ua.is( browser ) ) {
     103                                        found = true;
     104                                        _.each( sources, function (elem) {
     105                                                var audio = new RegExp( 'audio\/(' + supports.audio.join('|') + ')', 'gi' ),
     106                                                        video = new RegExp( 'video\/(' + supports.video.join('|') + ')', 'gi' );
     107
     108                                                if ( elem.type.match( video ) !== null || elem.type.match( audio ) !== null ) {
     109                                                        test = true;
     110                                                }
     111                                        } );
     112                                }
     113
     114                                return test || found;
     115                        } );
     116
     117                        return test;
     118                },
     119
     120                /**
     121                 * Override the MediaElement method for removing a player.
     122                 *      MediaElement tries to pull the audio/video tag out of
     123                 *      its container and re-add it to the DOM.
     124                 */
     125                removePlayer: function() {
     126                        var t = this.player, featureIndex, feature;
     127
     128                        // invoke features cleanup
     129                        for ( featureIndex in t.options.features ) {
     130                                feature = t.options.features[featureIndex];
     131                                if ( t['clean' + feature] ) {
     132                                        try {
     133                                                t['clean' + feature](t);
     134                                        } catch (e) {}
     135                                }
     136                        }
     137
     138                        if ( ! t.isDynamic ) {
     139                                t.$node.remove();
     140                        }
     141
     142                        if ( 'native' !== t.media.pluginType ) {
     143                                t.media.remove();
     144                        }
     145
     146                        delete window.mejs.players[t.id];
     147
     148                        t.container.remove();
     149                        t.globalUnbind();
     150                        delete t.node.player;
     151                },
     152
     153                /**
     154                 * Allows any class that has set 'player' to a MediaElementPlayer
     155                 *  instance to remove the player when listening to events.
     156                 *
     157                 *  Examples: modal closes, shortcode properties are removed, etc.
     158                 */
     159                unsetPlayer : function() {
     160                        if ( this.player ) {
     161                                wp.media.mixin.pauseAllPlayers();
     162                                wp.media.mixin.removePlayer.apply( this );
     163                                this.player = false;
     164                        }
     165                }
     166        };
     167
     168        /**
     169         * Autowire "collection"-type shortcodes
     170         */
     171        wp.media.playlist = new wp.media.collection({
     172                tag: 'playlist',
     173                type : 'audio',
     174                editTitle : l10n.editPlaylistTitle,
     175                defaults : {
     176                        id: wp.media.view.settings.post.id,
     177                        style: 'light',
     178                        tracklist: true,
     179                        tracknumbers: true,
     180                        images: true,
     181                        artists: true
     182                }
     183        });
     184
     185        wp.media['video-playlist'] = new wp.media.collection({
     186                tag: 'video-playlist',
     187                type : 'video',
     188                editTitle : l10n.editVideoPlaylistTitle,
     189                defaults : {
     190                        id: wp.media.view.settings.post.id,
     191                        style: 'light',
     192                        tracklist: false,
     193                        tracknumbers: false,
     194                        images: true
     195                }
     196        });
     197
     198        /**
     199         * Shortcode modeling for audio
     200         *  `edit()` prepares the shortcode for the media modal
     201         *  `shortcode()` builds the new shortcode after update
     202         *
     203         * @namespace
     204         */
     205        wp.media.audio = {
     206                coerce : wp.media.coerce,
     207
     208                defaults : {
     209                        id : wp.media.view.settings.post.id,
     210                        src      : '',
     211                        loop     : false,
     212                        autoplay : false,
     213                        preload  : 'none'
     214                },
     215
     216                edit : function (data) {
     217                        var frame, shortcode = wp.shortcode.next( 'audio', data ).shortcode;
     218                        frame = wp.media({
     219                                frame: 'audio',
     220                                state: 'audio-details',
     221                                metadata: _.defaults(
     222                                        shortcode.attrs.named,
     223                                        wp.media.audio.defaults
     224                                )
     225                        });
     226
     227                        return frame;
     228                },
     229
     230                shortcode : function (shortcode) {
     231                        var self = this;
     232
     233                        _.each( wp.media.audio.defaults, function( value, key ) {
     234                                shortcode[ key ] = self.coerce( shortcode, key );
     235
     236                                if ( value === shortcode[ key ] ) {
     237                                        delete shortcode[ key ];
     238                                }
     239                        });
     240
     241                        return wp.shortcode.string({
     242                                tag:     'audio',
     243                                attrs:   shortcode
     244                        });
     245                }
     246        };
     247
     248        /**
     249         * Shortcode modeling for video
     250         *  `edit()` prepares the shortcode for the media modal
     251         *  `shortcode()` builds the new shortcode after update
     252         *
     253         * @namespace
     254         */
     255        wp.media.video = {
     256                coerce : wp.media.coerce,
     257
     258                defaults : {
     259                        id : wp.media.view.settings.post.id,
     260                        src : '',
     261                        poster : '',
     262                        loop : false,
     263                        autoplay : false,
     264                        preload : 'metadata',
     265                        content : ''
     266                },
     267
     268                edit : function (data) {
     269                        var frame,
     270                                defaults = this.defaults,
     271                                shortcode = wp.shortcode.next( 'video', data ).shortcode,
     272                                attrs;
     273
     274                        attrs = shortcode.attrs.named;
     275                        attrs.content = shortcode.content;
     276
     277                        frame = wp.media({
     278                                frame: 'video',
     279                                state: 'video-details',
     280                                metadata: _.defaults( attrs, defaults )
     281                        });
     282
     283                        return frame;
     284                },
     285
     286                shortcode : function (shortcode) {
     287                        var self = this, content = shortcode.content;
     288                        delete shortcode.content;
     289
     290                        _.each( this.defaults, function( value, key ) {
     291                                shortcode[ key ] = self.coerce( shortcode, key );
     292
     293                                if ( value === shortcode[ key ] ) {
     294                                        delete shortcode[ key ];
     295                                }
     296                        });
     297
     298                        return wp.shortcode.string({
     299                                tag:     'video',
     300                                attrs:   shortcode,
     301                                content: content
     302                        });
     303                }
     304        };
     305
     306        /**
     307         * wp.media.model.PostMedia
     308         *
     309         * @constructor
     310         * @augments Backbone.Model
     311         **/
     312        media.model.PostMedia = Backbone.Model.extend({
     313                initialize: function() {
     314                        this.attachment = false;
     315                },
     316
     317                setSource: function ( attachment ) {
     318                        this.attachment = attachment;
     319                        this.extension = attachment.get('filename' ).split('.').pop();
     320
     321                        if ( this.get( 'src' ) && this.extension === this.get( 'src' ).split('.').pop() ) {
     322                                this.unset( 'src' );
     323                        }
     324
     325                        if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
     326                                this.set( this.extension, this.attachment.get( 'url' ) );
     327                        } else {
     328                                this.unset( this.extension );
     329                        }
     330                },
     331
     332                changeAttachment: function( attachment ) {
     333                        var self = this;
     334
     335                        this.setSource( attachment );
     336
     337                        this.unset( 'src' );
     338                        _.each( _.without( wp.media.view.settings.embedExts, this.extension ), function (ext) {
     339                                self.unset( ext );
     340                        } );
     341                }
     342        });
     343
     344        /**
     345         * wp.media.controller.AudioDetails
     346         *
     347         * @constructor
     348         * @augments wp.media.controller.State
     349         * @augments Backbone.Model
     350         */
     351        media.controller.AudioDetails = media.controller.State.extend({
     352                defaults: _.defaults({
     353                        id: 'audio-details',
     354                        toolbar: 'audio-details',
     355                        title: l10n.audioDetailsTitle,
     356                        content: 'audio-details',
     357                        menu: 'audio-details',
     358                        router: false,
     359                        attachment: false,
     360                        priority: 60,
     361                        editing: false
     362                }, media.controller.Library.prototype.defaults ),
     363
     364                initialize: function( options ) {
     365                        this.media = options.media;
     366                        media.controller.State.prototype.initialize.apply( this, arguments );
     367                }
     368        });
     369
     370        /**
     371         * wp.media.controller.VideoDetails
     372         *
     373         * @constructor
     374         * @augments wp.media.controller.State
     375         * @augments Backbone.Model
     376         */
     377        media.controller.VideoDetails = media.controller.State.extend({
     378                defaults: _.defaults({
     379                        id: 'video-details',
     380                        toolbar: 'video-details',
     381                        title: l10n.videoDetailsTitle,
     382                        content: 'video-details',
     383                        menu: 'video-details',
     384                        router: false,
     385                        attachment: false,
     386                        priority: 60,
     387                        editing: false
     388                }, media.controller.Library.prototype.defaults ),
     389
     390                initialize: function( options ) {
     391                        this.media = options.media;
     392                        media.controller.State.prototype.initialize.apply( this, arguments );
     393                }
     394        });
     395
     396        /**
     397         * wp.media.view.MediaFrame.MediaDetails
     398         *
     399         * @constructor
     400         * @augments wp.media.view.MediaFrame.Select
     401         * @augments wp.media.view.MediaFrame
     402         * @augments wp.media.view.Frame
     403         * @augments wp.media.View
     404         * @augments wp.Backbone.View
     405         * @augments Backbone.View
     406         * @mixes wp.media.controller.StateMachine
     407         */
     408        media.view.MediaFrame.MediaDetails = media.view.MediaFrame.Select.extend({
     409                defaults: {
     410                        id:      'media',
     411                        url:     '',
     412                        menu:    'media-details',
     413                        content: 'media-details',
     414                        toolbar: 'media-details',
     415                        type:    'link',
     416                        priority: 120
     417                },
     418
     419                initialize: function( options ) {
     420                        this.DetailsView = options.DetailsView;
     421                        this.cancelText = options.cancelText;
     422                        this.addText = options.addText;
     423
     424                        this.media = new media.model.PostMedia( options.metadata );
     425                        this.options.selection = new media.model.Selection( this.media.attachment, { multiple: false } );
     426                        media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
     427                },
     428
     429                bindHandlers: function() {
     430                        var menu = this.defaults.menu;
     431
     432                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
     433
     434                        this.on( 'menu:create:' + menu, this.createMenu, this );
     435                        this.on( 'content:render:' + menu, this.renderDetailsContent, this );
     436                        this.on( 'menu:render:' + menu, this.renderMenu, this );
     437                        this.on( 'toolbar:render:' + menu, this.renderDetailsToolbar, this );
     438                },
     439
     440                renderDetailsContent: function() {
     441                        var view = new this.DetailsView({
     442                                controller: this,
     443                                model: this.state().media,
     444                                attachment: this.state().media.attachment
     445                        }).render();
     446
     447                        this.content.set( view );
     448                },
     449
     450                renderMenu: function( view ) {
     451                        var lastState = this.lastState(),
     452                                previous = lastState && lastState.id,
     453                                frame = this;
     454
     455                        view.set({
     456                                cancel: {
     457                                        text:     this.cancelText,
     458                                        priority: 20,
     459                                        click:    function() {
     460                                                if ( previous ) {
     461                                                        frame.setState( previous );
     462                                                } else {
     463                                                        frame.close();
     464                                                }
     465                                        }
     466                                },
     467                                separateCancel: new media.View({
     468                                        className: 'separator',
     469                                        priority: 40
     470                                })
     471                        });
     472
     473                },
     474
     475                renderDetailsToolbar: function() {
     476                        this.toolbar.set( new media.view.Toolbar({
     477                                controller: this,
     478                                items: {
     479                                        select: {
     480                                                style:    'primary',
     481                                                text:     l10n.update,
     482                                                priority: 80,
     483
     484                                                click: function() {
     485                                                        var controller = this.controller,
     486                                                                state = controller.state();
     487
     488                                                        controller.close();
     489
     490                                                        state.trigger( 'update', controller.media.toJSON() );
     491
     492                                                        // Restore and reset the default state.
     493                                                        controller.setState( controller.options.state );
     494                                                        controller.reset();
     495                                                }
     496                                        }
     497                                }
     498                        }) );
     499                },
     500
     501                renderReplaceToolbar: function() {
     502                        this.toolbar.set( new media.view.Toolbar({
     503                                controller: this,
     504                                items: {
     505                                        replace: {
     506                                                style:    'primary',
     507                                                text:     l10n.replace,
     508                                                priority: 80,
     509
     510                                                click: function() {
     511                                                        var controller = this.controller,
     512                                                                state = controller.state(),
     513                                                                selection = state.get( 'selection' ),
     514                                                                attachment = selection.single();
     515
     516                                                        controller.media.changeAttachment( attachment );
     517
     518                                                        state.trigger( 'replace', controller.media.toJSON() );
     519
     520                                                        // Restore and reset the default state.
     521                                                        controller.setState( controller.options.state );
     522                                                        controller.reset();
     523                                                }
     524                                        }
     525                                }
     526                        }) );
     527                },
     528
     529                renderAddSourceToolbar: function() {
     530                        this.toolbar.set( new media.view.Toolbar({
     531                                controller: this,
     532                                items: {
     533                                        replace: {
     534                                                style:    'primary',
     535                                                text:     this.addText,
     536                                                priority: 80,
     537
     538                                                click: function() {
     539                                                        var controller = this.controller,
     540                                                                state = controller.state(),
     541                                                                selection = state.get( 'selection' ),
     542                                                                attachment = selection.single();
     543
     544                                                        controller.media.setSource( attachment );
     545
     546                                                        state.trigger( 'add-source', controller.media.toJSON() );
     547
     548                                                        // Restore and reset the default state.
     549                                                        controller.setState( controller.options.state );
     550                                                        controller.reset();
     551                                                }
     552                                        }
     553                                }
     554                        }) );
     555                }
     556        });
     557
     558        /**
     559         * wp.media.view.MediaFrame.AudioDetails
     560         *
     561         * @constructor
     562         * @augments wp.media.view.MediaFrame.MediaDetails
     563         * @augments wp.media.view.MediaFrame.Select
     564         * @augments wp.media.view.MediaFrame
     565         * @augments wp.media.view.Frame
     566         * @augments wp.media.View
     567         * @augments wp.Backbone.View
     568         * @augments Backbone.View
     569         * @mixes wp.media.controller.StateMachine
     570         */
     571        media.view.MediaFrame.AudioDetails = media.view.MediaFrame.MediaDetails.extend({
     572                defaults: {
     573                        id:      'audio',
     574                        url:     '',
     575                        menu:    'audio-details',
     576                        content: 'audio-details',
     577                        toolbar: 'audio-details',
     578                        type:    'link',
     579                        title:    l10n.audioDetailsTitle,
     580                        priority: 120
     581                },
     582
     583                initialize: function( options ) {
     584                        options.DetailsView = media.view.AudioDetails;
     585                        options.cancelText = l10n.audioDetailsCancel;
     586                        options.addText = l10n.audioAddSourceTitle;
     587
     588                        media.view.MediaFrame.MediaDetails.prototype.initialize.call( this, options );
     589                },
     590
     591                bindHandlers: function() {
     592                        media.view.MediaFrame.MediaDetails.prototype.bindHandlers.apply( this, arguments );
     593
     594                        this.on( 'toolbar:render:replace-audio', this.renderReplaceToolbar, this );
     595                        this.on( 'toolbar:render:add-audio-source', this.renderAddSourceToolbar, this );
     596                },
     597
     598                createStates: function() {
     599                        this.states.add([
     600                                new media.controller.AudioDetails( {
     601                                        media: this.media,
     602                                        editable: false,
     603                                        menu: 'audio-details'
     604                                } ),
     605
     606                                new media.controller.MediaLibrary( {
     607                                        type: 'audio',
     608                                        id: 'replace-audio',
     609                                        title: l10n.audioReplaceTitle,
     610                                        toolbar: 'replace-audio',
     611                                        media: this.media,
     612                                        menu: 'audio-details'
     613                                } ),
     614
     615                                new media.controller.MediaLibrary( {
     616                                        type: 'audio',
     617                                        id: 'add-audio-source',
     618                                        title: l10n.audioAddSourceTitle,
     619                                        toolbar: 'add-audio-source',
     620                                        media: this.media,
     621                                        menu: false
     622                                } )
     623                        ]);
     624                }
     625        });
     626
     627        /**
     628         * wp.media.view.MediaFrame.VideoDetails
     629         *
     630         * @constructor
     631         * @augments wp.media.view.MediaFrame.MediaDetails
     632         * @augments wp.media.view.MediaFrame.Select
     633         * @augments wp.media.view.MediaFrame
     634         * @augments wp.media.view.Frame
     635         * @augments wp.media.View
     636         * @augments wp.Backbone.View
     637         * @augments Backbone.View
     638         * @mixes wp.media.controller.StateMachine
     639         */
     640        media.view.MediaFrame.VideoDetails = media.view.MediaFrame.MediaDetails.extend({
     641                defaults: {
     642                        id:      'video',
     643                        url:     '',
     644                        menu:    'video-details',
     645                        content: 'video-details',
     646                        toolbar: 'video-details',
     647                        type:    'link',
     648                        title:    l10n.videoDetailsTitle,
     649                        priority: 120
     650                },
     651
     652                initialize: function( options ) {
     653                        options.DetailsView = media.view.VideoDetails;
     654                        options.cancelText = l10n.videoDetailsCancel;
     655                        options.addText = l10n.videoAddSourceTitle;
     656
     657                        media.view.MediaFrame.MediaDetails.prototype.initialize.call( this, options );
     658                },
     659
     660                bindHandlers: function() {
     661                        media.view.MediaFrame.MediaDetails.prototype.bindHandlers.apply( this, arguments );
     662
     663                        this.on( 'toolbar:render:replace-video', this.renderReplaceToolbar, this );
     664                        this.on( 'toolbar:render:add-video-source', this.renderAddSourceToolbar, this );
     665                        this.on( 'toolbar:render:select-poster-image', this.renderSelectPosterImageToolbar, this );
     666                        this.on( 'toolbar:render:add-track', this.renderAddTrackToolbar, this );
     667                },
     668
     669                createStates: function() {
     670                        this.states.add([
     671                                new media.controller.VideoDetails({
     672                                        media: this.media,
     673                                        editable: false,
     674                                        menu: 'video-details'
     675                                }),
     676
     677                                new media.controller.MediaLibrary( {
     678                                        type: 'video',
     679                                        id: 'replace-video',
     680                                        title: l10n.videoReplaceTitle,
     681                                        toolbar: 'replace-video',
     682                                        media: this.media,
     683                                        menu: 'video-details'
     684                                } ),
     685
     686                                new media.controller.MediaLibrary( {
     687                                        type: 'video',
     688                                        id: 'add-video-source',
     689                                        title: l10n.videoAddSourceTitle,
     690                                        toolbar: 'add-video-source',
     691                                        media: this.media,
     692                                        menu: false
     693                                } ),
     694
     695                                new media.controller.MediaLibrary( {
     696                                        type: 'image',
     697                                        id: 'select-poster-image',
     698                                        title: l10n.videoSelectPosterImageTitle,
     699                                        toolbar: 'select-poster-image',
     700                                        media: this.media,
     701                                        menu: 'video-details'
     702                                } ),
     703
     704                                new media.controller.MediaLibrary( {
     705                                        type: 'text',
     706                                        id: 'add-track',
     707                                        title: l10n.videoAddTrackTitle,
     708                                        toolbar: 'add-track',
     709                                        media: this.media,
     710                                        menu: 'video-details'
     711                                } )
     712                        ]);
     713                },
     714
     715                renderSelectPosterImageToolbar: function() {
     716                        this.toolbar.set( new media.view.Toolbar({
     717                                controller: this,
     718                                items: {
     719                                        replace: {
     720                                                style:    'primary',
     721                                                text:     l10n.videoSelectPosterImageTitle,
     722                                                priority: 80,
     723
     724                                                click: function() {
     725                                                        var controller = this.controller,
     726                                                                state = controller.state(),
     727                                                                selection = state.get( 'selection' ),
     728                                                                attachment = selection.single();
     729
     730                                                        controller.media.set( 'poster', attachment.get( 'url' ) );
     731
     732                                                        state.trigger( 'set-poster-image', controller.media.toJSON() );
     733
     734                                                        // Restore and reset the default state.
     735                                                        controller.setState( controller.options.state );
     736                                                        controller.reset();
     737                                                }
     738                                        }
     739                                }
     740                        }) );
     741                },
     742
     743                renderAddTrackToolbar: function() {
     744                        this.toolbar.set( new media.view.Toolbar({
     745                                controller: this,
     746                                items: {
     747                                        replace: {
     748                                                style:    'primary',
     749                                                text:     l10n.videoAddTrackTitle,
     750                                                priority: 80,
     751
     752                                                click: function() {
     753                                                        var controller = this.controller,
     754                                                                state = controller.state(),
     755                                                                selection = state.get( 'selection' ),
     756                                                                attachment = selection.single(),
     757                                                                content = controller.media.get( 'content' );
     758
     759                                                        if ( -1 === content.indexOf( attachment.get( 'url' ) ) ) {
     760                                                                content += [
     761                                                                        '<track srclang="en" label="English"kind="subtitles" src="',
     762                                                                        attachment.get( 'url' ),
     763                                                                        '" />'
     764                                                                ].join('');
     765
     766                                                                controller.media.set( 'content', content );
     767                                                        }
     768
     769                                                        state.trigger( 'add-track', controller.media.toJSON() );
     770
     771                                                        // Restore and reset the default state.
     772                                                        controller.setState( controller.options.state );
     773                                                        controller.reset();
     774                                                }
     775                                        }
     776                                }
     777                        }) );
     778                }
     779        });
     780
     781        /**
     782         * wp.media.view.AudioDetails
     783         *
     784         * @contructor
     785         * @augments wp.media.view.MediaDetails
     786         * @augments wp.media.view.Settings.AttachmentDisplay
     787         * @augments wp.media.view.Settings
     788         * @augments wp.media.View
     789         * @augments wp.Backbone.View
     790         * @augments Backbone.View
     791         */
     792        media.view.AudioDetails = media.view.MediaDetails.extend({
     793                className: 'audio-details',
     794                template:  media.template('audio-details'),
     795
     796                setMedia: function() {
     797                        var audio = this.$('.wp-audio-shortcode');
     798
     799                        if ( audio.find( 'source' ).length ) {
     800                                if ( audio.is(':hidden') ) {
     801                                        audio.show();
     802                                }
     803                                this.media = media.view.MediaDetails.prepareSrc( audio.get(0) );
     804                        } else {
     805                                audio.hide();
     806                                this.media = false;
     807                        }
     808
     809                        return this;
     810                }
     811        });
     812
     813        /**
     814         * wp.media.view.VideoDetails
     815         *
     816         * @contructor
     817         * @augments wp.media.view.MediaDetails
     818         * @augments wp.media.view.Settings.AttachmentDisplay
     819         * @augments wp.media.view.Settings
     820         * @augments wp.media.View
     821         * @augments wp.Backbone.View
     822         * @augments Backbone.View
     823         */
     824        media.view.VideoDetails = media.view.MediaDetails.extend({
     825                className: 'video-details',
     826                template:  media.template('video-details'),
     827
     828                setMedia: function() {
     829                        var video = this.$('.wp-video-shortcode');
     830
     831                        if ( video.find( 'source' ).length ) {
     832                                if ( video.is(':hidden') ) {
     833                                        video.show();
     834                                }
     835
     836                                if ( ! video.hasClass('youtube-video') ) {
     837                                        this.media = media.view.MediaDetails.prepareSrc( video.get(0) );
     838                                } else {
     839                                        this.media = video.get(0);
     840                                }
     841                        } else {
     842                                video.hide();
     843                                this.media = false;
     844                        }
     845
     846                        return this;
     847                }
     848        });
     849
     850        _.extend( wp.media.playlist, {
     851                /**
     852                 * Determine how many audio and video files the user has uploaded
     853                 */
     854                counts : (function (settings) {
     855                        var counts = {};
     856
     857                        return  function () {
     858                                if ( ! _.isEmpty( counts ) ) {
     859                                        return counts;
     860                                }
     861
     862                                var a = 0, v = 0;
     863                                _.each( settings.attachmentCounts, function (total, mime) {
     864                                        var type;
     865                                        if ( -1 < mime.indexOf('/') ) {
     866                                                type = mime.split('/')[0];
     867
     868                                                total = parseInt(total, 10);
     869
     870                                                switch ( type ) {
     871                                                        case 'audio':
     872                                                                a += total;
     873                                                        break;
     874                                                        case 'video':
     875                                                                v += total;
     876                                                        break;
     877                                                }
     878                                        }
     879                                } );
     880
     881                                counts.audio = a;
     882                                counts.video = v;
     883
     884                                return counts;
     885                        };
     886                }(media.view.settings)),
     887
     888                /**
     889                 * Return the playlist states for MediaFrame.Post
     890                 *
     891                 * @param {Object} options
     892                 * @returns {Array}
     893                 */
     894                states : function (options) {
     895                        return [
     896                                new media.controller.Library({
     897                                        id:         'playlist',
     898                                        title:      l10n.createPlaylistTitle,
     899                                        priority:   60,
     900                                        toolbar:    'main-playlist',
     901                                        filterable: 'uploaded',
     902                                        multiple:   'add',
     903                                        editable:   false,
     904
     905                                        library:  media.query( _.defaults({
     906                                                type: 'audio'
     907                                        }, options.library ) )
     908                                }),
     909
     910                                // Playlist states.
     911                                new media.controller.CollectionEdit({
     912                                        type:           'audio',
     913                                        collectionType: 'playlist',
     914                                        title:          l10n.editPlaylistTitle,
     915                                        SettingsView:   media.view.Settings.Playlist,
     916                                        library:        options.selection,
     917                                        editing:        options.editing,
     918                                        menu:           'playlist',
     919                                        dragInfoText:   l10n.playlistDragInfo,
     920                                        dragInfo:       false
     921                                }),
     922
     923                                new media.controller.CollectionAdd({
     924                                        type: 'audio',
     925                                        collectionType: 'playlist',
     926                                        title: l10n.addToPlaylistTitle
     927                                })
     928                        ];
     929                },
     930
     931                /**
     932                 * Return the video-playlist states for MediaFrame.Post
     933                 *
     934                 * @param {Object} options
     935                 * @returns {Array}
     936                 */
     937                videoStates : function (options) {
     938                        return [
     939                                new media.controller.Library({
     940                                        id:         'video-playlist',
     941                                        title:      l10n.createVideoPlaylistTitle,
     942                                        priority:   60,
     943                                        toolbar:    'main-video-playlist',
     944                                        filterable: 'uploaded',
     945                                        multiple:   'add',
     946                                        editable:   false,
     947
     948                                        library:  media.query( _.defaults({
     949                                                type: 'video'
     950                                        }, options.library ) )
     951                                }),
     952
     953                                // Video Playlist states.
     954                                new media.controller.CollectionEdit({
     955                                        type:           'video',
     956                                        collectionType: 'video-playlist',
     957                                        title:          l10n.editVideoPlaylistTitle,
     958                                        SettingsView:   media.view.Settings.Playlist,
     959                                        library:        options.selection,
     960                                        editing:        options.editing,
     961                                        menu:           'video-playlist',
     962                                        dragInfoText:   l10n.videoPlaylistDragInfo,
     963                                        dragInfo:       false
     964                                }),
     965
     966                                new media.controller.CollectionAdd({
     967                                        type:           'video',
     968                                        collectionType: 'video-playlist',
     969                                        title:          l10n.addToVideoPlaylistTitle
     970                                })
     971                        ];
     972                }
     973        } );
     974
     975        function init() {
     976                $(document.body)
     977                        .on( 'click', '.wp-switch-editor', wp.media.mixin.pauseAllPlayers )
     978                        .on( 'click', '.add-media-source', function () {
     979                                media.frame.setState('add-' + media.frame.defaults.id + '-source');
     980                        } );
     981        }
     982
     983        $( init );
     984
     985}(jQuery, _, Backbone));
     986 No newline at end of file
  • src/wp-includes/js/media-editor.js

     
    1111        var workflows = {};
    1212
    1313        /**
     14         * A helper mixin function to avoid truthy and falsey values being
     15         *   passed as an input that expects booleans. If key is undefined in the map,
     16         *   but has a default value, set it.
     17         *
     18         * @param {object} attrs Map of props from a shortcode or settings.
     19         * @param {string} key The key within the passed map to check for a value.
     20         * @returns {mixed|undefined} The original or coerced value of key within attrs
     21         */
     22        wp.media.coerce = function ( attrs, key ) {
     23                if ( _.isUndefined( attrs[ key ] ) && ! _.isUndefined( this.defaults[ key ] ) ) {
     24                        attrs[ key ] = this.defaults[ key ];
     25                } else if ( 'true' === attrs[ key ] ) {
     26                        attrs[ key ] = true;
     27                } else if ( 'false' === attrs[ key ] ) {
     28                        attrs[ key ] = false;
     29                }
     30                return attrs[ key ];
     31        };
     32
     33        /**
    1434         * wp.media.string
    1535         * @namespace
    1636         */
     
    274294                }
    275295        };
    276296
    277         /**
    278          * @mixin
    279          */
    280         wp.media.mixin = {
    281                 /**
    282                  * A helper function to avoid truthy and falsey values being
    283                  *   passed as an input that expects booleans. If key is undefined in the map,
    284                  *   but has a default value, set it.
    285                  *
    286                  * @param {object} attrs Map of props from a shortcode or settings.
    287                  * @param {string} key The key within the passed map to check for a value.
    288                  * @returns {mixed|undefined} The original or coerced value of key within attrs
    289                  */
    290                 coerce: function ( attrs, key ) {
    291                         if ( _.isUndefined( attrs[ key ] ) && ! _.isUndefined( this.defaults[ key ] ) ) {
    292                                 attrs[ key ] = this.defaults[ key ];
    293                         } else if ( 'true' === attrs[ key ] ) {
    294                                 attrs[ key ] = true;
    295                         } else if ( 'false' === attrs[ key ] ) {
    296                                 attrs[ key ] = false;
    297                         }
    298                         return attrs[ key ];
    299                 },
    300 
    301                 pauseAllPlayers: function () {
    302                         var p;
    303                         if ( window.mejs && window.mejs.players ) {
    304                                 for ( p in window.mejs.players ) {
    305                                         window.mejs.players[p].pause();
    306                                 }
    307                         }
    308                 },
    309 
    310                 ua: {
    311                         is : function (browser) {
    312                                 var passes = false, ua = window.navigator.userAgent;
    313 
    314                                 switch ( browser ) {
    315                                         case 'oldie':
    316                                                 passes = ua.match(/MSIE [6-8]/gi) !== null;
    317                                         break;
    318                                         case 'ie':
    319                                                 passes = ua.match(/MSIE/gi) !== null;
    320                                         break;
    321                                         case 'ff':
    322                                                 passes = ua.match(/firefox/gi) !== null;
    323                                         break;
    324                                         case 'opera':
    325                                                 passes = ua.match(/OPR/) !== null;
    326                                         break;
    327                                         case 'safari':
    328                                                 passes = ua.match(/safari/gi) !== null && ua.match(/chrome/gi) === null;
    329                                         break;
    330                                         case 'chrome':
    331                                                 passes = ua.match(/safari/gi) && ua.match(/chrome/gi) !== null;
    332                                         break;
    333                                 }
    334 
    335                                 return passes;
    336                         }
    337                 },
    338 
    339                 compat :{
    340                         'opera' : {
    341                                 audio: ['ogg', 'wav'],
    342                                 video: ['ogg', 'webm']
    343                         },
    344                         'chrome' : {
    345                                 audio: ['ogg', 'mpeg', 'x-ms-wma'],
    346                                 video: ['ogg', 'webm', 'mp4', 'm4v', 'mpeg']
    347                         },
    348                         'ff' : {
    349                                 audio: ['ogg', 'mpeg'],
    350                                 video: ['ogg', 'webm']
    351                         },
    352                         'safari' : {
    353                                 audio: ['mpeg', 'wav'],
    354                                 video: ['mp4', 'm4v', 'mpeg', 'x-ms-wmv', 'quicktime']
    355                         },
    356                         'ie' : {
    357                                 audio: ['mpeg'],
    358                                 video: ['mp4', 'm4v', 'mpeg']
    359                         }
    360                 },
    361 
    362                 isCompatible: function ( media ) {
    363                         if ( ! media.find( 'source' ).length ) {
    364                                 return false;
    365                         }
    366 
    367                         var ua = this.ua, test = false, found = false, sources;
    368 
    369                         if ( ua.is( 'oldIE' ) ) {
    370                                 return false;
    371                         }
    372 
    373                         sources = media.find( 'source' );
    374 
    375                         _.find( this.compat, function (supports, browser) {
    376                                 if ( ua.is( browser ) ) {
    377                                         found = true;
    378                                         _.each( sources, function (elem) {
    379                                                 var audio = new RegExp( 'audio\/(' + supports.audio.join('|') + ')', 'gi' ),
    380                                                         video = new RegExp( 'video\/(' + supports.video.join('|') + ')', 'gi' );
    381 
    382                                                 if ( elem.type.match( video ) !== null || elem.type.match( audio ) !== null ) {
    383                                                         test = true;
    384                                                 }
    385                                         } );
    386                                 }
    387 
    388                                 return test || found;
    389                         } );
    390 
    391                         return test;
    392                 },
    393 
    394                 /**
    395                  * Override the MediaElement method for removing a player.
    396                  *      MediaElement tries to pull the audio/video tag out of
    397                  *      its container and re-add it to the DOM.
    398                  */
    399                 removePlayer: function() {
    400                         var t = this.player, featureIndex, feature;
    401 
    402                         // invoke features cleanup
    403                         for ( featureIndex in t.options.features ) {
    404                                 feature = t.options.features[featureIndex];
    405                                 if ( t['clean' + feature] ) {
    406                                         try {
    407                                                 t['clean' + feature](t);
    408                                         } catch (e) {}
    409                                 }
    410                         }
    411 
    412                         if ( ! t.isDynamic ) {
    413                                 t.$node.remove();
    414                         }
    415 
    416                         if ( 'native' !== t.media.pluginType ) {
    417                                 t.media.remove();
    418                         }
    419 
    420                         delete window.mejs.players[t.id];
    421 
    422                         t.container.remove();
    423                         t.globalUnbind();
    424                         delete t.node.player;
    425                 },
    426 
    427                 /**
    428                  * Allows any class that has set 'player' to a MediaElementPlayer
    429                  *  instance to remove the player when listening to events.
    430                  *
    431                  *  Examples: modal closes, shortcode properties are removed, etc.
    432                  */
    433                 unsetPlayer : function() {
    434                         if ( this.player ) {
    435                                 wp.media.mixin.pauseAllPlayers();
    436                                 wp.media.mixin.removePlayer.apply( this );
    437                                 this.player = false;
    438                         }
    439                 }
    440         };
    441 
    442297        wp.media.collection = function(attributes) {
    443298                var collections = {};
    444299
    445300                return _.extend( attributes, {
    446                         coerce : wp.media.mixin.coerce,
     301                        coerce : wp.media.coerce,
    447302                        /**
    448303                         * Retrieve attachments based on the properties of the passed shortcode
    449304                         *
     
    669524                }
    670525        });
    671526
    672         wp.media.playlist = new wp.media.collection({
    673                 tag: 'playlist',
    674                 type : 'audio',
    675                 editTitle : wp.media.view.l10n.editPlaylistTitle,
    676                 defaults : {
    677                         id: wp.media.view.settings.post.id,
    678                         style: 'light',
    679                         tracklist: true,
    680                         tracknumbers: true,
    681                         images: true,
    682                         artists: true
    683                 }
    684         });
    685 
    686         wp.media['video-playlist'] = new wp.media.collection({
    687                 tag: 'video-playlist',
    688                 type : 'video',
    689                 editTitle : wp.media.view.l10n.editVideoPlaylistTitle,
    690                 defaults : {
    691                         id: wp.media.view.settings.post.id,
    692                         style: 'light',
    693                         tracklist: false,
    694                         tracknumbers: false,
    695                         images: true
    696                 }
    697         });
    698 
    699527        /**
    700          * @namespace
    701          */
    702         wp.media.audio = {
    703                 coerce : wp.media.mixin.coerce,
    704 
    705                 defaults : {
    706                         id : wp.media.view.settings.post.id,
    707                         src      : '',
    708                         loop     : false,
    709                         autoplay : false,
    710                         preload  : 'none'
    711                 },
    712 
    713                 edit : function (data) {
    714                         var frame, shortcode = wp.shortcode.next( 'audio', data ).shortcode;
    715                         frame = wp.media({
    716                                 frame: 'audio',
    717                                 state: 'audio-details',
    718                                 metadata: _.defaults(
    719                                         shortcode.attrs.named,
    720                                         wp.media.audio.defaults
    721                                 )
    722                         });
    723 
    724                         return frame;
    725                 },
    726 
    727                 shortcode : function (shortcode) {
    728                         var self = this;
    729 
    730                         _.each( wp.media.audio.defaults, function( value, key ) {
    731                                 shortcode[ key ] = self.coerce( shortcode, key );
    732 
    733                                 if ( value === shortcode[ key ] ) {
    734                                         delete shortcode[ key ];
    735                                 }
    736                         });
    737 
    738                         return wp.shortcode.string({
    739                                 tag:     'audio',
    740                                 attrs:   shortcode
    741                         });
    742                 }
    743         };
    744 
    745         /**
    746          * @namespace
    747          */
    748         wp.media.video = {
    749                 coerce : wp.media.mixin.coerce,
    750 
    751                 defaults : {
    752                         id : wp.media.view.settings.post.id,
    753                         src : '',
    754                         poster : '',
    755                         loop : false,
    756                         autoplay : false,
    757                         preload : 'metadata',
    758                         content : ''
    759                 },
    760 
    761                 edit : function (data) {
    762                         var frame,
    763                                 defaults = this.defaults,
    764                                 shortcode = wp.shortcode.next( 'video', data ).shortcode,
    765                                 attrs;
    766 
    767                         attrs = shortcode.attrs.named;
    768                         attrs.content = shortcode.content;
    769 
    770                         frame = wp.media({
    771                                 frame: 'video',
    772                                 state: 'video-details',
    773                                 metadata: _.defaults( attrs, defaults )
    774                         });
    775 
    776                         return frame;
    777                 },
    778 
    779                 shortcode : function (shortcode) {
    780                         var self = this, content = shortcode.content;
    781                         delete shortcode.content;
    782 
    783                         _.each( this.defaults, function( value, key ) {
    784                                 shortcode[ key ] = self.coerce( shortcode, key );
    785 
    786                                 if ( value === shortcode[ key ] ) {
    787                                         delete shortcode[ key ];
    788                                 }
    789                         });
    790 
    791                         return wp.shortcode.string({
    792                                 tag:     'video',
    793                                 attrs:   shortcode,
    794                                 content: content
    795                         });
    796                 }
    797         };
    798 
    799         /**
    800528         * wp.media.featuredImage
    801529         * @namespace
    802530         */
     
    12791007                                        if ( elem.hasClass( 'gallery' ) ) {
    12801008                                                options.state = 'gallery';
    12811009                                                options.title = wp.media.view.l10n.createGalleryTitle;
    1282                                         } else if ( elem.hasClass( 'playlist' ) ) {
    1283                                                 options.state = 'playlist';
    1284                                                 options.title = wp.media.view.l10n.createPlaylistTitle;
    1285                                         } else if ( elem.hasClass( 'video-playlist' ) ) {
    1286                                                 options.state = 'video-playlist';
    1287                                                 options.title = wp.media.view.l10n.createVideoPlaylistTitle;
    12881010                                        }
    12891011
    12901012                                        wp.media.editor.open( editor, options );
    1291                                 })
    1292                                 .on( 'click', '.wp-switch-editor', wp.media.mixin.pauseAllPlayers );
     1013                                });
    12931014
    12941015                        // Initialize and render the Editor drag-and-drop uploader.
    12951016                        new wp.media.view.EditorUploader().render();
  • src/wp-includes/js/media-models.js

     
    4040
    4141                delete attributes.frame;
    4242
     43                media.frame = frame;
     44
    4345                return frame;
    4446        };
    4547
     
    453455        });
    454456
    455457        /**
    456          * wp.media.model.PostMedia
    457          *
    458          * @constructor
    459          * @augments Backbone.Model
    460          **/
    461         media.model.PostMedia = Backbone.Model.extend({
    462                 initialize: function() {
    463                         this.attachment = false;
    464                 },
    465 
    466                 setSource: function ( attachment ) {
    467                         this.attachment = attachment;
    468                         this.extension = attachment.get('filename' ).split('.').pop();
    469 
    470                         if ( this.get( 'src' ) && this.extension === this.get( 'src' ).split('.').pop() ) {
    471                                 this.unset( 'src' );
    472                         }
    473 
    474                         if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
    475                                 this.set( this.extension, this.attachment.get( 'url' ) );
    476                         } else {
    477                                 this.unset( this.extension );
    478                         }
    479                 },
    480 
    481                 changeAttachment: function( attachment ) {
    482                         var self = this;
    483 
    484                         this.setSource( attachment );
    485 
    486                         this.unset( 'src' );
    487                         _.each( _.without( wp.media.view.settings.embedExts, this.extension ), function (ext) {
    488                                 self.unset( ext );
    489                         } );
    490                 }
    491         });
    492 
    493         /**
    494458         * wp.media.model.Attachments
    495459         *
    496460         * @constructor
  • src/wp-includes/js/media-views.js

     
    766766        });
    767767
    768768        /**
    769          * wp.media.controller.AudioDetails
    770          *
    771          * @constructor
    772          * @augments wp.media.controller.State
    773          * @augments Backbone.Model
    774          */
    775         media.controller.AudioDetails = media.controller.State.extend({
    776                 defaults: _.defaults({
    777                         id: 'audio-details',
    778                         toolbar: 'audio-details',
    779                         title: l10n.audioDetailsTitle,
    780                         content: 'audio-details',
    781                         menu: 'audio-details',
    782                         router: false,
    783                         attachment: false,
    784                         priority: 60,
    785                         editing: false
    786                 }, media.controller.Library.prototype.defaults ),
    787 
    788                 initialize: function( options ) {
    789                         this.media = options.media;
    790                         media.controller.State.prototype.initialize.apply( this, arguments );
    791                 }
    792         });
    793 
    794         /**
    795          * wp.media.controller.VideoDetails
    796          *
    797          * @constructor
    798          * @augments wp.media.controller.State
    799          * @augments Backbone.Model
    800          */
    801         media.controller.VideoDetails = media.controller.State.extend({
    802                 defaults: _.defaults({
    803                         id: 'video-details',
    804                         toolbar: 'video-details',
    805                         title: l10n.videoDetailsTitle,
    806                         content: 'video-details',
    807                         menu: 'video-details',
    808                         router: false,
    809                         attachment: false,
    810                         priority: 60,
    811                         editing: false
    812                 }, media.controller.Library.prototype.defaults ),
    813 
    814                 initialize: function( options ) {
    815                         this.media = options.media;
    816                         media.controller.State.prototype.initialize.apply( this, arguments );
    817                 }
    818         });
    819 
    820         /**
    821769         * wp.media.controller.CollectionEdit
    822770         *
    823771         * @constructor
     
    19301878                },
    19311879
    19321880                createStates: function() {
    1933                         var options = this.options;
     1881                        var options = this.options, counts;
    19341882
    19351883                        // Add the default states.
    19361884                        this.states.add([
     
    19901938                                        type:           'image',
    19911939                                        collectionType: 'gallery',
    19921940                                        title:          l10n.addToGalleryTitle
    1993                                 }),
     1941                                })
     1942                        ]);
    19941943
    1995                                 new media.controller.Library({
    1996                                         id:         'playlist',
    1997                                         title:      l10n.createPlaylistTitle,
    1998                                         priority:   60,
    1999                                         toolbar:    'main-playlist',
    2000                                         filterable: 'uploaded',
    2001                                         multiple:   'add',
    2002                                         editable:   false,
     1944                        counts = media.playlist.counts();
    20031945
    2004                                         library:  media.query( _.defaults({
    2005                                                 type: 'audio'
    2006                                         }, options.library ) )
    2007                                 }),
     1946                        if ( counts.audio ) {
     1947                                this.states.add( media.playlist.states(options) );
     1948                        }
    20081949
    2009                                 // Playlist states.
    2010                                 new media.controller.CollectionEdit({
    2011                                         type:           'audio',
    2012                                         collectionType: 'playlist',
    2013                                         title:          l10n.editPlaylistTitle,
    2014                                         SettingsView:   media.view.Settings.Playlist,
    2015                                         library:        options.selection,
    2016                                         editing:        options.editing,
    2017                                         menu:           'playlist',
    2018                                         dragInfoText:   l10n.playlistDragInfo,
    2019                                         dragInfo:       false
    2020                                 }),
     1950                        if ( counts.video ) {
     1951                                this.states.add( media.playlist.videoStates(options) );
     1952                        }
    20211953
    2022                                 new media.controller.CollectionAdd({
    2023                                         type: 'audio',
    2024                                         collectionType: 'playlist',
    2025                                         title: l10n.addToPlaylistTitle
    2026                                 }),
    2027 
    2028                                 new media.controller.Library({
    2029                                         id:         'video-playlist',
    2030                                         title:      l10n.createVideoPlaylistTitle,
    2031                                         priority:   60,
    2032                                         toolbar:    'main-video-playlist',
    2033                                         filterable: 'uploaded',
    2034                                         multiple:   'add',
    2035                                         editable:   false,
    2036 
    2037                                         library:  media.query( _.defaults({
    2038                                                 type: 'video'
    2039                                         }, options.library ) )
    2040                                 }),
    2041 
    2042                                 // Video Playlist states.
    2043                                 new media.controller.CollectionEdit({
    2044                                         type:           'video',
    2045                                         collectionType: 'video-playlist',
    2046                                         title:          l10n.editVideoPlaylistTitle,
    2047                                         SettingsView:   media.view.Settings.Playlist,
    2048                                         library:        options.selection,
    2049                                         editing:        options.editing,
    2050                                         menu:           'video-playlist',
    2051                                         dragInfoText:   l10n.videoPlaylistDragInfo,
    2052                                         dragInfo:       false
    2053                                 }),
    2054 
    2055                                 new media.controller.CollectionAdd({
    2056                                         type:           'video',
    2057                                         collectionType: 'video-playlist',
    2058                                         title:          l10n.addToVideoPlaylistTitle
    2059                                 })
    2060                         ]);
    2061 
    2062 
    20631954                        if ( media.view.settings.post.featuredImageId ) {
    20641955                                this.states.add( new media.controller.FeaturedImage() );
    20651956                        }
     
    27462637        });
    27472638
    27482639        /**
    2749          * wp.media.view.MediaFrame.MediaDetails
    2750          *
    2751          * @constructor
    2752          * @augments wp.media.view.MediaFrame.Select
    2753          * @augments wp.media.view.MediaFrame
    2754          * @augments wp.media.view.Frame
    2755          * @augments wp.media.View
    2756          * @augments wp.Backbone.View
    2757          * @augments Backbone.View
    2758          * @mixes wp.media.controller.StateMachine
    2759          */
    2760         media.view.MediaFrame.MediaDetails = media.view.MediaFrame.Select.extend({
    2761                 defaults: {
    2762                         id:      'media',
    2763                         url:     '',
    2764                         menu:    'media-details',
    2765                         content: 'media-details',
    2766                         toolbar: 'media-details',
    2767                         type:    'link',
    2768                         priority: 120
    2769                 },
    2770 
    2771                 initialize: function( options ) {
    2772                         this.DetailsView = options.DetailsView;
    2773                         this.cancelText = options.cancelText;
    2774                         this.addText = options.addText;
    2775 
    2776                         this.media = new media.model.PostMedia( options.metadata );
    2777                         this.options.selection = new media.model.Selection( this.media.attachment, { multiple: false } );
    2778                         media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
    2779                 },
    2780 
    2781                 bindHandlers: function() {
    2782                         var menu = this.defaults.menu;
    2783 
    2784                         media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
    2785 
    2786                         this.on( 'menu:create:' + menu, this.createMenu, this );
    2787                         this.on( 'content:render:' + menu, this.renderDetailsContent, this );
    2788                         this.on( 'menu:render:' + menu, this.renderMenu, this );
    2789                         this.on( 'toolbar:render:' + menu, this.renderDetailsToolbar, this );
    2790                 },
    2791 
    2792                 renderDetailsContent: function() {
    2793                         var view = new this.DetailsView({
    2794                                 controller: this,
    2795                                 model: this.state().media,
    2796                                 attachment: this.state().media.attachment
    2797                         }).render();
    2798 
    2799                         this.content.set( view );
    2800                 },
    2801 
    2802                 renderMenu: function( view ) {
    2803                         var lastState = this.lastState(),
    2804                                 previous = lastState && lastState.id,
    2805                                 frame = this;
    2806 
    2807                         view.set({
    2808                                 cancel: {
    2809                                         text:     this.cancelText,
    2810                                         priority: 20,
    2811                                         click:    function() {
    2812                                                 if ( previous ) {
    2813                                                         frame.setState( previous );
    2814                                                 } else {
    2815                                                         frame.close();
    2816                                                 }
    2817                                         }
    2818                                 },
    2819                                 separateCancel: new media.View({
    2820                                         className: 'separator',
    2821                                         priority: 40
    2822                                 })
    2823                         });
    2824 
    2825                 },
    2826 
    2827                 renderDetailsToolbar: function() {
    2828                         this.toolbar.set( new media.view.Toolbar({
    2829                                 controller: this,
    2830                                 items: {
    2831                                         select: {
    2832                                                 style:    'primary',
    2833                                                 text:     l10n.update,
    2834                                                 priority: 80,
    2835 
    2836                                                 click: function() {
    2837                                                         var controller = this.controller,
    2838                                                                 state = controller.state();
    2839 
    2840                                                         controller.close();
    2841 
    2842                                                         state.trigger( 'update', controller.media.toJSON() );
    2843 
    2844                                                         // Restore and reset the default state.
    2845                                                         controller.setState( controller.options.state );
    2846                                                         controller.reset();
    2847                                                 }
    2848                                         }
    2849                                 }
    2850                         }) );
    2851                 },
    2852 
    2853                 renderReplaceToolbar: function() {
    2854                         this.toolbar.set( new media.view.Toolbar({
    2855                                 controller: this,
    2856                                 items: {
    2857                                         replace: {
    2858                                                 style:    'primary',
    2859                                                 text:     l10n.replace,
    2860                                                 priority: 80,
    2861 
    2862                                                 click: function() {
    2863                                                         var controller = this.controller,
    2864                                                                 state = controller.state(),
    2865                                                                 selection = state.get( 'selection' ),
    2866                                                                 attachment = selection.single();
    2867 
    2868                                                         controller.media.changeAttachment( attachment );
    2869 
    2870                                                         state.trigger( 'replace', controller.media.toJSON() );
    2871 
    2872                                                         // Restore and reset the default state.
    2873                                                         controller.setState( controller.options.state );
    2874                                                         controller.reset();
    2875                                                 }
    2876                                         }
    2877                                 }
    2878                         }) );
    2879                 },
    2880 
    2881                 renderAddSourceToolbar: function() {
    2882                         this.toolbar.set( new media.view.Toolbar({
    2883                                 controller: this,
    2884                                 items: {
    2885                                         replace: {
    2886                                                 style:    'primary',
    2887                                                 text:     this.addText,
    2888                                                 priority: 80,
    2889 
    2890                                                 click: function() {
    2891                                                         var controller = this.controller,
    2892                                                                 state = controller.state(),
    2893                                                                 selection = state.get( 'selection' ),
    2894                                                                 attachment = selection.single();
    2895 
    2896                                                         controller.media.setSource( attachment );
    2897 
    2898                                                         state.trigger( 'add-source', controller.media.toJSON() );
    2899 
    2900                                                         // Restore and reset the default state.
    2901                                                         controller.setState( controller.options.state );
    2902                                                         controller.reset();
    2903                                                 }
    2904                                         }
    2905                                 }
    2906                         }) );
    2907                 }
    2908         });
    2909 
    2910         /**
    2911          * wp.media.view.MediaFrame.AudioDetails
    2912          *
    2913          * @constructor
    2914          * @augments wp.media.view.MediaFrame.MediaDetails
    2915          * @augments wp.media.view.MediaFrame.Select
    2916          * @augments wp.media.view.MediaFrame
    2917          * @augments wp.media.view.Frame
    2918          * @augments wp.media.View
    2919          * @augments wp.Backbone.View
    2920          * @augments Backbone.View
    2921          * @mixes wp.media.controller.StateMachine
    2922          */
    2923         media.view.MediaFrame.AudioDetails = media.view.MediaFrame.MediaDetails.extend({
    2924                 defaults: {
    2925                         id:      'audio',
    2926                         url:     '',
    2927                         menu:    'audio-details',
    2928                         content: 'audio-details',
    2929                         toolbar: 'audio-details',
    2930                         type:    'link',
    2931                         title:    l10n.audioDetailsTitle,
    2932                         priority: 120
    2933                 },
    2934 
    2935                 initialize: function( options ) {
    2936                         options.DetailsView = media.view.AudioDetails;
    2937                         options.cancelText = l10n.audioDetailsCancel;
    2938                         options.addText = l10n.audioAddSourceTitle;
    2939 
    2940                         media.view.MediaFrame.MediaDetails.prototype.initialize.call( this, options );
    2941                 },
    2942 
    2943                 bindHandlers: function() {
    2944                         media.view.MediaFrame.MediaDetails.prototype.bindHandlers.apply( this, arguments );
    2945 
    2946                         this.on( 'toolbar:render:replace-audio', this.renderReplaceToolbar, this );
    2947                         this.on( 'toolbar:render:add-audio-source', this.renderAddSourceToolbar, this );
    2948                 },
    2949 
    2950                 createStates: function() {
    2951                         this.states.add([
    2952                                 new media.controller.AudioDetails( {
    2953                                         media: this.media,
    2954                                         editable: false,
    2955                                         menu: 'audio-details'
    2956                                 } ),
    2957 
    2958                                 new media.controller.MediaLibrary( {
    2959                                         type: 'audio',
    2960                                         id: 'replace-audio',
    2961                                         title: l10n.audioReplaceTitle,
    2962                                         toolbar: 'replace-audio',
    2963                                         media: this.media,
    2964                                         menu: 'audio-details'
    2965                                 } ),
    2966 
    2967                                 new media.controller.MediaLibrary( {
    2968                                         type: 'audio',
    2969                                         id: 'add-audio-source',
    2970                                         title: l10n.audioAddSourceTitle,
    2971                                         toolbar: 'add-audio-source',
    2972                                         media: this.media,
    2973                                         menu: 'audio-details'
    2974                                 } )
    2975                         ]);
    2976                 }
    2977         });
    2978 
    2979         /**
    2980          * wp.media.view.MediaFrame.VideoDetails
    2981          *
    2982          * @constructor
    2983          * @augments wp.media.view.MediaFrame.MediaDetails
    2984          * @augments wp.media.view.MediaFrame.Select
    2985          * @augments wp.media.view.MediaFrame
    2986          * @augments wp.media.view.Frame
    2987          * @augments wp.media.View
    2988          * @augments wp.Backbone.View
    2989          * @augments Backbone.View
    2990          * @mixes wp.media.controller.StateMachine
    2991          */
    2992         media.view.MediaFrame.VideoDetails = media.view.MediaFrame.MediaDetails.extend({
    2993                 defaults: {
    2994                         id:      'video',
    2995                         url:     '',
    2996                         menu:    'video-details',
    2997                         content: 'video-details',
    2998                         toolbar: 'video-details',
    2999                         type:    'link',
    3000                         title:    l10n.videoDetailsTitle,
    3001                         priority: 120
    3002                 },
    3003 
    3004                 initialize: function( options ) {
    3005                         options.DetailsView = media.view.VideoDetails;
    3006                         options.cancelText = l10n.videoDetailsCancel;
    3007                         options.addText = l10n.videoAddSourceTitle;
    3008 
    3009                         media.view.MediaFrame.MediaDetails.prototype.initialize.call( this, options );
    3010                 },
    3011 
    3012                 bindHandlers: function() {
    3013                         media.view.MediaFrame.MediaDetails.prototype.bindHandlers.apply( this, arguments );
    3014 
    3015                         this.on( 'toolbar:render:replace-video', this.renderReplaceToolbar, this );
    3016                         this.on( 'toolbar:render:add-video-source', this.renderAddSourceToolbar, this );
    3017                         this.on( 'toolbar:render:select-poster-image', this.renderSelectPosterImageToolbar, this );
    3018                         this.on( 'toolbar:render:add-track', this.renderAddTrackToolbar, this );
    3019                 },
    3020 
    3021                 createStates: function() {
    3022                         this.states.add([
    3023                                 new media.controller.VideoDetails({
    3024                                         media: this.media,
    3025                                         editable: false,
    3026                                         menu: 'video-details'
    3027                                 }),
    3028 
    3029                                 new media.controller.MediaLibrary( {
    3030                                         type: 'video',
    3031                                         id: 'replace-video',
    3032                                         title: l10n.videoReplaceTitle,
    3033                                         toolbar: 'replace-video',
    3034                                         media: this.media,
    3035                                         menu: 'video-details'
    3036                                 } ),
    3037 
    3038                                 new media.controller.MediaLibrary( {
    3039                                         type: 'video',
    3040                                         id: 'add-video-source',
    3041                                         title: l10n.videoAddSourceTitle,
    3042                                         toolbar: 'add-video-source',
    3043                                         media: this.media,
    3044                                         menu: 'video-details'
    3045                                 } ),
    3046 
    3047                                 new media.controller.MediaLibrary( {
    3048                                         type: 'image',
    3049                                         id: 'select-poster-image',
    3050                                         title: l10n.videoSelectPosterImageTitle,
    3051                                         toolbar: 'select-poster-image',
    3052                                         media: this.media,
    3053                                         menu: 'video-details'
    3054                                 } ),
    3055 
    3056                                 new media.controller.MediaLibrary( {
    3057                                         type: 'text',
    3058                                         id: 'add-track',
    3059                                         title: l10n.videoAddTrackTitle,
    3060                                         toolbar: 'add-track',
    3061                                         media: this.media,
    3062                                         menu: 'video-details'
    3063                                 } )
    3064                         ]);
    3065                 },
    3066 
    3067                 renderSelectPosterImageToolbar: function() {
    3068                         this.toolbar.set( new media.view.Toolbar({
    3069                                 controller: this,
    3070                                 items: {
    3071                                         replace: {
    3072                                                 style:    'primary',
    3073                                                 text:     l10n.videoSelectPosterImageTitle,
    3074                                                 priority: 80,
    3075 
    3076                                                 click: function() {
    3077                                                         var controller = this.controller,
    3078                                                                 state = controller.state(),
    3079                                                                 selection = state.get( 'selection' ),
    3080                                                                 attachment = selection.single();
    3081 
    3082                                                         controller.media.set( 'poster', attachment.get( 'url' ) );
    3083 
    3084                                                         state.trigger( 'set-poster-image', controller.media.toJSON() );
    3085 
    3086                                                         // Restore and reset the default state.
    3087                                                         controller.setState( controller.options.state );
    3088                                                         controller.reset();
    3089                                                 }
    3090                                         }
    3091                                 }
    3092                         }) );
    3093                 },
    3094 
    3095                 renderAddTrackToolbar: function() {
    3096                         this.toolbar.set( new media.view.Toolbar({
    3097                                 controller: this,
    3098                                 items: {
    3099                                         replace: {
    3100                                                 style:    'primary',
    3101                                                 text:     l10n.videoAddTrackTitle,
    3102                                                 priority: 80,
    3103 
    3104                                                 click: function() {
    3105                                                         var controller = this.controller,
    3106                                                                 state = controller.state(),
    3107                                                                 selection = state.get( 'selection' ),
    3108                                                                 attachment = selection.single(),
    3109                                                                 content = controller.media.get( 'content' );
    3110 
    3111                                                         if ( -1 === content.indexOf( attachment.get( 'url' ) ) ) {
    3112                                                                 content += [
    3113                                                                         '<track srclang="en" label="English"kind="subtitles" src="',
    3114                                                                         attachment.get( 'url' ),
    3115                                                                         '" />'
    3116                                                                 ].join('');
    3117 
    3118                                                                 controller.media.set( 'content', content );
    3119                                                         }
    3120 
    3121                                                         state.trigger( 'add-track', controller.media.toJSON() );
    3122 
    3123                                                         // Restore and reset the default state.
    3124                                                         controller.setState( controller.options.state );
    3125                                                         controller.reset();
    3126                                                 }
    3127                                         }
    3128                                 }
    3129                         }) );
    3130                 }
    3131         });
    3132 
    3133         /**
    31342640         * wp.media.view.Modal
    31352641         *
    31362642         * @constructor
     
    66636169        });
    66646170
    66656171        /**
    6666          * wp.media.view.AudioDetails
    6667          *
    6668          * @contructor
    6669          * @augments wp.media.view.MediaDetails
    6670          * @augments wp.media.view.Settings.AttachmentDisplay
    6671          * @augments wp.media.view.Settings
    6672          * @augments wp.media.View
    6673          * @augments wp.Backbone.View
    6674          * @augments Backbone.View
    6675          */
    6676         media.view.AudioDetails = media.view.MediaDetails.extend({
    6677                 className: 'audio-details',
    6678                 template:  media.template('audio-details'),
    6679 
    6680                 setMedia: function() {
    6681                         var audio = this.$('.wp-audio-shortcode');
    6682 
    6683                         if ( audio.find( 'source' ).length ) {
    6684                                 if ( audio.is(':hidden') ) {
    6685                                         audio.show();
    6686                                 }
    6687                                 this.media = media.view.MediaDetails.prepareSrc( audio.get(0) );
    6688                         } else {
    6689                                 audio.hide();
    6690                                 this.media = false;
    6691                         }
    6692 
    6693                         return this;
    6694                 }
    6695         });
    6696 
    6697         /**
    6698          * wp.media.view.VideoDetails
    6699          *
    6700          * @contructor
    6701          * @augments wp.media.view.MediaDetails
    6702          * @augments wp.media.view.Settings.AttachmentDisplay
    6703          * @augments wp.media.view.Settings
    6704          * @augments wp.media.View
    6705          * @augments wp.Backbone.View
    6706          * @augments Backbone.View
    6707          */
    6708         media.view.VideoDetails = media.view.MediaDetails.extend({
    6709                 className: 'video-details',
    6710                 template:  media.template('video-details'),
    6711 
    6712                 setMedia: function() {
    6713                         var video = this.$('.wp-video-shortcode');
    6714 
    6715                         if ( video.find( 'source' ).length ) {
    6716                                 if ( video.is(':hidden') ) {
    6717                                         video.show();
    6718                                 }
    6719 
    6720                                 if ( ! video.hasClass('youtube-video') ) {
    6721                                         this.media = media.view.MediaDetails.prepareSrc( video.get(0) );
    6722                                 } else {
    6723                                         this.media = video.get(0);
    6724                                 }
    6725                         } else {
    6726                                 video.hide();
    6727                                 this.media = false;
    6728                         }
    6729 
    6730                         return this;
    6731                 }
    6732         });
    6733 
    6734         /**
    67356172         * wp.media.view.Spinner
    67366173         *
    67376174         * @constructor
  • src/wp-includes/js/mediaelement/wp-mediaelement.css

     
    2626
    2727.media-embed-details .embed-media-settings {
    2828        padding-top: 0;
     29        top: 28px;
    2930}
    3031
    3132.media-embed-details .instructions {
     
    4445        color: #f00;
    4546}
    4647
    47 .media-embed-details .embed-media-settings {
    48         top: 0;
    49 }
    50 
    5148.media-embed-details .embed-media-settings .checkbox-setting {
    5249        width: 100px;
    5350        clear: none;
  • src/wp-includes/media-template.php

     
    765765        </script>
    766766
    767767        <script type="text/html" id="tmpl-audio-details">
     768                <# var ext, html5types = { mp3: true, ogg: true }; #>
     769
    768770                <?php $audio_types = wp_get_audio_extensions(); ?>
    769771                <div class="media-embed media-embed-details">
    770772                        <div class="embed-media-settings embed-audio-settings">
    771                                 <div class="instructions media-instructions">{{{ wp.media.view.l10n.audioDetailsText }}}</div>
    772 
    773773                                <?php wp_underscore_audio_template() ?>
    774774
    775                                 <# if ( ! _.isEmpty( data.model.src ) ) { #>
     775                                <# if ( ! _.isEmpty( data.model.src ) ) {
     776                                        ext = data.model.src.split('.').pop();
     777                                        if ( html5types[ ext ] ) {
     778                                                delete html5types[ ext ];
     779                                        }
     780                                #>
    776781                                <label class="setting">
    777782                                        <span>SRC</span>
    778783                                        <input type="text" disabled="disabled" data-setting="src" value="{{ data.model.src }}" />
     
    782787                                <?php
    783788
    784789                                foreach ( $audio_types as $type ):
    785                                 ?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) { #>
     790                                ?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) {
     791                                        if ( ! _.isUndefined( html5types.<?php echo $type ?> ) ) {
     792                                                delete html5types.<?php echo $type ?>;
     793                                        }
     794                                #>
    786795                                <label class="setting">
    787796                                        <span><?php echo strtoupper( $type ) ?></span>
    788797                                        <input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{ data.model.<?php echo $type ?> }}" />
     
    791800                                <# } #>
    792801                                <?php endforeach ?>
    793802
     803                                <# if ( ! _.isEmpty( html5types ) ) { #>
     804                                <div class="setting">
     805                                        <span>{{{ wp.media.view.l10n.mediaHTML5Text }}}</span>
     806                                        <div class="button-large">
     807                                        <# _.each( html5types, function (value, type) { #>
     808                                        <button class="button add-media-source">{{ type }}</button>
     809                                        <# } ) #>
     810                                        </div>
     811                                </div>
     812                                <# } #>
     813
    794814                                <div class="setting preload">
    795815                                        <span><?php _e( 'Preload' ); ?></span>
    796816                                        <div class="button-group button-large" data-setting="preload">
     
    815835        </script>
    816836
    817837        <script type="text/html" id="tmpl-video-details">
     838                <# var ext, html5types = { mp4: true, ogv: true, webm: true }; #>
     839
    818840                <?php $video_types = wp_get_video_extensions(); ?>
    819841                <div class="media-embed media-embed-details">
    820842                        <div class="embed-media-settings embed-video-settings">
    821                                 <div class="instructions media-instructions">{{{ wp.media.view.l10n.videoDetailsText }}}</div>
    822843                                <div class="wp-video-holder">
    823844                                <#
    824845                                var isYouTube = ! _.isEmpty( data.model.src ) && data.model.src.match(/youtube|youtu\.be/);
     
    832853
    833854                                <?php wp_underscore_video_template() ?>
    834855
    835                                 <# if ( ! _.isEmpty( data.model.src ) ) { #>
     856                                <# if ( ! _.isEmpty( data.model.src ) ) {
     857                                        ext = data.model.src.split('.').pop();
     858                                        if ( html5types[ ext ] ) {
     859                                                delete html5types[ ext ];
     860                                        }
     861                                #>
    836862                                <label class="setting">
    837863                                        <span>SRC</span>
    838864                                        <input type="text" disabled="disabled" data-setting="src" value="{{ data.model.src }}" />
     
    840866                                </label>
    841867                                <# } #>
    842868                                <?php foreach ( $video_types as $type ):
    843                                 ?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) { #>
     869                                ?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) {
     870                                        if ( ! _.isUndefined( html5types.<?php echo $type ?> ) ) {
     871                                                delete html5types.<?php echo $type ?>;
     872                                        }
     873                                #>
    844874                                <label class="setting">
    845875                                        <span><?php echo strtoupper( $type ) ?></span>
    846876                                        <input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{ data.model.<?php echo $type ?> }}" />
     
    849879                                <# } #>
    850880                                <?php endforeach ?>
    851881                                </div>
     882
     883                                <# if ( ! _.isEmpty( html5types ) ) { #>
     884                                <div class="setting">
     885                                        <span>{{{ wp.media.view.l10n.mediaHTML5Text }}}</span>
     886                                        <div class="button-large">
     887                                        <# _.each( html5types, function (value, type) { #>
     888                                        <button class="button add-media-source">{{ type }}</button>
     889                                        <# } ) #>
     890                                        </div>
     891                                </div>
     892                                <# } #>
     893
    852894                                <# if ( ! _.isEmpty( data.model.poster ) ) { #>
    853895                                <label class="setting">
    854896                                        <span><?php _e( 'Poster Image' ); ?></span>
  • src/wp-includes/media.php

     
    24002400                        'id' => 0,
    24012401                ),
    24022402                'defaultProps' => $props,
     2403                'attachmentCounts' => wp_count_attachments(),
    24032404                'embedExts'    => $exts,
    24042405                'embedMimes'   => $ext_mimes
    24052406        );
     
    24952496                /* translators: suggested height of header image in pixels */
    24962497                'suggestedHeight' => __( 'Suggested height is %d pixels.' ),
    24972498
     2499                'mediaHTML5Text'        => __( 'Add alternate sources for maximum HTML5 playback:' ),
     2500
    24982501                // Edit Audio
    24992502                'audioDetailsTitle'     => __( 'Audio Details' ),
    25002503                'audioReplaceTitle'     => __( 'Replace Audio' ),
    25012504                'audioAddSourceTitle'   => __( 'Add Audio Source' ),
    25022505                'audioDetailsCancel'    => __( 'Cancel Edit' ),
    2503                 'audioDetailsText'      => __( '"Replace Audio" will remove all associated source files when you update. ' .
    2504                         '"Add Audio Source" allows you to specify alternate sources for maximum native HTML5 audio playback.' ),
    25052506
    25062507                // Edit Video
    25072508                'videoDetailsTitle'     => __( 'Video Details' ),
     
    25082509                'videoReplaceTitle'     => __( 'Replace Video' ),
    25092510                'videoAddSourceTitle'   => __( 'Add Video Source' ),
    25102511                'videoDetailsCancel'    => __( 'Cancel Edit' ),
    2511                 'videoDetailsText'      => __( '"Replace Video" will remove all associated source files when you update. ' .
    2512                         '"Add Video Source" allows you to specify alternate sources for maximum native HTML5 video playback.' ),
    25132512                'videoSelectPosterImageTitle' => _( 'Select Poster Image' ),
    25142513                'videoAddTrackTitle'    => __( 'Add Subtitles' ),
    25152514
     
    25422541        wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings );
    25432542
    25442543        wp_enqueue_script( 'media-editor' );
     2544        wp_enqueue_script( 'media-audiovideo' );
    25452545        wp_enqueue_style( 'media-views' );
    25462546        wp_enqueue_style( 'imgareaselect' );
    25472547        wp_plupload_default_settings();
  • src/wp-includes/script-loader.php

     
    395395        // Both rely on numerous settings, styles, and templates to operate correctly.
    396396        $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement', 'image-edit' ), false, 1 );
    397397        $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
     398        $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor' ), false, 1 );
    398399        $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 );
    399400
    400401        if ( is_admin() ) {