WordPress.org

Make WordPress Core

Changeset 27640


Ignore:
Timestamp:
03/20/2014 01:33:00 PM (7 years ago)
Author:
wonderboymusic
Message:

Unifying media controls and supporting playlists in the editor:

  • Support a caption attribute for audio and video shortcodes
  • In wp.media.audio|video, rename update to shortcode to allow these models to share the same mixins as wp.media.collection subclasses
  • When sending an audio or video shortcode to the editor, create a default caption if the user hasn't entered one. This currently only displays in the editor, not on the front end. Captions aren't tied to a specific attachment here because external sources are supported.
  • In the wp.mce.media mixin, in the edit method, read attr instead of data when attempting to parse the encoded shortcode. data does not automatically update when the attribute changes. This was a blessing to debug.
  • Add wp.mce.media.PlaylistView to support playlist views in TinyMCE
  • Expose WPPlaylistView to global scope and suppress auto-parsing of playlist nodes when in the admin. Allow WPPlaylistView to be passed metadata on creation instead of requiring a JSON blob to be parsed.
  • Remove all of the playlist logic from the wpgallery TinyMCE plugin.
  • In wp_prepare_attachment_for_js() return more data for audio/video so that playlists can have parity in the admin/front end.

See #27320.

Location:
trunk/src/wp-includes
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/js/media-audiovideo.js

    r27631 r27640  
    208208        defaults : {
    209209            id : wp.media.view.settings.post.id,
    210             src      : '',
    211             loop     : false,
     210            src : '',
     211            loop : false,
    212212            autoplay : false,
    213             preload  : 'none'
     213            preload : 'none',
     214            caption : ''
    214215        },
    215216
     
    228229        },
    229230
    230         update : function (model) {
     231        shortcode : function (model) {
    231232            var self = this, content;
    232233
     
    267268            autoplay : false,
    268269            preload : 'metadata',
    269             content : ''
     270            content : '',
     271            caption : ''
    270272        },
    271273
     
    288290        },
    289291
    290         update : function (model) {
     292        shortcode : function (model) {
    291293            var self = this, content;
    292294
     
    11301132            wp.media.mixin.pauseAllPlayers();
    11311133
    1132             data = window.decodeURIComponent( $( node ).data('wpview-text') );
     1134            data = window.decodeURIComponent( $( node ).attr('data-wpview-text') );
    11331135            frame = media.edit( data );
    11341136            frame.on( 'close', function () {
    11351137                frame.detach();
    11361138            } );
    1137             frame.state( self.shortcode + '-details' ).on( 'update', function( selection ) {
    1138                 var shortcode = wp.media[ self.shortcode ].update( selection ).string();
     1139            frame.state( self.state ).on( 'update', function( selection ) {
     1140                var shortcode = wp.media[ self.shortcode ].shortcode( selection ).string();
    11391141                $( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) );
    11401142                wp.mce.views.refreshView( self, shortcode );
     
    12061208    wp.mce.video = _.extend( {}, wp.mce.media, {
    12071209        shortcode: 'video',
     1210        state: 'video-details',
    12081211        View: wp.mce.media.View.extend({
    12091212            className: 'editor-video',
     
    12161219    wp.mce.audio = _.extend( {}, wp.mce.media, {
    12171220        shortcode: 'audio',
     1221        state: 'audio-details',
    12181222        View: wp.mce.media.View.extend({
    12191223            className: 'editor-audio',
     
    12231227
    12241228    wp.mce.views.register( 'audio', wp.mce.audio );
     1229
     1230    wp.mce.media.PlaylistView = wp.mce.View.extend({
     1231        className: 'editor-playlist',
     1232        template:  media.template('editor-playlist'),
     1233
     1234        initialize: function( options ) {
     1235            this.data = {};
     1236            this.attachments = [];
     1237            this.shortcode = options.shortcode;
     1238            _.bindAll( this, 'setPlayer' );
     1239            $(this).on('ready', this.setNode);
     1240        },
     1241
     1242        setNode: function (e, node) {
     1243            this.node = node;
     1244            this.fetch();
     1245        },
     1246
     1247        fetch: function() {
     1248            this.attachments = wp.media[ this.shortcode.tag ].attachments( this.shortcode );
     1249            this.attachments.more().done( this.setPlayer );
     1250        },
     1251
     1252        setPlayer: function () {
     1253            var p,
     1254                html = this.getHtml(),
     1255                t = this.encodedText,
     1256                self = this;
     1257
     1258            this.unsetPlayer();
     1259
     1260            _.each( tinymce.editors, function( editor ) {
     1261                var doc;
     1262                if ( editor.plugins.wpview ) {
     1263                    doc = editor.getDoc();
     1264                    $( doc ).find( '[data-wpview-text="' + t + '"]' ).each(function (i, elem) {
     1265                        var node = $( elem );
     1266                        node.html( html );
     1267                        self.node = elem;
     1268                    });
     1269                }
     1270            }, this );
     1271
     1272            p = new WPPlaylistView({
     1273                el: $( self.node ).find( '.wp-playlist' ).get(0),
     1274                metadata: this.data
     1275            });
     1276
     1277            this.player = p._player;
     1278        },
     1279
     1280        getHtml: function() {
     1281            var data = this.shortcode.attrs.named,
     1282                model = wp.media[ this.shortcode.tag ],
     1283                type = 'playlist' === this.shortcode.tag ? 'audio' : 'video',
     1284                options,
     1285                attachments,
     1286                tracks = [];
     1287
     1288            if ( ! this.attachments.length ) {
     1289                return;
     1290            }
     1291
     1292            _.each( model.defaults, function( value, key ) {
     1293                data[ key ] = model.coerce( data, key );
     1294            });
     1295
     1296            attachments = this.attachments.toJSON();
     1297
     1298            options = {
     1299                type: type,
     1300                style: data.style,
     1301                tracklist: data.tracklist,
     1302                tracknumbers: data.tracknumbers,
     1303                images: data.images,
     1304                artists: data.artists
     1305            };
     1306
     1307            _.each( attachments, function (attachment) {
     1308                var size = {}, track = {
     1309                    src : attachment.url,
     1310                    type : attachment.mime,
     1311                    title : attachment.title,
     1312                    caption : attachment.caption,
     1313                    description : attachment.description,
     1314                    meta : attachment.meta
     1315                };
     1316
     1317                if ( 'video' === type ) {
     1318                    if ( ! options.width ) {
     1319                        options.width = attachment.width;
     1320                        options.height = attachment.height;
     1321                    }
     1322                    size.width = attachment.width;
     1323                    size.height = attachment.height;
     1324                    track.dimensions = {
     1325                        original : size,
     1326                        resized : size
     1327                    };
     1328                } else {
     1329                    options.width = 400;
     1330                }
     1331
     1332                track.image = attachment.image;
     1333                track.thumb = attachment.thumb;
     1334
     1335                tracks.push( track );
     1336            } );
     1337
     1338            options.tracks = tracks;
     1339            this.data = options;
     1340
     1341            return this.template( options );
     1342        }
     1343    });
     1344    _.extend( wp.mce.media.PlaylistView.prototype, wp.media.mixin );
     1345
     1346    wp.mce.playlist = _.extend( {}, wp.mce.media, {
     1347        shortcode: 'playlist',
     1348        state: 'playlist-edit',
     1349        View: wp.mce.media.PlaylistView
     1350    } );
     1351
     1352    wp.mce.views.register( 'playlist', wp.mce.playlist );
     1353
     1354    wp.mce['video-playlist'] = _.extend( {}, wp.mce.media, {
     1355        shortcode: 'video-playlist',
     1356        state: 'video-playlist-edit',
     1357        View: wp.mce.media.PlaylistView
     1358    } );
     1359
     1360    wp.mce.views.register( 'video-playlist', wp.mce['video-playlist'] );
    12251361
    12261362    function init() {
  • trunk/src/wp-includes/js/media-editor.js

    r27608 r27640  
    199199            }
    200200
     201            if ( ! _.isEmpty( attachment.caption ) ) {
     202                shortcode.caption = attachment.caption;
     203            } else if ( attachment.meta && attachment.meta.title ) {
     204                shortcode.caption = '“' + attachment.meta.title + '”';
     205                if ( attachment.meta.album ) {
     206                    shortcode.caption += ' from ' + attachment.meta.album;
     207                }
     208
     209                if ( attachment.meta.artist ) {
     210                    shortcode.caption += ' by ' + attachment.meta.artist;
     211                }
     212            } else if ( ! _.isEmpty( attachment.description ) ) {
     213                shortcode.caption = attachment.description;
     214            } else {
     215                shortcode.caption = attachment.title;
     216            }
     217
    201218            extension = attachment.filename.split('.').pop();
    202219
     
    388405                    _.extend( attrs, attachments[this.tag].toJSON() );
    389406                }
     407
    390408                // Convert all gallery shortcodes to use the `ids` property.
    391409                // Ignore `post__in` and `post__not_in`; the attachments in
  • trunk/src/wp-includes/js/mediaelement/wp-playlist.js

    r27489 r27640  
    99        itemTemplate : wp.template('wp-playlist-item'),
    1010
    11         initialize : function () {
     11        initialize : function (options) {
    1212            var settings = {};
    1313
    14             this.data = $.parseJSON( this.$('script').html() );
     14            this.data = options.metadata || $.parseJSON( this.$('script').html() );
    1515            this.playerNode = this.$( this.data.type );
    1616
     
    3939            settings.success = this.bindPlayer;
    4040
    41             new MediaElementPlayer( this.playerNode.get(0), settings );
     41            this._player = new MediaElementPlayer( this.playerNode.get(0), settings );
    4242        },
    4343
     
    133133
    134134    $(document).ready(function () {
    135         $('.wp-playlist').each(function () {
    136             return new WPPlaylistView({ el: this });
    137         });
     135        if ( ! $( 'body' ).hasClass('wp-admin') ) {
     136            $('.wp-playlist').each(function () {
     137                return new WPPlaylistView({ el: this });
     138            });
     139        }
    138140    });
    139141
     142    window.WPPlaylistView = WPPlaylistView;
     143
    140144}(jQuery, _, Backbone));
  • trunk/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js

    r27615 r27640  
    1212        return '<img src="' + tinymce.Env.transparentSrc + '" class="wp-media mceItem ' + cls + '" ' +
    1313            'data-wp-media="' + data + '" data-mce-resize="false" data-mce-placeholder="1" />';
    14     }
    15 
    16     function replaceCallback( match, type, close ) {
    17         var index;
    18 
    19         if ( close && close.indexOf( '[' + type ) > -1 ) {
    20             index = match.length - close.length;
    21             return html( 'wp-' + type, match.substring( 0, index ) ) + match.substring( index );
    22         }
    23 
    24         return html( 'wp-' + type, match );
    25     }
    26 
    27     function replaceAVShortcodes( content ) {
    28         var testRegex = /\[(video-playlist|playlist)[^\]]*\]/,
    29             replaceRegex = /\[(video-playlist|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/;
    30 
    31         while ( testRegex.test( content ) ) {
    32             content = content.replace( replaceRegex, replaceCallback );
    33         }
    34 
    35         return content;
    3614    }
    3715
     
    7755                frame.detach();
    7856            });
    79         } else if ( editor.dom.hasClass( node, 'wp-playlist' ) && wp.media.playlist ) {
    80             frame = wp.media.playlist.edit( data );
    81 
    82             frame.state('playlist-edit').on( 'update', function( selection ) {
    83                 var shortcode = wp.media.playlist.shortcode( selection ).string();
    84                 editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
    85                 frame.detach();
    86             });
    87         } else if ( editor.dom.hasClass( node, 'wp-video-playlist' ) && wp.media['video-playlist'] ) {
    88             frame = wp.media['video-playlist'].edit( data );
    89 
    90             frame.state('video-playlist-edit').on( 'update', function( selection ) {
    91                 var shortcode = wp.media['video-playlist'].shortcode( selection ).string();
    92                 editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
    93                 frame.detach();
    94             });
    95         } else {
    96             // temp
    97             window.console && window.console.log( 'Edit AV shortcode ' + data );
    9857        }
    9958    }
     
    153112            if ( dom.hasClass( node, 'wp-gallery' ) ) {
    154113                event.name = 'gallery';
    155             } else if ( dom.hasClass( node, 'wp-playlist' ) ) {
    156                 event.name = 'playlist';
    157             } else if ( dom.hasClass( node, 'wp-video-playlist' ) ) {
    158                 event.name = 'video-playlist';
    159114            }
    160115        }
     
    166121            event.content = replaceGalleryShortcodes( event.content );
    167122        }
    168 
    169         event.content = replaceAVShortcodes( event.content );
    170123    });
    171124
  • trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css

    r27628 r27640  
    140140.mce-content-body img.wp-media.wp-gallery {
    141141    background-image: url(images/gallery.png);
    142 }
    143 
    144 .mce-content-body img.wp-media.wp-playlist {
    145     background-image: url("images/playlist-audio.png");
    146 }
    147 
    148 .mce-content-body img.wp-media.wp-video-playlist {
    149     background-image: url("images/playlist-video.png");
    150142}
    151143
     
    300292}
    301293
     294.wpview-type-audio .track-details {
     295    position: absolute;
     296    top: 0;
     297    left: 5px;
     298    width: 85%;
     299    overflow: hidden;
     300    white-space: nowrap;
     301    text-overflow: ellipsis;
     302}
     303
    302304.gallery img[data-mce-selected]:focus {
    303305    outline: none;
  • trunk/src/wp-includes/media-template.php

    r27628 r27640  
    815815                    <span><?php _e( 'Preload' ); ?></span>
    816816                    <div class="button-group button-large" data-setting="preload">
    817                         <button class="button" value="auto"><?php _ex( 'Auto', 'auto preload video' ); ?></button>
     817                        <button class="button" value="auto"><?php _ex( 'Auto', 'auto preload audio' ); ?></button>
    818818                        <button class="button" value="metadata"><?php _e( 'Metadata' ); ?></button>
    819819                        <button class="button active" value="none"><?php _e( 'None' ); ?></button>
     
    830830                    <input type="checkbox" data-setting="loop" />
    831831                </label>
     832
     833                <label class="setting">
     834                    <span><?php _e( 'Caption' ); ?></span>
     835                    <input type="text" data-setting="caption" value="{{ data.model.caption }}" />
     836                </label>
     837
    832838                <div class="clear"></div>
    833839            </div>
     
    902908                    <span><?php _e( 'Preload' ); ?></span>
    903909                    <div class="button-group button-large" data-setting="preload">
    904                         <button class="button" value="auto"><?php _e( 'Auto' ); ?></button>
     910                        <button class="button" value="auto"><?php _ex( 'Auto', 'auto preload video' ); ?></button>
    905911                        <button class="button" value="metadata"><?php _e( 'Metadata' ); ?></button>
    906912                        <button class="button active" value="none"><?php _e( 'None' ); ?></button>
     
    937943                    <textarea class="hidden content-setting">{{ content }}</textarea>
    938944                </label>
     945
     946                <label class="setting">
     947                    <span><?php _e( 'Caption' ); ?></span>
     948                    <input type="text" data-setting="caption" value="{{ data.model.caption }}" />
     949                </label>
    939950            </div>
    940951        </div>
     
    967978            <div class="dashicons dashicons-no-alt remove"></div>
    968979        </div>
     980        <# if ( ! _.isEmpty( data.model.caption ) ) { #>
     981        <div class="track-details">{{{ data.model.caption }}}</div>
     982        <# } #>
    969983        <?php wp_underscore_audio_template() ?>
    970984    </script>
     
    975989            <div class="dashicons dashicons-no-alt remove"></div>
    976990        </div>
     991        <# if ( ! _.isEmpty( data.model.caption ) ) { #>
     992        <div class="track-details">{{{ data.model.caption }}}</div>
     993        <# } #>
    977994        <?php wp_underscore_video_template() ?>
     995    </script>
     996
     997    <?php wp_underscore_playlist_templates() ?>
     998
     999    <script type="text/html" id="tmpl-editor-playlist">
     1000        <div class="toolbar">
     1001            <div class="dashicons dashicons-edit edit"></div>
     1002            <div class="dashicons dashicons-no-alt remove"></div>
     1003        </div>
     1004        <div class="wp-playlist wp-{{ data.type }}-playlist wp-playlist-{{ data.style }}">
     1005            <# if ( 'audio' === data.type ){ #>
     1006            <div class="wp-playlist-current-item"></div>
     1007            <# } #>
     1008            <{{ data.type }} controls="controls" preload="none" <#
     1009                if ( data.width ) { #> width="{{ data.width }}"<# }
     1010                #><# if ( data.height ) { #> height="{{ data.height }}"<# } #>></{{ data.type }}>
     1011            <div class="wp-playlist-next"></div>
     1012            <div class="wp-playlist-prev"></div>
     1013        </div>
    9781014    </script>
    9791015
  • trunk/src/wp-includes/media.php

    r27625 r27640  
    10001000
    10011001/**
    1002  * Output and enqueue default scripts and styles for playlists.
     1002 * Output the templates used by playlists
    10031003 *
    10041004 * @since 3.9.0
    1005  *
    1006  * @param string $type Type of playlist: "audio" or "video."
    1007  */
    1008 function wp_playlist_scripts( $type ) {
    1009     wp_enqueue_style( 'wp-mediaelement' );
    1010     wp_enqueue_script( 'wp-playlist' );
     1005 */
     1006function wp_underscore_playlist_templates() {
    10111007?>
    1012 <!--[if lt IE 9]><script>document.createElement('<?php echo esc_js( $type ) ?>');</script><![endif]-->
    10131008<script type="text/html" id="tmpl-wp-playlist-current-item">
    10141009    <# if ( data.image ) { #>
     
    10461041<?php
    10471042}
     1043
     1044/**
     1045 * Output and enqueue default scripts and styles for playlists.
     1046 *
     1047 * @since 3.9.0
     1048 *
     1049 * @param string $type Type of playlist: "audio" or "video."
     1050 */
     1051function wp_playlist_scripts( $type ) {
     1052    wp_enqueue_style( 'wp-mediaelement' );
     1053    wp_enqueue_script( 'wp-playlist' );
     1054?>
     1055<!--[if lt IE 9]><script>document.createElement('<?php echo esc_js( $type ) ?>');</script><![endif]-->
     1056<?php
     1057    wp_underscore_playlist_templates();
     1058}
    10481059add_action( 'wp_playlist_scripts', 'wp_playlist_scripts' );
    10491060
     
    13911402    $default_types = wp_get_audio_extensions();
    13921403    $defaults_atts = array(
     1404        'caption'  => '',
    13931405        'src'      => '',
    13941406        'loop'     => '',
     
    15501562    $default_types = wp_get_video_extensions();
    15511563    $defaults_atts = array(
     1564        'caption'  => '',
    15521565        'src'      => '',
    15531566        'poster'   => '',
     
    23332346        if ( isset( $meta['length_formatted'] ) )
    23342347            $response['fileLength'] = $meta['length_formatted'];
     2348
     2349        $response['meta'] = array();
     2350        $keys = array( 'title', 'artist', 'band', 'album', 'genre', 'year', 'length', 'length_formatted' );
     2351        foreach ( $keys as $key ) {
     2352            if ( ! empty( $meta[ $key ] ) ) {
     2353                $response['meta'][ $key ] = $meta[ $key ];
     2354            }
     2355        }
     2356
     2357        $id = get_post_thumbnail_id( $attachment->ID );
     2358        if ( ! empty( $id ) ) {
     2359            list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' );
     2360            $response['image'] = compact( 'src', 'width', 'height' );
     2361            list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' );
     2362            $response['thumb'] = compact( 'src', 'width', 'height' );
     2363        }
    23352364    }
    23362365
  • trunk/src/wp-includes/script-loader.php

    r27625 r27640  
    397397    $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement' ), false, 1 );
    398398    $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
    399     $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor', 'mce-view' ), false, 1 );
     399    $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor', 'mce-view', 'wp-playlist' ), false, 1 );
    400400    $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 );
    401401
Note: See TracChangeset for help on using the changeset viewer.