Skip to content

Commit d39e5ec

Browse files
committed
Video editing in the media modal:
* Add a state: `Add Subititles` * Add `text/vtt` to the list of allowed mime-types, files end in `.vtt`. `.srt` files are served as `text/plain`. * The content body of a video shortcode should be used for adding `<track>` elements only. This happens dynamically in the modal. If added by hand, they can still be parsed and managed. See #27016. git-svn-id: https://develop.svn.wordpress.org/trunk@27481 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 29e2d9f commit d39e5ec

7 files changed

Lines changed: 133 additions & 62 deletions

File tree

src/wp-includes/functions.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,6 +1983,7 @@ function wp_get_mime_types() {
19831983
'rtx' => 'text/richtext',
19841984
'css' => 'text/css',
19851985
'htm|html' => 'text/html',
1986+
'vtt' => 'text/vtt',
19861987
// Audio formats
19871988
'mp3|m4a|m4b' => 'audio/mpeg',
19881989
'ra|ram' => 'audio/x-realaudio',

src/wp-includes/js/media-editor.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -609,26 +609,33 @@
609609
poster : '',
610610
loop : false,
611611
autoplay : false,
612-
preload : 'metadata'
612+
preload : 'metadata',
613+
content : ''
613614
},
614615

615616
edit : function (data) {
616-
var frame, shortcode = wp.shortcode.next( 'video', data ).shortcode;
617+
var frame,
618+
defaults = this.defaults,
619+
shortcode = wp.shortcode.next( 'video', data ).shortcode,
620+
attrs;
621+
622+
attrs = shortcode.attrs.named;
623+
attrs.content = shortcode.content;
624+
617625
frame = wp.media({
618626
frame: 'video',
619627
state: 'video-details',
620-
metadata: _.defaults(
621-
shortcode.attrs.named,
622-
wp.media.video.defaults
623-
)
628+
metadata: _.defaults( attrs, defaults )
624629
});
625630

626631
return frame;
627632
},
628633

629634
shortcode : function (shortcode) {
630-
var self = this;
631-
_.each( wp.media.video.defaults, function( value, key ) {
635+
var self = this, content = shortcode.content;
636+
delete shortcode.content;
637+
638+
_.each( this.defaults, function( value, key ) {
632639
shortcode[ key ] = self.coerce( shortcode, key );
633640

634641
if ( value === shortcode[ key ] ) {
@@ -638,7 +645,8 @@
638645

639646
return wp.shortcode.string({
640647
tag: 'video',
641-
attrs: shortcode
648+
attrs: shortcode,
649+
content: content
642650
});
643651
}
644652
}, wp.media.mixin);

src/wp-includes/js/media-views.js

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,41 +1193,16 @@
11931193
media.controller.MediaLibrary = media.controller.Library.extend({
11941194
defaults: _.defaults({
11951195
filterable: 'uploaded',
1196-
multiple: false,
11971196
priority: 80,
11981197
syncSelection: false,
1199-
displaySettings: true
1198+
displaySettings: false
12001199
}, media.controller.Library.prototype.defaults ),
12011200

12021201
initialize: function( options ) {
1203-
var library, comparator;
1204-
12051202
this.media = options.media;
12061203
this.set( 'library', media.query({ type: options.type }) );
12071204

12081205
media.controller.Library.prototype.initialize.apply( this, arguments );
1209-
1210-
library = this.get('library');
1211-
comparator = library.comparator;
1212-
1213-
// Overload the library's comparator to push items that are not in
1214-
// the mirrored query to the front of the aggregate collection.
1215-
library.comparator = function( a, b ) {
1216-
var aInQuery = !! this.mirroring.get( a.cid ),
1217-
bInQuery = !! this.mirroring.get( b.cid );
1218-
1219-
if ( ! aInQuery && bInQuery ) {
1220-
return -1;
1221-
} else if ( aInQuery && ! bInQuery ) {
1222-
return 1;
1223-
} else {
1224-
return comparator.apply( this, arguments );
1225-
}
1226-
};
1227-
1228-
// Add all items in the selection to the library, so any featured
1229-
// images that are not initially loaded still appear.
1230-
library.observe( this.get('selection') );
12311206
}
12321207
});
12331208

@@ -2952,6 +2927,7 @@
29522927
this.on( 'toolbar:render:replace-video', this.renderReplaceToolbar, this );
29532928
this.on( 'toolbar:render:add-video-source', this.renderAddSourceToolbar, this );
29542929
this.on( 'toolbar:render:select-poster-image', this.renderSelectPosterImageToolbar, this );
2930+
this.on( 'toolbar:render:add-track', this.renderAddTrackToolbar, this );
29552931
},
29562932

29572933
createStates: function() {
@@ -2987,6 +2963,15 @@
29872963
toolbar: 'select-poster-image',
29882964
media: this.media,
29892965
menu: 'video-details'
2966+
} ),
2967+
2968+
new media.controller.MediaLibrary( {
2969+
type: 'text',
2970+
id: 'add-track',
2971+
title: l10n.videoAddTrackTitle,
2972+
toolbar: 'add-track',
2973+
media: this.media,
2974+
menu: 'video-details'
29902975
} )
29912976
]);
29922977
},
@@ -3010,6 +2995,43 @@
30102995

30112996
state.trigger( 'set-poster-image', controller.media.toJSON() );
30122997

2998+
// Restore and reset the default state.
2999+
controller.setState( controller.options.state );
3000+
controller.reset();
3001+
}
3002+
}
3003+
}
3004+
}) );
3005+
},
3006+
3007+
renderAddTrackToolbar: function() {
3008+
this.toolbar.set( new media.view.Toolbar({
3009+
controller: this,
3010+
items: {
3011+
replace: {
3012+
style: 'primary',
3013+
text: l10n.videoAddTrackTitle,
3014+
priority: 80,
3015+
3016+
click: function() {
3017+
var controller = this.controller,
3018+
state = controller.state(),
3019+
selection = state.get( 'selection' ),
3020+
attachment = selection.single(),
3021+
content = controller.media.get( 'content' );
3022+
3023+
if ( -1 === content.indexOf( attachment.get( 'url' ) ) ) {
3024+
content += [
3025+
'<track srclang="en" label="English"kind="subtitles" src="',
3026+
attachment.get( 'url' ),
3027+
'" />'
3028+
].join('');
3029+
3030+
controller.media.set( 'content', content );
3031+
}
3032+
3033+
state.trigger( 'add-track', controller.media.toJSON() );
3034+
30133035
// Restore and reset the default state.
30143036
controller.setState( controller.options.state );
30153037
controller.reset();
@@ -6366,21 +6388,17 @@
63666388
this.on( 'media:setting:remove', this.render );
63676389
this.on( 'media:setting:remove', this.setPlayer );
63686390
this.events = _.extend( this.events, {
6369-
'click .remove-setting' : 'removeSetting'
6391+
'click .remove-setting' : 'removeSetting',
6392+
'change .content-track' : 'setTracks',
6393+
'click .remove-track' : 'setTracks'
63706394
} );
63716395

63726396
media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
63736397
},
63746398

63756399
prepare: function() {
6376-
var attachment = false;
6377-
6378-
if ( this.model.attachment ) {
6379-
attachment = this.model.attachment.toJSON();
6380-
}
63816400
return _.defaults({
6382-
model: this.model.toJSON(),
6383-
attachment: attachment
6401+
model: this.model.toJSON()
63846402
}, this.options );
63856403
},
63866404

@@ -6404,12 +6422,26 @@
64046422
},
64056423

64066424
removeSetting : function (e) {
6407-
var setting = $( e.currentTarget ).parent();
6425+
var wrap = $( e.currentTarget ).parent(), setting;
6426+
6427+
setting = wrap.find( 'input' ).data( 'setting' );
6428+
6429+
if ( setting ) {
6430+
this.model.unset( setting );
6431+
this.trigger( 'media:setting:remove', this );
6432+
}
6433+
6434+
wrap.remove();
6435+
},
64086436

6409-
this.model.unset( setting.find( 'input' ).data( 'setting' ) );
6437+
setTracks : function () {
6438+
var tracks = '';
64106439

6411-
setting.remove();
6440+
_.each( this.$('.content-track'), function (track) {
6441+
tracks += $( track ).val();
6442+
} );
64126443

6444+
this.model.set( 'content', tracks );
64136445
this.trigger( 'media:setting:remove', this );
64146446
},
64156447

src/wp-includes/js/mediaelement/wp-mediaelement.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
max-width: 400px;
2020
}
2121

22+
.media-embed-details .embed-media-settings .setting span {
23+
max-width: 400px;
24+
width: auto;
25+
}
26+
2227
.media-embed-details .embed-media-settings {
2328
padding-top: 0;
2429
}
@@ -28,8 +33,11 @@
2833
max-width: 600px;
2934
}
3035

36+
.media-embed-details .setting p,
3137
.media-embed-details .setting a {
3238
color: #a00;
39+
font-size: 10px;
40+
text-transform: uppercase;
3341
}
3442

3543
.media-embed-details .setting a:hover {

src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,14 @@ tinymce.PluginManager.add('wpgallery', function( editor ) {
9797
frame.on( 'close', function () {
9898
frame.detach();
9999
} );
100-
frame.state( 'video-details' ).on( 'update replace add-source select-poster-image', function ( selection ) {
101-
var shortcode = wp.media.video.shortcode( selection );
102-
editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
103-
frame.detach();
104-
} );
100+
frame.state( 'video-details' ).on(
101+
'update replace add-source select-poster-image add-track',
102+
function ( selection ) {
103+
var shortcode = wp.media.video.shortcode( selection );
104+
editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
105+
frame.detach();
106+
}
107+
);
105108
frame.open();
106109
} else if ( editor.dom.hasClass( node, 'wp-audio' ) ) {
107110
frame = wp.media.audio.edit( data );

src/wp-includes/media-template.php

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ class="wp-audio-shortcode"
690690
<label class="setting">
691691
<span>SRC</span>
692692
<input type="text" disabled="disabled" data-setting="src" value="{{ data.model.src }}" />
693-
<a class="remove-setting">{{{ wp.media.view.l10n.audioRemoveSource }}}</a>
693+
<a class="remove-setting">{{{ wp.media.view.l10n.remove }}}</a>
694694
</label>
695695
<# } #>
696696
<?php
@@ -700,7 +700,7 @@ class="wp-audio-shortcode"
700700
<label class="setting">
701701
<span><?php echo strtoupper( $type ) ?></span>
702702
<input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{ data.model.<?php echo $type ?> }}" />
703-
<a class="remove-setting">{{{ wp.media.view.l10n.audioRemoveSource }}}</a>
703+
<a class="remove-setting">{{{ wp.media.view.l10n.remove }}}</a>
704704
</label>
705705
<# } #>
706706
<?php endforeach ?>
@@ -779,21 +779,22 @@ class="wp-video-shortcode{{ isYouTube ? ' youtube-video' : '' }}"
779779
?><# if ( data.model.<?php echo $type ?> ) { #>
780780
<source src="{{ data.model.<?php echo $type ?> }}" type="{{ wp.media.view.settings.embedMimes[ '<?php echo $type ?>' ] }}" />
781781
<# } #>
782-
<?php endforeach;
783-
?></video>
782+
<?php endforeach; ?>
783+
{{{ data.model.content }}}
784+
</video>
784785
<# if ( ! _.isEmpty( data.model.src ) ) { #>
785786
<label class="setting">
786787
<span>SRC</span>
787788
<input type="text" disabled="disabled" data-setting="src" value="{{ data.model.src }}" />
788-
<a class="remove-setting">{{{ wp.media.view.l10n.videoRemoveSource }}}</a>
789+
<a class="remove-setting">{{{ wp.media.view.l10n.remove }}}</a>
789790
</label>
790791
<# } #>
791792
<?php foreach ( $video_types as $type ):
792793
?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) { #>
793794
<label class="setting">
794795
<span><?php echo strtoupper( $type ) ?></span>
795796
<input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{ data.model.<?php echo $type ?> }}" />
796-
<a class="remove-setting">{{{ wp.media.view.l10n.videoRemoveSource }}}</a>
797+
<a class="remove-setting">{{{ wp.media.view.l10n.remove }}}</a>
797798
</label>
798799
<# } #>
799800
<?php endforeach ?>
@@ -802,7 +803,7 @@ class="wp-video-shortcode{{ isYouTube ? ' youtube-video' : '' }}"
802803
<label class="setting">
803804
<span><?php _e( 'Poster Image' ); ?></span>
804805
<input type="text" disabled="disabled" data-setting="poster" value="{{ data.model.poster }}" />
805-
<a class="remove-setting">{{{ wp.media.view.l10n.videoRemovePoster }}}</a>
806+
<a class="remove-setting">{{{ wp.media.view.l10n.remove }}}</a>
806807
</label>
807808
<# } #>
808809
<div class="setting preload">
@@ -824,6 +825,25 @@ class="wp-video-shortcode{{ isYouTube ? ' youtube-video' : '' }}"
824825
<input type="checkbox" data-setting="loop" />
825826
</label>
826827
<div class="clear"></div>
828+
829+
<label class="setting" data-setting="content">
830+
<span><?php _e( 'Tracks (subtitles, captions, descriptions, chapters or metadata)' ); ?></span>
831+
<#
832+
var content = '';
833+
if ( ! _.isEmpty( data.model.content ) ) {
834+
var tracks = jQuery( data.model.content ).filter( 'track' );
835+
_.each( tracks.toArray(), function (track) {
836+
content += track.outerHTML; #>
837+
<p>
838+
<input class="content-track" type="text" value="{{ track.outerHTML }}" />
839+
<a class="remove-setting remove-track">{{{ wp.media.view.l10n.remove }}}</a>
840+
</p>
841+
<# } ); #>
842+
<# } else { #>
843+
<em>There are no associated subtitles.</em>
844+
<# } #>
845+
<textarea class="hidden content-setting">{{ content }}</textarea>
846+
</label>
827847
</div>
828848
</div>
829849
</script>

src/wp-includes/media.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2395,7 +2395,8 @@ function wp_enqueue_media( $args = array() ) {
23952395
'cancel' => __( 'Cancel' ),
23962396
'update' => __( 'Update' ),
23972397
'replace' => __( 'Replace' ),
2398-
'back' => __( 'Back' ),
2398+
'remove' => __( 'Remove' ),
2399+
'back' => __( 'Back' ),
23992400
/* translators: This is a would-be plural string used in the media manager.
24002401
If there is not a word you can use in your language to avoid issues with the
24012402
lack of plural support here, turn it into "selected: %d" then translate it.
@@ -2450,7 +2451,6 @@ function wp_enqueue_media( $args = array() ) {
24502451
'audioDetailsCancel' => __( 'Cancel Edit' ),
24512452
'audioDetailsText' => __( '"Replace Audio" will remove all associated source files when you update. ' .
24522453
'"Add Audio Source" allows you to specify alternate sources for maximum native HTML5 audio playback.' ),
2453-
'audioRemoveSource' => __( 'Remove Audio Source' ),
24542454

24552455
// Edit Video
24562456
'videoDetailsTitle' => __( 'Video Details' ),
@@ -2459,9 +2459,8 @@ function wp_enqueue_media( $args = array() ) {
24592459
'videoDetailsCancel' => __( 'Cancel Edit' ),
24602460
'videoDetailsText' => __( '"Replace Video" will remove all associated source files when you update. ' .
24612461
'"Add Video Source" allows you to specify alternate sources for maximum native HTML5 video playback.' ),
2462-
'videoRemoveSource' => __( 'Remove Video Source' ),
24632462
'videoSelectPosterImageTitle' => _( 'Select Poster Image' ),
2464-
'videoRemovePoster' => __( 'Remove Poster Image' ),
2463+
'videoAddTrackTitle' => __( 'Add Subtitles' ),
24652464

24662465
// Playlist
24672466
'playlistDragInfo' => __( 'Drag and drop to reorder tracks.' ),

0 commit comments

Comments
 (0)