<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[27608] trunk/src/wp-includes: Create a new file, `media-audiovideo.js`, to house all of the audio and video JS code in core.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://core.trac.wordpress.org/changeset/27608">27608</a></dd>
<dt>Author</dt> <dd>wonderboymusic</dd>
<dt>Date</dt> <dd>2014-03-19 05:30:27 +0000 (Wed, 19 Mar 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Create a new file, `media-audiovideo.js`, to house all of the audio and video JS code in core.

UX Changes:
* Don't add a menu item for "Add Audio|Video Source"
* In the Audio|Video Details modal, add buttons and some suggestive text for adding alternate playback sources
* Don't show "Create Audio|Video Playlist" menu items until the user has uploaded audio or video files

See <a href="http://core.trac.wordpress.org/ticket/27437">#27437</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesjsmediaeditorjs">trunk/src/wp-includes/js/media-editor.js</a></li>
<li><a href="#trunksrcwpincludesjsmediamodelsjs">trunk/src/wp-includes/js/media-models.js</a></li>
<li><a href="#trunksrcwpincludesjsmediaviewsjs">trunk/src/wp-includes/js/media-views.js</a></li>
<li><a href="#trunksrcwpincludesjsmediaelementwpmediaelementcss">trunk/src/wp-includes/js/mediaelement/wp-mediaelement.css</a></li>
<li><a href="#trunksrcwpincludesmediatemplatephp">trunk/src/wp-includes/media-template.php</a></li>
<li><a href="#trunksrcwpincludesmediaphp">trunk/src/wp-includes/media.php</a></li>
<li><a href="#trunksrcwpincludesscriptloaderphp">trunk/src/wp-includes/script-loader.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesjsmediaaudiovideojs">trunk/src/wp-includes/js/media-audiovideo.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesjsmediaaudiovideojs"></a>
<div class="addfile"><h4>Added: trunk/src/wp-includes/js/media-audiovideo.js (0 => 27608)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/media-audiovideo.js                             (rev 0)
+++ trunk/src/wp-includes/js/media-audiovideo.js        2014-03-19 05:30:27 UTC (rev 27608)
</span><span class="lines">@@ -0,0 +1,985 @@
</span><ins>+/* global _wpMediaViewsL10n */
+
+(function ($, _, Backbone) {
+       var media = wp.media, l10n = typeof _wpMediaViewsL10n === 'undefined' ? {} : _wpMediaViewsL10n;
+
+       /**
+        * @mixin
+        */
+       wp.media.mixin = {
+
+               /**
+                * Pauses every instance of MediaElementPlayer
+                */
+               pauseAllPlayers: function () {
+                       var p;
+                       if ( window.mejs && window.mejs.players ) {
+                               for ( p in window.mejs.players ) {
+                                       window.mejs.players[p].pause();
+                               }
+                       }
+               },
+
+               /**
+                * Utility to identify the user's browser
+                */
+               ua: {
+                       is : function (browser) {
+                               var passes = false, ua = window.navigator.userAgent;
+
+                               switch ( browser ) {
+                                       case 'oldie':
+                                               passes = ua.match(/MSIE [6-8]/gi) !== null;
+                                       break;
+                                       case 'ie':
+                                               passes = ua.match(/MSIE/gi) !== null;
+                                       break;
+                                       case 'ff':
+                                               passes = ua.match(/firefox/gi) !== null;
+                                       break;
+                                       case 'opera':
+                                               passes = ua.match(/OPR/) !== null;
+                                       break;
+                                       case 'safari':
+                                               passes = ua.match(/safari/gi) !== null && ua.match(/chrome/gi) === null;
+                                       break;
+                                       case 'chrome':
+                                               passes = ua.match(/safari/gi) && ua.match(/chrome/gi) !== null;
+                                       break;
+                               }
+
+                               return passes;
+                       }
+               },
+
+               /**
+                * Specify compatibility for native playback by browser
+                */
+               compat :{
+                       'opera' : {
+                               audio: ['ogg', 'wav'],
+                               video: ['ogg', 'webm']
+                       },
+                       'chrome' : {
+                               audio: ['ogg', 'mpeg', 'x-ms-wma'],
+                               video: ['ogg', 'webm', 'mp4', 'm4v', 'mpeg']
+                       },
+                       'ff' : {
+                               audio: ['ogg', 'mpeg'],
+                               video: ['ogg', 'webm']
+                       },
+                       'safari' : {
+                               audio: ['mpeg', 'wav'],
+                               video: ['mp4', 'm4v', 'mpeg', 'x-ms-wmv', 'quicktime']
+                       },
+                       'ie' : {
+                               audio: ['mpeg'],
+                               video: ['mp4', 'm4v', 'mpeg']
+                       }
+               },
+
+               /**
+                * Determine if the passed media contains a <source> that provides
+                *  native playback in the user's browser
+                *
+                * @param {jQuery} media
+                * @returns {Boolean}
+                */
+               isCompatible: function ( media ) {
+                       if ( ! media.find( 'source' ).length ) {
+                               return false;
+                       }
+
+                       var ua = this.ua, test = false, found = false, sources;
+
+                       if ( ua.is( 'oldIE' ) ) {
+                               return false;
+                       }
+
+                       sources = media.find( 'source' );
+
+                       _.find( this.compat, function (supports, browser) {
+                               if ( ua.is( browser ) ) {
+                                       found = true;
+                                       _.each( sources, function (elem) {
+                                               var audio = new RegExp( 'audio\/(' + supports.audio.join('|') + ')', 'gi' ),
+                                                       video = new RegExp( 'video\/(' + supports.video.join('|') + ')', 'gi' );
+
+                                               if ( elem.type.match( video ) !== null || elem.type.match( audio ) !== null ) {
+                                                       test = true;
+                                               }
+                                       } );
+                               }
+
+                               return test || found;
+                       } );
+
+                       return test;
+               },
+
+               /**
+                * Override the MediaElement method for removing a player.
+                *      MediaElement tries to pull the audio/video tag out of
+                *      its container and re-add it to the DOM.
+                */
+               removePlayer: function() {
+                       var t = this.player, featureIndex, feature;
+
+                       // invoke features cleanup
+                       for ( featureIndex in t.options.features ) {
+                               feature = t.options.features[featureIndex];
+                               if ( t['clean' + feature] ) {
+                                       try {
+                                               t['clean' + feature](t);
+                                       } catch (e) {}
+                               }
+                       }
+
+                       if ( ! t.isDynamic ) {
+                               t.$node.remove();
+                       }
+
+                       if ( 'native' !== t.media.pluginType ) {
+                               t.media.remove();
+                       }
+
+                       delete window.mejs.players[t.id];
+
+                       t.container.remove();
+                       t.globalUnbind();
+                       delete t.node.player;
+               },
+
+               /**
+                * Allows any class that has set 'player' to a MediaElementPlayer
+                *  instance to remove the player when listening to events.
+                *
+                *  Examples: modal closes, shortcode properties are removed, etc.
+                */
+               unsetPlayer : function() {
+                       if ( this.player ) {
+                               wp.media.mixin.pauseAllPlayers();
+                               wp.media.mixin.removePlayer.apply( this );
+                               this.player = false;
+                       }
+               }
+       };
+
+       /**
+        * Autowire "collection"-type shortcodes
+        */
+       wp.media.playlist = new wp.media.collection({
+               tag: 'playlist',
+               type : 'audio',
+               editTitle : l10n.editPlaylistTitle,
+               defaults : {
+                       id: wp.media.view.settings.post.id,
+                       style: 'light',
+                       tracklist: true,
+                       tracknumbers: true,
+                       images: true,
+                       artists: true
+               }
+       });
+
+       wp.media['video-playlist'] = new wp.media.collection({
+               tag: 'video-playlist',
+               type : 'video',
+               editTitle : l10n.editVideoPlaylistTitle,
+               defaults : {
+                       id: wp.media.view.settings.post.id,
+                       style: 'light',
+                       tracklist: false,
+                       tracknumbers: false,
+                       images: true
+               }
+       });
+
+       /**
+        * Shortcode modeling for audio
+        *  `edit()` prepares the shortcode for the media modal
+        *  `shortcode()` builds the new shortcode after update
+        *
+        * @namespace
+        */
+       wp.media.audio = {
+               coerce : wp.media.coerce,
+
+               defaults : {
+                       id : wp.media.view.settings.post.id,
+                       src      : '',
+                       loop     : false,
+                       autoplay : false,
+                       preload  : 'none'
+               },
+
+               edit : function (data) {
+                       var frame, shortcode = wp.shortcode.next( 'audio', data ).shortcode;
+                       frame = wp.media({
+                               frame: 'audio',
+                               state: 'audio-details',
+                               metadata: _.defaults(
+                                       shortcode.attrs.named,
+                                       wp.media.audio.defaults
+                               )
+                       });
+
+                       return frame;
+               },
+
+               shortcode : function (shortcode) {
+                       var self = this;
+
+                       _.each( wp.media.audio.defaults, function( value, key ) {
+                               shortcode[ key ] = self.coerce( shortcode, key );
+
+                               if ( value === shortcode[ key ] ) {
+                                       delete shortcode[ key ];
+                               }
+                       });
+
+                       return wp.shortcode.string({
+                               tag:     'audio',
+                               attrs:   shortcode
+                       });
+               }
+       };
+
+       /**
+        * Shortcode modeling for video
+        *  `edit()` prepares the shortcode for the media modal
+        *  `shortcode()` builds the new shortcode after update
+        *
+        * @namespace
+        */
+       wp.media.video = {
+               coerce : wp.media.coerce,
+
+               defaults : {
+                       id : wp.media.view.settings.post.id,
+                       src : '',
+                       poster : '',
+                       loop : false,
+                       autoplay : false,
+                       preload : 'metadata',
+                       content : ''
+               },
+
+               edit : function (data) {
+                       var frame,
+                               defaults = this.defaults,
+                               shortcode = wp.shortcode.next( 'video', data ).shortcode,
+                               attrs;
+
+                       attrs = shortcode.attrs.named;
+                       attrs.content = shortcode.content;
+
+                       frame = wp.media({
+                               frame: 'video',
+                               state: 'video-details',
+                               metadata: _.defaults( attrs, defaults )
+                       });
+
+                       return frame;
+               },
+
+               shortcode : function (shortcode) {
+                       var self = this, content = shortcode.content;
+                       delete shortcode.content;
+
+                       _.each( this.defaults, function( value, key ) {
+                               shortcode[ key ] = self.coerce( shortcode, key );
+
+                               if ( value === shortcode[ key ] ) {
+                                       delete shortcode[ key ];
+                               }
+                       });
+
+                       return wp.shortcode.string({
+                               tag:     'video',
+                               attrs:   shortcode,
+                               content: content
+                       });
+               }
+       };
+
+       /**
+        * wp.media.model.PostMedia
+        *
+        * @constructor
+        * @augments Backbone.Model
+        **/
+       media.model.PostMedia = Backbone.Model.extend({
+               initialize: function() {
+                       this.attachment = false;
+               },
+
+               setSource: function ( attachment ) {
+                       this.attachment = attachment;
+                       this.extension = attachment.get('filename' ).split('.').pop();
+
+                       if ( this.get( 'src' ) && this.extension === this.get( 'src' ).split('.').pop() ) {
+                               this.unset( 'src' );
+                       }
+
+                       if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
+                               this.set( this.extension, this.attachment.get( 'url' ) );
+                       } else {
+                               this.unset( this.extension );
+                       }
+               },
+
+               changeAttachment: function( attachment ) {
+                       var self = this;
+
+                       this.setSource( attachment );
+
+                       this.unset( 'src' );
+                       _.each( _.without( wp.media.view.settings.embedExts, this.extension ), function (ext) {
+                               self.unset( ext );
+                       } );
+               }
+       });
+
+       /**
+        * wp.media.controller.AudioDetails
+        *
+        * @constructor
+        * @augments wp.media.controller.State
+        * @augments Backbone.Model
+        */
+       media.controller.AudioDetails = media.controller.State.extend({
+               defaults: _.defaults({
+                       id: 'audio-details',
+                       toolbar: 'audio-details',
+                       title: l10n.audioDetailsTitle,
+                       content: 'audio-details',
+                       menu: 'audio-details',
+                       router: false,
+                       attachment: false,
+                       priority: 60,
+                       editing: false
+               }, media.controller.Library.prototype.defaults ),
+
+               initialize: function( options ) {
+                       this.media = options.media;
+                       media.controller.State.prototype.initialize.apply( this, arguments );
+               }
+       });
+
+       /**
+        * wp.media.controller.VideoDetails
+        *
+        * @constructor
+        * @augments wp.media.controller.State
+        * @augments Backbone.Model
+        */
+       media.controller.VideoDetails = media.controller.State.extend({
+               defaults: _.defaults({
+                       id: 'video-details',
+                       toolbar: 'video-details',
+                       title: l10n.videoDetailsTitle,
+                       content: 'video-details',
+                       menu: 'video-details',
+                       router: false,
+                       attachment: false,
+                       priority: 60,
+                       editing: false
+               }, media.controller.Library.prototype.defaults ),
+
+               initialize: function( options ) {
+                       this.media = options.media;
+                       media.controller.State.prototype.initialize.apply( this, arguments );
+               }
+       });
+
+       /**
+        * wp.media.view.MediaFrame.MediaDetails
+        *
+        * @constructor
+        * @augments wp.media.view.MediaFrame.Select
+        * @augments wp.media.view.MediaFrame
+        * @augments wp.media.view.Frame
+        * @augments wp.media.View
+        * @augments wp.Backbone.View
+        * @augments Backbone.View
+        * @mixes wp.media.controller.StateMachine
+        */
+       media.view.MediaFrame.MediaDetails = media.view.MediaFrame.Select.extend({
+               defaults: {
+                       id:      'media',
+                       url:     '',
+                       menu:    'media-details',
+                       content: 'media-details',
+                       toolbar: 'media-details',
+                       type:    'link',
+                       priority: 120
+               },
+
+               initialize: function( options ) {
+                       this.DetailsView = options.DetailsView;
+                       this.cancelText = options.cancelText;
+                       this.addText = options.addText;
+
+                       this.media = new media.model.PostMedia( options.metadata );
+                       this.options.selection = new media.model.Selection( this.media.attachment, { multiple: false } );
+                       media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
+               },
+
+               bindHandlers: function() {
+                       var menu = this.defaults.menu;
+
+                       media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
+
+                       this.on( 'menu:create:' + menu, this.createMenu, this );
+                       this.on( 'content:render:' + menu, this.renderDetailsContent, this );
+                       this.on( 'menu:render:' + menu, this.renderMenu, this );
+                       this.on( 'toolbar:render:' + menu, this.renderDetailsToolbar, this );
+               },
+
+               renderDetailsContent: function() {
+                       var view = new this.DetailsView({
+                               controller: this,
+                               model: this.state().media,
+                               attachment: this.state().media.attachment
+                       }).render();
+
+                       this.content.set( view );
+               },
+
+               renderMenu: function( view ) {
+                       var lastState = this.lastState(),
+                               previous = lastState && lastState.id,
+                               frame = this;
+
+                       view.set({
+                               cancel: {
+                                       text:     this.cancelText,
+                                       priority: 20,
+                                       click:    function() {
+                                               if ( previous ) {
+                                                       frame.setState( previous );
+                                               } else {
+                                                       frame.close();
+                                               }
+                                       }
+                               },
+                               separateCancel: new media.View({
+                                       className: 'separator',
+                                       priority: 40
+                               })
+                       });
+
+               },
+
+               renderDetailsToolbar: function() {
+                       this.toolbar.set( new media.view.Toolbar({
+                               controller: this,
+                               items: {
+                                       select: {
+                                               style:    'primary',
+                                               text:     l10n.update,
+                                               priority: 80,
+
+                                               click: function() {
+                                                       var controller = this.controller,
+                                                               state = controller.state();
+
+                                                       controller.close();
+
+                                                       state.trigger( 'update', controller.media.toJSON() );
+
+                                                       // Restore and reset the default state.
+                                                       controller.setState( controller.options.state );
+                                                       controller.reset();
+                                               }
+                                       }
+                               }
+                       }) );
+               },
+
+               renderReplaceToolbar: function() {
+                       this.toolbar.set( new media.view.Toolbar({
+                               controller: this,
+                               items: {
+                                       replace: {
+                                               style:    'primary',
+                                               text:     l10n.replace,
+                                               priority: 80,
+
+                                               click: function() {
+                                                       var controller = this.controller,
+                                                               state = controller.state(),
+                                                               selection = state.get( 'selection' ),
+                                                               attachment = selection.single();
+
+                                                       controller.media.changeAttachment( attachment );
+
+                                                       state.trigger( 'replace', controller.media.toJSON() );
+
+                                                       // Restore and reset the default state.
+                                                       controller.setState( controller.options.state );
+                                                       controller.reset();
+                                               }
+                                       }
+                               }
+                       }) );
+               },
+
+               renderAddSourceToolbar: function() {
+                       this.toolbar.set( new media.view.Toolbar({
+                               controller: this,
+                               items: {
+                                       replace: {
+                                               style:    'primary',
+                                               text:     this.addText,
+                                               priority: 80,
+
+                                               click: function() {
+                                                       var controller = this.controller,
+                                                               state = controller.state(),
+                                                               selection = state.get( 'selection' ),
+                                                               attachment = selection.single();
+
+                                                       controller.media.setSource( attachment );
+
+                                                       state.trigger( 'add-source', controller.media.toJSON() );
+
+                                                       // Restore and reset the default state.
+                                                       controller.setState( controller.options.state );
+                                                       controller.reset();
+                                               }
+                                       }
+                               }
+                       }) );
+               }
+       });
+
+       /**
+        * wp.media.view.MediaFrame.AudioDetails
+        *
+        * @constructor
+        * @augments wp.media.view.MediaFrame.MediaDetails
+        * @augments wp.media.view.MediaFrame.Select
+        * @augments wp.media.view.MediaFrame
+        * @augments wp.media.view.Frame
+        * @augments wp.media.View
+        * @augments wp.Backbone.View
+        * @augments Backbone.View
+        * @mixes wp.media.controller.StateMachine
+        */
+       media.view.MediaFrame.AudioDetails = media.view.MediaFrame.MediaDetails.extend({
+               defaults: {
+                       id:      'audio',
+                       url:     '',
+                       menu:    'audio-details',
+                       content: 'audio-details',
+                       toolbar: 'audio-details',
+                       type:    'link',
+                       title:    l10n.audioDetailsTitle,
+                       priority: 120
+               },
+
+               initialize: function( options ) {
+                       options.DetailsView = media.view.AudioDetails;
+                       options.cancelText = l10n.audioDetailsCancel;
+                       options.addText = l10n.audioAddSourceTitle;
+
+                       media.view.MediaFrame.MediaDetails.prototype.initialize.call( this, options );
+               },
+
+               bindHandlers: function() {
+                       media.view.MediaFrame.MediaDetails.prototype.bindHandlers.apply( this, arguments );
+
+                       this.on( 'toolbar:render:replace-audio', this.renderReplaceToolbar, this );
+                       this.on( 'toolbar:render:add-audio-source', this.renderAddSourceToolbar, this );
+               },
+
+               createStates: function() {
+                       this.states.add([
+                               new media.controller.AudioDetails( {
+                                       media: this.media,
+                                       editable: false,
+                                       menu: 'audio-details'
+                               } ),
+
+                               new media.controller.MediaLibrary( {
+                                       type: 'audio',
+                                       id: 'replace-audio',
+                                       title: l10n.audioReplaceTitle,
+                                       toolbar: 'replace-audio',
+                                       media: this.media,
+                                       menu: 'audio-details'
+                               } ),
+
+                               new media.controller.MediaLibrary( {
+                                       type: 'audio',
+                                       id: 'add-audio-source',
+                                       title: l10n.audioAddSourceTitle,
+                                       toolbar: 'add-audio-source',
+                                       media: this.media,
+                                       menu: false
+                               } )
+                       ]);
+               }
+       });
+
+       /**
+        * wp.media.view.MediaFrame.VideoDetails
+        *
+        * @constructor
+        * @augments wp.media.view.MediaFrame.MediaDetails
+        * @augments wp.media.view.MediaFrame.Select
+        * @augments wp.media.view.MediaFrame
+        * @augments wp.media.view.Frame
+        * @augments wp.media.View
+        * @augments wp.Backbone.View
+        * @augments Backbone.View
+        * @mixes wp.media.controller.StateMachine
+        */
+       media.view.MediaFrame.VideoDetails = media.view.MediaFrame.MediaDetails.extend({
+               defaults: {
+                       id:      'video',
+                       url:     '',
+                       menu:    'video-details',
+                       content: 'video-details',
+                       toolbar: 'video-details',
+                       type:    'link',
+                       title:    l10n.videoDetailsTitle,
+                       priority: 120
+               },
+
+               initialize: function( options ) {
+                       options.DetailsView = media.view.VideoDetails;
+                       options.cancelText = l10n.videoDetailsCancel;
+                       options.addText = l10n.videoAddSourceTitle;
+
+                       media.view.MediaFrame.MediaDetails.prototype.initialize.call( this, options );
+               },
+
+               bindHandlers: function() {
+                       media.view.MediaFrame.MediaDetails.prototype.bindHandlers.apply( this, arguments );
+
+                       this.on( 'toolbar:render:replace-video', this.renderReplaceToolbar, this );
+                       this.on( 'toolbar:render:add-video-source', this.renderAddSourceToolbar, this );
+                       this.on( 'toolbar:render:select-poster-image', this.renderSelectPosterImageToolbar, this );
+                       this.on( 'toolbar:render:add-track', this.renderAddTrackToolbar, this );
+               },
+
+               createStates: function() {
+                       this.states.add([
+                               new media.controller.VideoDetails({
+                                       media: this.media,
+                                       editable: false,
+                                       menu: 'video-details'
+                               }),
+
+                               new media.controller.MediaLibrary( {
+                                       type: 'video',
+                                       id: 'replace-video',
+                                       title: l10n.videoReplaceTitle,
+                                       toolbar: 'replace-video',
+                                       media: this.media,
+                                       menu: 'video-details'
+                               } ),
+
+                               new media.controller.MediaLibrary( {
+                                       type: 'video',
+                                       id: 'add-video-source',
+                                       title: l10n.videoAddSourceTitle,
+                                       toolbar: 'add-video-source',
+                                       media: this.media,
+                                       menu: false
+                               } ),
+
+                               new media.controller.MediaLibrary( {
+                                       type: 'image',
+                                       id: 'select-poster-image',
+                                       title: l10n.videoSelectPosterImageTitle,
+                                       toolbar: 'select-poster-image',
+                                       media: this.media,
+                                       menu: 'video-details'
+                               } ),
+
+                               new media.controller.MediaLibrary( {
+                                       type: 'text',
+                                       id: 'add-track',
+                                       title: l10n.videoAddTrackTitle,
+                                       toolbar: 'add-track',
+                                       media: this.media,
+                                       menu: 'video-details'
+                               } )
+                       ]);
+               },
+
+               renderSelectPosterImageToolbar: function() {
+                       this.toolbar.set( new media.view.Toolbar({
+                               controller: this,
+                               items: {
+                                       replace: {
+                                               style:    'primary',
+                                               text:     l10n.videoSelectPosterImageTitle,
+                                               priority: 80,
+
+                                               click: function() {
+                                                       var controller = this.controller,
+                                                               state = controller.state(),
+                                                               selection = state.get( 'selection' ),
+                                                               attachment = selection.single();
+
+                                                       controller.media.set( 'poster', attachment.get( 'url' ) );
+
+                                                       state.trigger( 'set-poster-image', controller.media.toJSON() );
+
+                                                       // Restore and reset the default state.
+                                                       controller.setState( controller.options.state );
+                                                       controller.reset();
+                                               }
+                                       }
+                               }
+                       }) );
+               },
+
+               renderAddTrackToolbar: function() {
+                       this.toolbar.set( new media.view.Toolbar({
+                               controller: this,
+                               items: {
+                                       replace: {
+                                               style:    'primary',
+                                               text:     l10n.videoAddTrackTitle,
+                                               priority: 80,
+
+                                               click: function() {
+                                                       var controller = this.controller,
+                                                               state = controller.state(),
+                                                               selection = state.get( 'selection' ),
+                                                               attachment = selection.single(),
+                                                               content = controller.media.get( 'content' );
+
+                                                       if ( -1 === content.indexOf( attachment.get( 'url' ) ) ) {
+                                                               content += [
+                                                                       '<track srclang="en" label="English"kind="subtitles" src="',
+                                                                       attachment.get( 'url' ),
+                                                                       '" />'
+                                                               ].join('');
+
+                                                               controller.media.set( 'content', content );
+                                                       }
+
+                                                       state.trigger( 'add-track', controller.media.toJSON() );
+
+                                                       // Restore and reset the default state.
+                                                       controller.setState( controller.options.state );
+                                                       controller.reset();
+                                               }
+                                       }
+                               }
+                       }) );
+               }
+       });
+
+       /**
+        * wp.media.view.AudioDetails
+        *
+        * @contructor
+        * @augments wp.media.view.MediaDetails
+        * @augments wp.media.view.Settings.AttachmentDisplay
+        * @augments wp.media.view.Settings
+        * @augments wp.media.View
+        * @augments wp.Backbone.View
+        * @augments Backbone.View
+        */
+       media.view.AudioDetails = media.view.MediaDetails.extend({
+               className: 'audio-details',
+               template:  media.template('audio-details'),
+
+               setMedia: function() {
+                       var audio = this.$('.wp-audio-shortcode');
+
+                       if ( audio.find( 'source' ).length ) {
+                               if ( audio.is(':hidden') ) {
+                                       audio.show();
+                               }
+                               this.media = media.view.MediaDetails.prepareSrc( audio.get(0) );
+                       } else {
+                               audio.hide();
+                               this.media = false;
+                       }
+
+                       return this;
+               }
+       });
+
+       /**
+        * wp.media.view.VideoDetails
+        *
+        * @contructor
+        * @augments wp.media.view.MediaDetails
+        * @augments wp.media.view.Settings.AttachmentDisplay
+        * @augments wp.media.view.Settings
+        * @augments wp.media.View
+        * @augments wp.Backbone.View
+        * @augments Backbone.View
+        */
+       media.view.VideoDetails = media.view.MediaDetails.extend({
+               className: 'video-details',
+               template:  media.template('video-details'),
+
+               setMedia: function() {
+                       var video = this.$('.wp-video-shortcode');
+
+                       if ( video.find( 'source' ).length ) {
+                               if ( video.is(':hidden') ) {
+                                       video.show();
+                               }
+
+                               if ( ! video.hasClass('youtube-video') ) {
+                                       this.media = media.view.MediaDetails.prepareSrc( video.get(0) );
+                               } else {
+                                       this.media = video.get(0);
+                               }
+                       } else {
+                               video.hide();
+                               this.media = false;
+                       }
+
+                       return this;
+               }
+       });
+
+       _.extend( wp.media.playlist, {
+               /**
+                * Determine how many audio and video files the user has uploaded
+                */
+               counts : (function (settings) {
+                       var counts = {};
+
+                       return  function () {
+                               if ( ! _.isEmpty( counts ) ) {
+                                       return counts;
+                               }
+
+                               var a = 0, v = 0;
+                               _.each( settings.attachmentCounts, function (total, mime) {
+                                       var type;
+                                       if ( -1 < mime.indexOf('/') ) {
+                                               type = mime.split('/')[0];
+
+                                               total = parseInt(total, 10);
+
+                                               switch ( type ) {
+                                                       case 'audio':
+                                                               a += total;
+                                                       break;
+                                                       case 'video':
+                                                               v += total;
+                                                       break;
+                                               }
+                                       }
+                               } );
+
+                               counts.audio = a;
+                               counts.video = v;
+
+                               return counts;
+                       };
+               }(media.view.settings)),
+
+               /**
+                * Return the playlist states for MediaFrame.Post
+                *
+                * @param {Object} options
+                * @returns {Array}
+                */
+               states : function (options) {
+                       return [
+                               new media.controller.Library({
+                                       id:         'playlist',
+                                       title:      l10n.createPlaylistTitle,
+                                       priority:   60,
+                                       toolbar:    'main-playlist',
+                                       filterable: 'uploaded',
+                                       multiple:   'add',
+                                       editable:   false,
+
+                                       library:  media.query( _.defaults({
+                                               type: 'audio'
+                                       }, options.library ) )
+                               }),
+
+                               // Playlist states.
+                               new media.controller.CollectionEdit({
+                                       type:           'audio',
+                                       collectionType: 'playlist',
+                                       title:          l10n.editPlaylistTitle,
+                                       SettingsView:   media.view.Settings.Playlist,
+                                       library:        options.selection,
+                                       editing:        options.editing,
+                                       menu:           'playlist',
+                                       dragInfoText:   l10n.playlistDragInfo,
+                                       dragInfo:       false
+                               }),
+
+                               new media.controller.CollectionAdd({
+                                       type: 'audio',
+                                       collectionType: 'playlist',
+                                       title: l10n.addToPlaylistTitle
+                               })
+                       ];
+               },
+
+               /**
+                * Return the video-playlist states for MediaFrame.Post
+                *
+                * @param {Object} options
+                * @returns {Array}
+                */
+               videoStates : function (options) {
+                       return [
+                               new media.controller.Library({
+                                       id:         'video-playlist',
+                                       title:      l10n.createVideoPlaylistTitle,
+                                       priority:   60,
+                                       toolbar:    'main-video-playlist',
+                                       filterable: 'uploaded',
+                                       multiple:   'add',
+                                       editable:   false,
+
+                                       library:  media.query( _.defaults({
+                                               type: 'video'
+                                       }, options.library ) )
+                               }),
+
+                               // Video Playlist states.
+                               new media.controller.CollectionEdit({
+                                       type:           'video',
+                                       collectionType: 'video-playlist',
+                                       title:          l10n.editVideoPlaylistTitle,
+                                       SettingsView:   media.view.Settings.Playlist,
+                                       library:        options.selection,
+                                       editing:        options.editing,
+                                       menu:           'video-playlist',
+                                       dragInfoText:   l10n.videoPlaylistDragInfo,
+                                       dragInfo:       false
+                               }),
+
+                               new media.controller.CollectionAdd({
+                                       type:           'video',
+                                       collectionType: 'video-playlist',
+                                       title:          l10n.addToVideoPlaylistTitle
+                               })
+                       ];
+               }
+       } );
+
+       function init() {
+               $(document.body)
+                       .on( 'click', '.wp-switch-editor', wp.media.mixin.pauseAllPlayers )
+                       .on( 'click', '.add-media-source', function () {
+                               media.frame.setState('add-' + media.frame.defaults.id + '-source');
+                       } );
+       }
+
+       $( init );
+
+}(jQuery, _, Backbone));
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjsmediaeditorjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/media-editor.js (27607 => 27608)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/media-editor.js 2014-03-19 05:28:36 UTC (rev 27607)
+++ trunk/src/wp-includes/js/media-editor.js    2014-03-19 05:30:27 UTC (rev 27608)
</span><span class="lines">@@ -11,6 +11,26 @@
</span><span class="cx">  var workflows = {};
</span><span class="cx"> 
</span><span class="cx">  /**
</span><ins>+        * A helper mixin function to avoid truthy and falsey values being
+        *   passed as an input that expects booleans. If key is undefined in the map,
+        *   but has a default value, set it.
+        *
+        * @param {object} attrs Map of props from a shortcode or settings.
+        * @param {string} key The key within the passed map to check for a value.
+        * @returns {mixed|undefined} The original or coerced value of key within attrs
+        */
+       wp.media.coerce = function ( attrs, key ) {
+               if ( _.isUndefined( attrs[ key ] ) && ! _.isUndefined( this.defaults[ key ] ) ) {
+                       attrs[ key ] = this.defaults[ key ];
+               } else if ( 'true' === attrs[ key ] ) {
+                       attrs[ key ] = true;
+               } else if ( 'false' === attrs[ key ] ) {
+                       attrs[ key ] = false;
+               }
+               return attrs[ key ];
+       };
+
+       /**
</ins><span class="cx">    * wp.media.string
</span><span class="cx">   * @namespace
</span><span class="cx">   */
</span><span class="lines">@@ -274,176 +294,11 @@
</span><span class="cx">          }
</span><span class="cx">  };
</span><span class="cx"> 
</span><del>-       /**
-        * @mixin
-        */
-       wp.media.mixin = {
-               /**
-                * A helper function to avoid truthy and falsey values being
-                *   passed as an input that expects booleans. If key is undefined in the map,
-                *   but has a default value, set it.
-                *
-                * @param {object} attrs Map of props from a shortcode or settings.
-                * @param {string} key The key within the passed map to check for a value.
-                * @returns {mixed|undefined} The original or coerced value of key within attrs
-                */
-               coerce: function ( attrs, key ) {
-                       if ( _.isUndefined( attrs[ key ] ) && ! _.isUndefined( this.defaults[ key ] ) ) {
-                               attrs[ key ] = this.defaults[ key ];
-                       } else if ( 'true' === attrs[ key ] ) {
-                               attrs[ key ] = true;
-                       } else if ( 'false' === attrs[ key ] ) {
-                               attrs[ key ] = false;
-                       }
-                       return attrs[ key ];
-               },
-
-               pauseAllPlayers: function () {
-                       var p;
-                       if ( window.mejs && window.mejs.players ) {
-                               for ( p in window.mejs.players ) {
-                                       window.mejs.players[p].pause();
-                               }
-                       }
-               },
-
-               ua: {
-                       is : function (browser) {
-                               var passes = false, ua = window.navigator.userAgent;
-
-                               switch ( browser ) {
-                                       case 'oldie':
-                                               passes = ua.match(/MSIE [6-8]/gi) !== null;
-                                       break;
-                                       case 'ie':
-                                               passes = ua.match(/MSIE/gi) !== null;
-                                       break;
-                                       case 'ff':
-                                               passes = ua.match(/firefox/gi) !== null;
-                                       break;
-                                       case 'opera':
-                                               passes = ua.match(/OPR/) !== null;
-                                       break;
-                                       case 'safari':
-                                               passes = ua.match(/safari/gi) !== null && ua.match(/chrome/gi) === null;
-                                       break;
-                                       case 'chrome':
-                                               passes = ua.match(/safari/gi) && ua.match(/chrome/gi) !== null;
-                                       break;
-                               }
-
-                               return passes;
-                       }
-               },
-
-               compat :{
-                       'opera' : {
-                               audio: ['ogg', 'wav'],
-                               video: ['ogg', 'webm']
-                       },
-                       'chrome' : {
-                               audio: ['ogg', 'mpeg', 'x-ms-wma'],
-                               video: ['ogg', 'webm', 'mp4', 'm4v', 'mpeg']
-                       },
-                       'ff' : {
-                               audio: ['ogg', 'mpeg'],
-                               video: ['ogg', 'webm']
-                       },
-                       'safari' : {
-                               audio: ['mpeg', 'wav'],
-                               video: ['mp4', 'm4v', 'mpeg', 'x-ms-wmv', 'quicktime']
-                       },
-                       'ie' : {
-                               audio: ['mpeg'],
-                               video: ['mp4', 'm4v', 'mpeg']
-                       }
-               },
-
-               isCompatible: function ( media ) {
-                       if ( ! media.find( 'source' ).length ) {
-                               return false;
-                       }
-
-                       var ua = this.ua, test = false, found = false, sources;
-
-                       if ( ua.is( 'oldIE' ) ) {
-                               return false;
-                       }
-
-                       sources = media.find( 'source' );
-
-                       _.find( this.compat, function (supports, browser) {
-                               if ( ua.is( browser ) ) {
-                                       found = true;
-                                       _.each( sources, function (elem) {
-                                               var audio = new RegExp( 'audio\/(' + supports.audio.join('|') + ')', 'gi' ),
-                                                       video = new RegExp( 'video\/(' + supports.video.join('|') + ')', 'gi' );
-
-                                               if ( elem.type.match( video ) !== null || elem.type.match( audio ) !== null ) {
-                                                       test = true;
-                                               }
-                                       } );
-                               }
-
-                               return test || found;
-                       } );
-
-                       return test;
-               },
-
-               /**
-                * Override the MediaElement method for removing a player.
-                *      MediaElement tries to pull the audio/video tag out of
-                *      its container and re-add it to the DOM.
-                */
-               removePlayer: function() {
-                       var t = this.player, featureIndex, feature;
-
-                       // invoke features cleanup
-                       for ( featureIndex in t.options.features ) {
-                               feature = t.options.features[featureIndex];
-                               if ( t['clean' + feature] ) {
-                                       try {
-                                               t['clean' + feature](t);
-                                       } catch (e) {}
-                               }
-                       }
-
-                       if ( ! t.isDynamic ) {
-                               t.$node.remove();
-                       }
-
-                       if ( 'native' !== t.media.pluginType ) {
-                               t.media.remove();
-                       }
-
-                       delete window.mejs.players[t.id];
-
-                       t.container.remove();
-                       t.globalUnbind();
-                       delete t.node.player;
-               },
-
-               /**
-                * Allows any class that has set 'player' to a MediaElementPlayer
-                *  instance to remove the player when listening to events.
-                *
-                *  Examples: modal closes, shortcode properties are removed, etc.
-                */
-               unsetPlayer : function() {
-                       if ( this.player ) {
-                               wp.media.mixin.pauseAllPlayers();
-                               wp.media.mixin.removePlayer.apply( this );
-                               this.player = false;
-                       }
-               }
-       };
-
</del><span class="cx">   wp.media.collection = function(attributes) {
</span><span class="cx">          var collections = {};
</span><span class="cx"> 
</span><span class="cx">          return _.extend( attributes, {
</span><del>-                       coerce : wp.media.mixin.coerce,
</del><ins>+                        coerce : wp.media.coerce,
</ins><span class="cx">                   /**
</span><span class="cx">                   * Retrieve attachments based on the properties of the passed shortcode
</span><span class="cx">                   *
</span><span class="lines">@@ -669,134 +524,7 @@
</span><span class="cx">          }
</span><span class="cx">  });
</span><span class="cx"> 
</span><del>-       wp.media.playlist = new wp.media.collection({
-               tag: 'playlist',
-               type : 'audio',
-               editTitle : wp.media.view.l10n.editPlaylistTitle,
-               defaults : {
-                       id: wp.media.view.settings.post.id,
-                       style: 'light',
-                       tracklist: true,
-                       tracknumbers: true,
-                       images: true,
-                       artists: true
-               }
-       });
-
-       wp.media['video-playlist'] = new wp.media.collection({
-               tag: 'video-playlist',
-               type : 'video',
-               editTitle : wp.media.view.l10n.editVideoPlaylistTitle,
-               defaults : {
-                       id: wp.media.view.settings.post.id,
-                       style: 'light',
-                       tracklist: false,
-                       tracknumbers: false,
-                       images: true
-               }
-       });
-
</del><span class="cx">   /**
</span><del>-        * @namespace
-        */
-       wp.media.audio = {
-               coerce : wp.media.mixin.coerce,
-
-               defaults : {
-                       id : wp.media.view.settings.post.id,
-                       src      : '',
-                       loop     : false,
-                       autoplay : false,
-                       preload  : 'none'
-               },
-
-               edit : function (data) {
-                       var frame, shortcode = wp.shortcode.next( 'audio', data ).shortcode;
-                       frame = wp.media({
-                               frame: 'audio',
-                               state: 'audio-details',
-                               metadata: _.defaults(
-                                       shortcode.attrs.named,
-                                       wp.media.audio.defaults
-                               )
-                       });
-
-                       return frame;
-               },
-
-               shortcode : function (shortcode) {
-                       var self = this;
-
-                       _.each( wp.media.audio.defaults, function( value, key ) {
-                               shortcode[ key ] = self.coerce( shortcode, key );
-
-                               if ( value === shortcode[ key ] ) {
-                                       delete shortcode[ key ];
-                               }
-                       });
-
-                       return wp.shortcode.string({
-                               tag:     'audio',
-                               attrs:   shortcode
-                       });
-               }
-       };
-
-       /**
-        * @namespace
-        */
-       wp.media.video = {
-               coerce : wp.media.mixin.coerce,
-
-               defaults : {
-                       id : wp.media.view.settings.post.id,
-                       src : '',
-                       poster : '',
-                       loop : false,
-                       autoplay : false,
-                       preload : 'metadata',
-                       content : ''
-               },
-
-               edit : function (data) {
-                       var frame,
-                               defaults = this.defaults,
-                               shortcode = wp.shortcode.next( 'video', data ).shortcode,
-                               attrs;
-
-                       attrs = shortcode.attrs.named;
-                       attrs.content = shortcode.content;
-
-                       frame = wp.media({
-                               frame: 'video',
-                               state: 'video-details',
-                               metadata: _.defaults( attrs, defaults )
-                       });
-
-                       return frame;
-               },
-
-               shortcode : function (shortcode) {
-                       var self = this, content = shortcode.content;
-                       delete shortcode.content;
-
-                       _.each( this.defaults, function( value, key ) {
-                               shortcode[ key ] = self.coerce( shortcode, key );
-
-                               if ( value === shortcode[ key ] ) {
-                                       delete shortcode[ key ];
-                               }
-                       });
-
-                       return wp.shortcode.string({
-                               tag:     'video',
-                               attrs:   shortcode,
-                               content: content
-                       });
-               }
-       };
-
-       /**
</del><span class="cx">    * wp.media.featuredImage
</span><span class="cx">   * @namespace
</span><span class="cx">   */
</span><span class="lines">@@ -1279,17 +1007,10 @@
</span><span class="cx">                                  if ( elem.hasClass( 'gallery' ) ) {
</span><span class="cx">                                          options.state = 'gallery';
</span><span class="cx">                                          options.title = wp.media.view.l10n.createGalleryTitle;
</span><del>-                                       } else if ( elem.hasClass( 'playlist' ) ) {
-                                               options.state = 'playlist';
-                                               options.title = wp.media.view.l10n.createPlaylistTitle;
-                                       } else if ( elem.hasClass( 'video-playlist' ) ) {
-                                               options.state = 'video-playlist';
-                                               options.title = wp.media.view.l10n.createVideoPlaylistTitle;
</del><span class="cx">                                   }
</span><span class="cx"> 
</span><span class="cx">                                  wp.media.editor.open( editor, options );
</span><del>-                               })
-                               .on( 'click', '.wp-switch-editor', wp.media.mixin.pauseAllPlayers );
</del><ins>+                                });
</ins><span class="cx"> 
</span><span class="cx">                  // Initialize and render the Editor drag-and-drop uploader.
</span><span class="cx">                  new wp.media.view.EditorUploader().render();
</span></span></pre></div>
<a id="trunksrcwpincludesjsmediamodelsjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/media-models.js (27607 => 27608)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/media-models.js 2014-03-19 05:28:36 UTC (rev 27607)
+++ trunk/src/wp-includes/js/media-models.js    2014-03-19 05:30:27 UTC (rev 27608)
</span><span class="lines">@@ -40,6 +40,8 @@
</span><span class="cx"> 
</span><span class="cx">          delete attributes.frame;
</span><span class="cx"> 
</span><ins>+               media.frame = frame;
+
</ins><span class="cx">           return frame;
</span><span class="cx">  };
</span><span class="cx"> 
</span><span class="lines">@@ -453,44 +455,6 @@
</span><span class="cx">  });
</span><span class="cx"> 
</span><span class="cx">  /**
</span><del>-        * wp.media.model.PostMedia
-        *
-        * @constructor
-        * @augments Backbone.Model
-        **/
-       media.model.PostMedia = Backbone.Model.extend({
-               initialize: function() {
-                       this.attachment = false;
-               },
-
-               setSource: function ( attachment ) {
-                       this.attachment = attachment;
-                       this.extension = attachment.get('filename' ).split('.').pop();
-
-                       if ( this.get( 'src' ) && this.extension === this.get( 'src' ).split('.').pop() ) {
-                               this.unset( 'src' );
-                       }
-
-                       if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
-                               this.set( this.extension, this.attachment.get( 'url' ) );
-                       } else {
-                               this.unset( this.extension );
-                       }
-               },
-
-               changeAttachment: function( attachment ) {
-                       var self = this;
-
-                       this.setSource( attachment );
-
-                       this.unset( 'src' );
-                       _.each( _.without( wp.media.view.settings.embedExts, this.extension ), function (ext) {
-                               self.unset( ext );
-                       } );
-               }
-       });
-
-       /**
</del><span class="cx">    * wp.media.model.Attachments
</span><span class="cx">   *
</span><span class="cx">   * @constructor
</span></span></pre></div>
<a id="trunksrcwpincludesjsmediaviewsjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/media-views.js (27607 => 27608)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/media-views.js  2014-03-19 05:28:36 UTC (rev 27607)
+++ trunk/src/wp-includes/js/media-views.js     2014-03-19 05:30:27 UTC (rev 27608)
</span><span class="lines">@@ -766,58 +766,6 @@
</span><span class="cx">  });
</span><span class="cx"> 
</span><span class="cx">  /**
</span><del>-        * wp.media.controller.AudioDetails
-        *
-        * @constructor
-        * @augments wp.media.controller.State
-        * @augments Backbone.Model
-        */
-       media.controller.AudioDetails = media.controller.State.extend({
-               defaults: _.defaults({
-                       id: 'audio-details',
-                       toolbar: 'audio-details',
-                       title: l10n.audioDetailsTitle,
-                       content: 'audio-details',
-                       menu: 'audio-details',
-                       router: false,
-                       attachment: false,
-                       priority: 60,
-                       editing: false
-               }, media.controller.Library.prototype.defaults ),
-
-               initialize: function( options ) {
-                       this.media = options.media;
-                       media.controller.State.prototype.initialize.apply( this, arguments );
-               }
-       });
-
-       /**
-        * wp.media.controller.VideoDetails
-        *
-        * @constructor
-        * @augments wp.media.controller.State
-        * @augments Backbone.Model
-        */
-       media.controller.VideoDetails = media.controller.State.extend({
-               defaults: _.defaults({
-                       id: 'video-details',
-                       toolbar: 'video-details',
-                       title: l10n.videoDetailsTitle,
-                       content: 'video-details',
-                       menu: 'video-details',
-                       router: false,
-                       attachment: false,
-                       priority: 60,
-                       editing: false
-               }, media.controller.Library.prototype.defaults ),
-
-               initialize: function( options ) {
-                       this.media = options.media;
-                       media.controller.State.prototype.initialize.apply( this, arguments );
-               }
-       });
-
-       /**
</del><span class="cx">    * wp.media.controller.CollectionEdit
</span><span class="cx">   *
</span><span class="cx">   * @constructor
</span><span class="lines">@@ -1930,7 +1878,7 @@
</span><span class="cx">          },
</span><span class="cx"> 
</span><span class="cx">          createStates: function() {
</span><del>-                       var options = this.options;
</del><ins>+                        var options = this.options, counts;
</ins><span class="cx"> 
</span><span class="cx">                  // Add the default states.
</span><span class="cx">                  this.states.add([
</span><span class="lines">@@ -1990,76 +1938,19 @@
</span><span class="cx">                                  type:           'image',
</span><span class="cx">                                  collectionType: 'gallery',
</span><span class="cx">                                  title:          l10n.addToGalleryTitle
</span><del>-                               }),
</del><ins>+                                })
+                       ]);
</ins><span class="cx"> 
</span><del>-                               new media.controller.Library({
-                                       id:         'playlist',
-                                       title:      l10n.createPlaylistTitle,
-                                       priority:   60,
-                                       toolbar:    'main-playlist',
-                                       filterable: 'uploaded',
-                                       multiple:   'add',
-                                       editable:   false,
</del><ins>+                        counts = media.playlist.counts();
</ins><span class="cx"> 
</span><del>-                                       library:  media.query( _.defaults({
-                                               type: 'audio'
-                                       }, options.library ) )
-                               }),
</del><ins>+                        if ( counts.audio ) {
+                               this.states.add( media.playlist.states(options) );
+                       }
</ins><span class="cx"> 
</span><del>-                               // Playlist states.
-                               new media.controller.CollectionEdit({
-                                       type:           'audio',
-                                       collectionType: 'playlist',
-                                       title:          l10n.editPlaylistTitle,
-                                       SettingsView:   media.view.Settings.Playlist,
-                                       library:        options.selection,
-                                       editing:        options.editing,
-                                       menu:           'playlist',
-                                       dragInfoText:   l10n.playlistDragInfo,
-                                       dragInfo:       false
-                               }),
</del><ins>+                        if ( counts.video ) {
+                               this.states.add( media.playlist.videoStates(options) );
+                       }
</ins><span class="cx"> 
</span><del>-                               new media.controller.CollectionAdd({
-                                       type: 'audio',
-                                       collectionType: 'playlist',
-                                       title: l10n.addToPlaylistTitle
-                               }),
-
-                               new media.controller.Library({
-                                       id:         'video-playlist',
-                                       title:      l10n.createVideoPlaylistTitle,
-                                       priority:   60,
-                                       toolbar:    'main-video-playlist',
-                                       filterable: 'uploaded',
-                                       multiple:   'add',
-                                       editable:   false,
-
-                                       library:  media.query( _.defaults({
-                                               type: 'video'
-                                       }, options.library ) )
-                               }),
-
-                               // Video Playlist states.
-                               new media.controller.CollectionEdit({
-                                       type:           'video',
-                                       collectionType: 'video-playlist',
-                                       title:          l10n.editVideoPlaylistTitle,
-                                       SettingsView:   media.view.Settings.Playlist,
-                                       library:        options.selection,
-                                       editing:        options.editing,
-                                       menu:           'video-playlist',
-                                       dragInfoText:   l10n.videoPlaylistDragInfo,
-                                       dragInfo:       false
-                               }),
-
-                               new media.controller.CollectionAdd({
-                                       type:           'video',
-                                       collectionType: 'video-playlist',
-                                       title:          l10n.addToVideoPlaylistTitle
-                               })
-                       ]);
-
-
</del><span class="cx">                   if ( media.view.settings.post.featuredImageId ) {
</span><span class="cx">                          this.states.add( new media.controller.FeaturedImage() );
</span><span class="cx">                  }
</span><span class="lines">@@ -2746,391 +2637,6 @@
</span><span class="cx">  });
</span><span class="cx"> 
</span><span class="cx">  /**
</span><del>-        * wp.media.view.MediaFrame.MediaDetails
-        *
-        * @constructor
-        * @augments wp.media.view.MediaFrame.Select
-        * @augments wp.media.view.MediaFrame
-        * @augments wp.media.view.Frame
-        * @augments wp.media.View
-        * @augments wp.Backbone.View
-        * @augments Backbone.View
-        * @mixes wp.media.controller.StateMachine
-        */
-       media.view.MediaFrame.MediaDetails = media.view.MediaFrame.Select.extend({
-               defaults: {
-                       id:      'media',
-                       url:     '',
-                       menu:    'media-details',
-                       content: 'media-details',
-                       toolbar: 'media-details',
-                       type:    'link',
-                       priority: 120
-               },
-
-               initialize: function( options ) {
-                       this.DetailsView = options.DetailsView;
-                       this.cancelText = options.cancelText;
-                       this.addText = options.addText;
-
-                       this.media = new media.model.PostMedia( options.metadata );
-                       this.options.selection = new media.model.Selection( this.media.attachment, { multiple: false } );
-                       media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
-               },
-
-               bindHandlers: function() {
-                       var menu = this.defaults.menu;
-
-                       media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
-
-                       this.on( 'menu:create:' + menu, this.createMenu, this );
-                       this.on( 'content:render:' + menu, this.renderDetailsContent, this );
-                       this.on( 'menu:render:' + menu, this.renderMenu, this );
-                       this.on( 'toolbar:render:' + menu, this.renderDetailsToolbar, this );
-               },
-
-               renderDetailsContent: function() {
-                       var view = new this.DetailsView({
-                               controller: this,
-                               model: this.state().media,
-                               attachment: this.state().media.attachment
-                       }).render();
-
-                       this.content.set( view );
-               },
-
-               renderMenu: function( view ) {
-                       var lastState = this.lastState(),
-                               previous = lastState && lastState.id,
-                               frame = this;
-
-                       view.set({
-                               cancel: {
-                                       text:     this.cancelText,
-                                       priority: 20,
-                                       click:    function() {
-                                               if ( previous ) {
-                                                       frame.setState( previous );
-                                               } else {
-                                                       frame.close();
-                                               }
-                                       }
-                               },
-                               separateCancel: new media.View({
-                                       className: 'separator',
-                                       priority: 40
-                               })
-                       });
-
-               },
-
-               renderDetailsToolbar: function() {
-                       this.toolbar.set( new media.view.Toolbar({
-                               controller: this,
-                               items: {
-                                       select: {
-                                               style:    'primary',
-                                               text:     l10n.update,
-                                               priority: 80,
-
-                                               click: function() {
-                                                       var controller = this.controller,
-                                                               state = controller.state();
-
-                                                       controller.close();
-
-                                                       state.trigger( 'update', controller.media.toJSON() );
-
-                                                       // Restore and reset the default state.
-                                                       controller.setState( controller.options.state );
-                                                       controller.reset();
-                                               }
-                                       }
-                               }
-                       }) );
-               },
-
-               renderReplaceToolbar: function() {
-                       this.toolbar.set( new media.view.Toolbar({
-                               controller: this,
-                               items: {
-                                       replace: {
-                                               style:    'primary',
-                                               text:     l10n.replace,
-                                               priority: 80,
-
-                                               click: function() {
-                                                       var controller = this.controller,
-                                                               state = controller.state(),
-                                                               selection = state.get( 'selection' ),
-                                                               attachment = selection.single();
-
-                                                       controller.media.changeAttachment( attachment );
-
-                                                       state.trigger( 'replace', controller.media.toJSON() );
-
-                                                       // Restore and reset the default state.
-                                                       controller.setState( controller.options.state );
-                                                       controller.reset();
-                                               }
-                                       }
-                               }
-                       }) );
-               },
-
-               renderAddSourceToolbar: function() {
-                       this.toolbar.set( new media.view.Toolbar({
-                               controller: this,
-                               items: {
-                                       replace: {
-                                               style:    'primary',
-                                               text:     this.addText,
-                                               priority: 80,
-
-                                               click: function() {
-                                                       var controller = this.controller,
-                                                               state = controller.state(),
-                                                               selection = state.get( 'selection' ),
-                                                               attachment = selection.single();
-
-                                                       controller.media.setSource( attachment );
-
-                                                       state.trigger( 'add-source', controller.media.toJSON() );
-
-                                                       // Restore and reset the default state.
-                                                       controller.setState( controller.options.state );
-                                                       controller.reset();
-                                               }
-                                       }
-                               }
-                       }) );
-               }
-       });
-
-       /**
-        * wp.media.view.MediaFrame.AudioDetails
-        *
-        * @constructor
-        * @augments wp.media.view.MediaFrame.MediaDetails
-        * @augments wp.media.view.MediaFrame.Select
-        * @augments wp.media.view.MediaFrame
-        * @augments wp.media.view.Frame
-        * @augments wp.media.View
-        * @augments wp.Backbone.View
-        * @augments Backbone.View
-        * @mixes wp.media.controller.StateMachine
-        */
-       media.view.MediaFrame.AudioDetails = media.view.MediaFrame.MediaDetails.extend({
-               defaults: {
-                       id:      'audio',
-                       url:     '',
-                       menu:    'audio-details',
-                       content: 'audio-details',
-                       toolbar: 'audio-details',
-                       type:    'link',
-                       title:    l10n.audioDetailsTitle,
-                       priority: 120
-               },
-
-               initialize: function( options ) {
-                       options.DetailsView = media.view.AudioDetails;
-                       options.cancelText = l10n.audioDetailsCancel;
-                       options.addText = l10n.audioAddSourceTitle;
-
-                       media.view.MediaFrame.MediaDetails.prototype.initialize.call( this, options );
-               },
-
-               bindHandlers: function() {
-                       media.view.MediaFrame.MediaDetails.prototype.bindHandlers.apply( this, arguments );
-
-                       this.on( 'toolbar:render:replace-audio', this.renderReplaceToolbar, this );
-                       this.on( 'toolbar:render:add-audio-source', this.renderAddSourceToolbar, this );
-               },
-
-               createStates: function() {
-                       this.states.add([
-                               new media.controller.AudioDetails( {
-                                       media: this.media,
-                                       editable: false,
-                                       menu: 'audio-details'
-                               } ),
-
-                               new media.controller.MediaLibrary( {
-                                       type: 'audio',
-                                       id: 'replace-audio',
-                                       title: l10n.audioReplaceTitle,
-                                       toolbar: 'replace-audio',
-                                       media: this.media,
-                                       menu: 'audio-details'
-                               } ),
-
-                               new media.controller.MediaLibrary( {
-                                       type: 'audio',
-                                       id: 'add-audio-source',
-                                       title: l10n.audioAddSourceTitle,
-                                       toolbar: 'add-audio-source',
-                                       media: this.media,
-                                       menu: 'audio-details'
-                               } )
-                       ]);
-               }
-       });
-
-       /**
-        * wp.media.view.MediaFrame.VideoDetails
-        *
-        * @constructor
-        * @augments wp.media.view.MediaFrame.MediaDetails
-        * @augments wp.media.view.MediaFrame.Select
-        * @augments wp.media.view.MediaFrame
-        * @augments wp.media.view.Frame
-        * @augments wp.media.View
-        * @augments wp.Backbone.View
-        * @augments Backbone.View
-        * @mixes wp.media.controller.StateMachine
-        */
-       media.view.MediaFrame.VideoDetails = media.view.MediaFrame.MediaDetails.extend({
-               defaults: {
-                       id:      'video',
-                       url:     '',
-                       menu:    'video-details',
-                       content: 'video-details',
-                       toolbar: 'video-details',
-                       type:    'link',
-                       title:    l10n.videoDetailsTitle,
-                       priority: 120
-               },
-
-               initialize: function( options ) {
-                       options.DetailsView = media.view.VideoDetails;
-                       options.cancelText = l10n.videoDetailsCancel;
-                       options.addText = l10n.videoAddSourceTitle;
-
-                       media.view.MediaFrame.MediaDetails.prototype.initialize.call( this, options );
-               },
-
-               bindHandlers: function() {
-                       media.view.MediaFrame.MediaDetails.prototype.bindHandlers.apply( this, arguments );
-
-                       this.on( 'toolbar:render:replace-video', this.renderReplaceToolbar, this );
-                       this.on( 'toolbar:render:add-video-source', this.renderAddSourceToolbar, this );
-                       this.on( 'toolbar:render:select-poster-image', this.renderSelectPosterImageToolbar, this );
-                       this.on( 'toolbar:render:add-track', this.renderAddTrackToolbar, this );
-               },
-
-               createStates: function() {
-                       this.states.add([
-                               new media.controller.VideoDetails({
-                                       media: this.media,
-                                       editable: false,
-                                       menu: 'video-details'
-                               }),
-
-                               new media.controller.MediaLibrary( {
-                                       type: 'video',
-                                       id: 'replace-video',
-                                       title: l10n.videoReplaceTitle,
-                                       toolbar: 'replace-video',
-                                       media: this.media,
-                                       menu: 'video-details'
-                               } ),
-
-                               new media.controller.MediaLibrary( {
-                                       type: 'video',
-                                       id: 'add-video-source',
-                                       title: l10n.videoAddSourceTitle,
-                                       toolbar: 'add-video-source',
-                                       media: this.media,
-                                       menu: 'video-details'
-                               } ),
-
-                               new media.controller.MediaLibrary( {
-                                       type: 'image',
-                                       id: 'select-poster-image',
-                                       title: l10n.videoSelectPosterImageTitle,
-                                       toolbar: 'select-poster-image',
-                                       media: this.media,
-                                       menu: 'video-details'
-                               } ),
-
-                               new media.controller.MediaLibrary( {
-                                       type: 'text',
-                                       id: 'add-track',
-                                       title: l10n.videoAddTrackTitle,
-                                       toolbar: 'add-track',
-                                       media: this.media,
-                                       menu: 'video-details'
-                               } )
-                       ]);
-               },
-
-               renderSelectPosterImageToolbar: function() {
-                       this.toolbar.set( new media.view.Toolbar({
-                               controller: this,
-                               items: {
-                                       replace: {
-                                               style:    'primary',
-                                               text:     l10n.videoSelectPosterImageTitle,
-                                               priority: 80,
-
-                                               click: function() {
-                                                       var controller = this.controller,
-                                                               state = controller.state(),
-                                                               selection = state.get( 'selection' ),
-                                                               attachment = selection.single();
-
-                                                       controller.media.set( 'poster', attachment.get( 'url' ) );
-
-                                                       state.trigger( 'set-poster-image', controller.media.toJSON() );
-
-                                                       // Restore and reset the default state.
-                                                       controller.setState( controller.options.state );
-                                                       controller.reset();
-                                               }
-                                       }
-                               }
-                       }) );
-               },
-
-               renderAddTrackToolbar: function() {
-                       this.toolbar.set( new media.view.Toolbar({
-                               controller: this,
-                               items: {
-                                       replace: {
-                                               style:    'primary',
-                                               text:     l10n.videoAddTrackTitle,
-                                               priority: 80,
-
-                                               click: function() {
-                                                       var controller = this.controller,
-                                                               state = controller.state(),
-                                                               selection = state.get( 'selection' ),
-                                                               attachment = selection.single(),
-                                                               content = controller.media.get( 'content' );
-
-                                                       if ( -1 === content.indexOf( attachment.get( 'url' ) ) ) {
-                                                               content += [
-                                                                       '<track srclang="en" label="English"kind="subtitles" src="',
-                                                                       attachment.get( 'url' ),
-                                                                       '" />'
-                                                               ].join('');
-
-                                                               controller.media.set( 'content', content );
-                                                       }
-
-                                                       state.trigger( 'add-track', controller.media.toJSON() );
-
-                                                       // Restore and reset the default state.
-                                                       controller.setState( controller.options.state );
-                                                       controller.reset();
-                                               }
-                                       }
-                               }
-                       }) );
-               }
-       });
-
-       /**
</del><span class="cx">    * wp.media.view.Modal
</span><span class="cx">   *
</span><span class="cx">   * @constructor
</span><span class="lines">@@ -6663,75 +6169,6 @@
</span><span class="cx">  });
</span><span class="cx"> 
</span><span class="cx">  /**
</span><del>-        * wp.media.view.AudioDetails
-        *
-        * @contructor
-        * @augments wp.media.view.MediaDetails
-        * @augments wp.media.view.Settings.AttachmentDisplay
-        * @augments wp.media.view.Settings
-        * @augments wp.media.View
-        * @augments wp.Backbone.View
-        * @augments Backbone.View
-        */
-       media.view.AudioDetails = media.view.MediaDetails.extend({
-               className: 'audio-details',
-               template:  media.template('audio-details'),
-
-               setMedia: function() {
-                       var audio = this.$('.wp-audio-shortcode');
-
-                       if ( audio.find( 'source' ).length ) {
-                               if ( audio.is(':hidden') ) {
-                                       audio.show();
-                               }
-                               this.media = media.view.MediaDetails.prepareSrc( audio.get(0) );
-                       } else {
-                               audio.hide();
-                               this.media = false;
-                       }
-
-                       return this;
-               }
-       });
-
-       /**
-        * wp.media.view.VideoDetails
-        *
-        * @contructor
-        * @augments wp.media.view.MediaDetails
-        * @augments wp.media.view.Settings.AttachmentDisplay
-        * @augments wp.media.view.Settings
-        * @augments wp.media.View
-        * @augments wp.Backbone.View
-        * @augments Backbone.View
-        */
-       media.view.VideoDetails = media.view.MediaDetails.extend({
-               className: 'video-details',
-               template:  media.template('video-details'),
-
-               setMedia: function() {
-                       var video = this.$('.wp-video-shortcode');
-
-                       if ( video.find( 'source' ).length ) {
-                               if ( video.is(':hidden') ) {
-                                       video.show();
-                               }
-
-                               if ( ! video.hasClass('youtube-video') ) {
-                                       this.media = media.view.MediaDetails.prepareSrc( video.get(0) );
-                               } else {
-                                       this.media = video.get(0);
-                               }
-                       } else {
-                               video.hide();
-                               this.media = false;
-                       }
-
-                       return this;
-               }
-       });
-
-       /**
</del><span class="cx">    * wp.media.view.Spinner
</span><span class="cx">   *
</span><span class="cx">   * @constructor
</span></span></pre></div>
<a id="trunksrcwpincludesjsmediaelementwpmediaelementcss"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/mediaelement/wp-mediaelement.css (27607 => 27608)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/mediaelement/wp-mediaelement.css        2014-03-19 05:28:36 UTC (rev 27607)
+++ trunk/src/wp-includes/js/mediaelement/wp-mediaelement.css   2014-03-19 05:30:27 UTC (rev 27608)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> 
</span><span class="cx"> .media-embed-details .embed-media-settings {
</span><span class="cx">  padding-top: 0;
</span><ins>+       top: 28px;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> .media-embed-details .instructions {
</span><span class="lines">@@ -44,10 +45,6 @@
</span><span class="cx">  color: #f00;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.media-embed-details .embed-media-settings {
-       top: 0;
-}
-
</del><span class="cx"> .media-embed-details .embed-media-settings .checkbox-setting {
</span><span class="cx">  width: 100px;
</span><span class="cx">  clear: none;
</span></span></pre></div>
<a id="trunksrcwpincludesmediatemplatephp"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/media-template.php (27607 => 27608)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/media-template.php 2014-03-19 05:28:36 UTC (rev 27607)
+++ trunk/src/wp-includes/media-template.php    2014-03-19 05:30:27 UTC (rev 27608)
</span><span class="lines">@@ -765,14 +765,19 @@
</span><span class="cx">  </script>
</span><span class="cx"> 
</span><span class="cx">  <script type="text/html" id="tmpl-audio-details">
</span><ins>+               <# var ext, html5types = { mp3: true, ogg: true }; #>
+
</ins><span class="cx">           <?php $audio_types = wp_get_audio_extensions(); ?>
</span><span class="cx">          <div class="media-embed media-embed-details">
</span><span class="cx">                  <div class="embed-media-settings embed-audio-settings">
</span><del>-                               <div class="instructions media-instructions">{{{ wp.media.view.l10n.audioDetailsText }}}</div>
-
</del><span class="cx">                           <?php wp_underscore_audio_template() ?>
</span><span class="cx"> 
</span><del>-                               <# if ( ! _.isEmpty( data.model.src ) ) { #>
</del><ins>+                                <# if ( ! _.isEmpty( data.model.src ) ) {
+                                       ext = data.model.src.split('.').pop();
+                                       if ( html5types[ ext ] ) {
+                                               delete html5types[ ext ];
+                                       }
+                               #>
</ins><span class="cx">                           <label class="setting">
</span><span class="cx">                                  <span>SRC</span>
</span><span class="cx">                                  <input type="text" disabled="disabled" data-setting="src" value="{{ data.model.src }}" />
</span><span class="lines">@@ -782,7 +787,11 @@
</span><span class="cx">                          <?php
</span><span class="cx"> 
</span><span class="cx">                          foreach ( $audio_types as $type ):
</span><del>-                               ?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) { #>
</del><ins>+                                ?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) {
+                                       if ( ! _.isUndefined( html5types.<?php echo $type ?> ) ) {
+                                               delete html5types.<?php echo $type ?>;
+                                       }
+                               #>
</ins><span class="cx">                           <label class="setting">
</span><span class="cx">                                  <span><?php echo strtoupper( $type ) ?></span>
</span><span class="cx">                                  <input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{ data.model.<?php echo $type ?> }}" />
</span><span class="lines">@@ -791,6 +800,17 @@
</span><span class="cx">                          <# } #>
</span><span class="cx">                          <?php endforeach ?>
</span><span class="cx"> 
</span><ins>+                               <# if ( ! _.isEmpty( html5types ) ) { #>
+                               <div class="setting">
+                                       <span>{{{ wp.media.view.l10n.mediaHTML5Text }}}</span>
+                                       <div class="button-large">
+                                       <# _.each( html5types, function (value, type) { #>
+                                       <button class="button add-media-source">{{ type }}</button>
+                                       <# } ) #>
+                                       </div>
+                               </div>
+                               <# } #>
+
</ins><span class="cx">                           <div class="setting preload">
</span><span class="cx">                                  <span><?php _e( 'Preload' ); ?></span>
</span><span class="cx">                                  <div class="button-group button-large" data-setting="preload">
</span><span class="lines">@@ -815,10 +835,11 @@
</span><span class="cx">  </script>
</span><span class="cx"> 
</span><span class="cx">  <script type="text/html" id="tmpl-video-details">
</span><ins>+               <# var ext, html5types = { mp4: true, ogv: true, webm: true }; #>
+
</ins><span class="cx">           <?php $video_types = wp_get_video_extensions(); ?>
</span><span class="cx">          <div class="media-embed media-embed-details">
</span><span class="cx">                  <div class="embed-media-settings embed-video-settings">
</span><del>-                               <div class="instructions media-instructions">{{{ wp.media.view.l10n.videoDetailsText }}}</div>
</del><span class="cx">                           <div class="wp-video-holder">
</span><span class="cx">                          <#
</span><span class="cx">                          var isYouTube = ! _.isEmpty( data.model.src ) && data.model.src.match(/youtube|youtu\.be/);
</span><span class="lines">@@ -832,7 +853,12 @@
</span><span class="cx"> 
</span><span class="cx">                          <?php wp_underscore_video_template() ?>
</span><span class="cx"> 
</span><del>-                               <# if ( ! _.isEmpty( data.model.src ) ) { #>
</del><ins>+                                <# if ( ! _.isEmpty( data.model.src ) ) {
+                                       ext = data.model.src.split('.').pop();
+                                       if ( html5types[ ext ] ) {
+                                               delete html5types[ ext ];
+                                       }
+                               #>
</ins><span class="cx">                           <label class="setting">
</span><span class="cx">                                  <span>SRC</span>
</span><span class="cx">                                  <input type="text" disabled="disabled" data-setting="src" value="{{ data.model.src }}" />
</span><span class="lines">@@ -840,7 +866,11 @@
</span><span class="cx">                          </label>
</span><span class="cx">                          <# } #>
</span><span class="cx">                          <?php foreach ( $video_types as $type ):
</span><del>-                               ?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) { #>
</del><ins>+                                ?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) {
+                                       if ( ! _.isUndefined( html5types.<?php echo $type ?> ) ) {
+                                               delete html5types.<?php echo $type ?>;
+                                       }
+                               #>
</ins><span class="cx">                           <label class="setting">
</span><span class="cx">                                  <span><?php echo strtoupper( $type ) ?></span>
</span><span class="cx">                                  <input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{ data.model.<?php echo $type ?> }}" />
</span><span class="lines">@@ -849,6 +879,18 @@
</span><span class="cx">                          <# } #>
</span><span class="cx">                          <?php endforeach ?>
</span><span class="cx">                          </div>
</span><ins>+
+                               <# if ( ! _.isEmpty( html5types ) ) { #>
+                               <div class="setting">
+                                       <span>{{{ wp.media.view.l10n.mediaHTML5Text }}}</span>
+                                       <div class="button-large">
+                                       <# _.each( html5types, function (value, type) { #>
+                                       <button class="button add-media-source">{{ type }}</button>
+                                       <# } ) #>
+                                       </div>
+                               </div>
+                               <# } #>
+
</ins><span class="cx">                           <# if ( ! _.isEmpty( data.model.poster ) ) { #>
</span><span class="cx">                          <label class="setting">
</span><span class="cx">                                  <span><?php _e( 'Poster Image' ); ?></span>
</span></span></pre></div>
<a id="trunksrcwpincludesmediaphp"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/media.php (27607 => 27608)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/media.php  2014-03-19 05:28:36 UTC (rev 27607)
+++ trunk/src/wp-includes/media.php     2014-03-19 05:30:27 UTC (rev 27608)
</span><span class="lines">@@ -2400,6 +2400,7 @@
</span><span class="cx">                  'id' => 0,
</span><span class="cx">          ),
</span><span class="cx">          'defaultProps' => $props,
</span><ins>+               'attachmentCounts' => wp_count_attachments(),
</ins><span class="cx">           'embedExts'    => $exts,
</span><span class="cx">          'embedMimes'   => $ext_mimes
</span><span class="cx">  );
</span><span class="lines">@@ -2495,21 +2496,19 @@
</span><span class="cx">          /* translators: suggested height of header image in pixels */
</span><span class="cx">          'suggestedHeight' => __( 'Suggested height is %d pixels.' ),
</span><span class="cx"> 
</span><ins>+               'mediaHTML5Text'        => __( 'Add alternate sources for maximum HTML5 playback:' ),
+
</ins><span class="cx">           // Edit Audio
</span><span class="cx">          'audioDetailsTitle'     => __( 'Audio Details' ),
</span><span class="cx">          'audioReplaceTitle'     => __( 'Replace Audio' ),
</span><span class="cx">          'audioAddSourceTitle'   => __( 'Add Audio Source' ),
</span><span class="cx">          'audioDetailsCancel'    => __( 'Cancel Edit' ),
</span><del>-               'audioDetailsText'      => __( '"Replace Audio" will remove all associated source files when you update. ' .
-                       '"Add Audio Source" allows you to specify alternate sources for maximum native HTML5 audio playback.' ),
</del><span class="cx"> 
</span><span class="cx">          // Edit Video
</span><span class="cx">          'videoDetailsTitle'     => __( 'Video Details' ),
</span><span class="cx">          'videoReplaceTitle'     => __( 'Replace Video' ),
</span><span class="cx">          'videoAddSourceTitle'   => __( 'Add Video Source' ),
</span><span class="cx">          'videoDetailsCancel'    => __( 'Cancel Edit' ),
</span><del>-               'videoDetailsText'      => __( '"Replace Video" will remove all associated source files when you update. ' .
-                       '"Add Video Source" allows you to specify alternate sources for maximum native HTML5 video playback.' ),
</del><span class="cx">           'videoSelectPosterImageTitle' => _( 'Select Poster Image' ),
</span><span class="cx">          'videoAddTrackTitle'    => __( 'Add Subtitles' ),
</span><span class="cx"> 
</span><span class="lines">@@ -2542,6 +2541,7 @@
</span><span class="cx">  wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings );
</span><span class="cx"> 
</span><span class="cx">  wp_enqueue_script( 'media-editor' );
</span><ins>+       wp_enqueue_script( 'media-audiovideo' );
</ins><span class="cx">   wp_enqueue_style( 'media-views' );
</span><span class="cx">  wp_enqueue_style( 'imgareaselect' );
</span><span class="cx">  wp_plupload_default_settings();
</span></span></pre></div>
<a id="trunksrcwpincludesscriptloaderphp"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/script-loader.php (27607 => 27608)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/script-loader.php  2014-03-19 05:28:36 UTC (rev 27607)
+++ trunk/src/wp-includes/script-loader.php     2014-03-19 05:30:27 UTC (rev 27608)
</span><span class="lines">@@ -396,6 +396,7 @@
</span><span class="cx">  // Both rely on numerous settings, styles, and templates to operate correctly.
</span><span class="cx">  $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 );
</span><span class="cx">  $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
</span><ins>+       $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor' ), false, 1 );
</ins><span class="cx">   $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 );
</span><span class="cx"> 
</span><span class="cx">  if ( is_admin() ) {
</span></span></pre>
</div>
</div>

</body>
</html>