Make WordPress Core

Ticket #26631: 26631.8.diff

File 26631.8.diff, 62.6 KB (added by wonderboymusic, 10 years ago)
  • src/wp-admin/edit-form-advanced.php

     
    2424$user_ID = isset($user_ID) ? (int) $user_ID : 0;
    2525$action = isset($action) ? $action : '';
    2626
    27 if ( post_type_supports($post_type, 'editor') || post_type_supports($post_type, 'thumbnail') ) {
     27$media_type = false;
     28if ( 'attachment' && $post_ID ) {
     29        $post = get_post( $post_ID );
     30        $media_type = post_supports_thumbnails( $post );
     31}
     32
     33if ( post_type_supports( $post_type, 'editor' ) || post_type_supports( $post_type, 'thumbnail' ) || $media_type ) {
    2834        add_thickbox();
    2935        wp_enqueue_media( array( 'post' => $post_ID ) );
    3036}
  • src/wp-content/themes/twentyfourteen/functions.php

     
    111111                'max_posts' => 6,
    112112        ) );
    113113
     114        add_post_type_support( 'attachment:audio', 'thumbnail' );
     115        add_post_type_support( 'attachment:video', 'thumbnail' );
     116        add_theme_support( 'post-thumbnails', array( 'post', 'attachment:audio', 'attachment:video' ) );
     117
    114118        // This theme uses its own gallery styles.
    115119        add_filter( 'use_default_gallery_style', '__return_false' );
    116120}
  • src/wp-includes/css/media-views.css

     
    592592        box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
    593593}
    594594
    595 .media-frame .media-toolbar .add-to-gallery {
    596         display: none;
    597 }
    598 
    599595.media-frame-title h1 {
    600596        padding: 0 16px;
    601597        font-size: 22px;
     
    14241420        margin: 1.4em 0 0.4em;
    14251421}
    14261422
    1427 .gallery-settings {
     1423.collection-settings {
    14281424        overflow: hidden;
    14291425}
    14301426
     
    18831879                border-top: none;
    18841880        }
    18851881
    1886         .gallery-settings h3 {
     1882        .collection-settings h3 {
    18871883                margin-top: 45px;
    18881884        }
    18891885
  • src/wp-includes/js/media-editor.js

     
    88         *
    99         * @static
    1010         */
    11         var workflows = {};
     11        var workflows = {}, cache = {};
    1212
    1313        /**
    1414         * wp.media.string
     
    273273                        return html;
    274274                }
    275275        };
    276 
    277276        /**
    278          * wp.media.gallery
     277         * wp.media.collection
    279278         * @namespace
    280279         */
    281         wp.media.gallery = (function() {
    282                 /**
    283                  *
    284                  * @static
    285                  * @type object
    286                  */
    287                 var galleries = {};
    288 
    289                 return {
     280        wp.media.collection = {
     281                attachments : function ( prop, type ) {
    290282                        /**
    291                          * Default gallery properties
    292                          *
    293                          * @global wp.media.view.settings
    294                          * @readonly
    295                          */
    296                         defaults: {
    297                                 order:      'ASC',
    298                                 id:         wp.media.view.settings.post.id,
    299                                 itemtag:    'dl',
    300                                 icontag:    'dt',
    301                                 captiontag: 'dd',
    302                                 columns:    '3',
    303                                 link:       'post',
    304                                 size:       'thumbnail',
    305                                 orderby:    'menu_order ID'
    306                         },
    307                         /**
    308283                         * Retrieve attachments based on the properties of the passed shortcode
    309284                         *
    310285                         * @global wp.media.query
    311286                         *
    312287                         * @param {wp.shortcode} shortcode An instance of wp.shortcode().
    313288                         * @returns {wp.media.model.Attachments} A Backbone.Collection containing
    314                          *      the images belonging to a gallery. The 'gallery' prop is a Backbone.Model
    315                          *      containing the 'props' for the gallery.
     289                         *      the media items belonging to a collection.
     290                         *      The 'prop' specified by the passed prop is a Backbone.Model
     291                         *                      containing the 'props' for the gallery.
    316292                         */
    317                         attachments: function( shortcode ) {
    318                                 var shortcodeString = shortcode.string(),
    319                                         result = galleries[ shortcodeString ],
    320                                         attrs, args, query, others;
     293                        return function( shortcode ) {
     294                                var shortcodeString = shortcode.string(),
     295                                        result = cache[ shortcodeString ],
     296                                        attrs, args, query, others;
    321297
    322                                 delete galleries[ shortcodeString ];
     298                                delete cache[ shortcodeString ];
    323299
    324                                 if ( result ) {
    325                                         return result;
     300                                if ( result ) {
     301                                        return result;
    326302                                }
    327303
    328                                 // Fill the default shortcode attributes.
    329                                 attrs = _.defaults( shortcode.attrs.named, wp.media.gallery.defaults );
    330                                 args  = _.pick( attrs, 'orderby', 'order' );
     304                                // Fill the default shortcode attributes.
     305                                attrs = _.defaults( shortcode.attrs.named, this.defaults );
     306                                args  = _.pick( attrs, 'orderby', 'order' );
    331307
    332                                 args.type    = 'image';
    333                                 args.perPage = -1;
     308                                args.type = type;
     309                                args.perPage = -1;
    334310
    335                                 // Mark the `orderby` override attribute.
    336                                 if( undefined !== attrs.orderby ) {
    337                                         attrs._orderByField = attrs.orderby;
     311                                // Mark the `orderby` override attribute.
     312                                if ( undefined !== attrs.orderby ) {
     313                                        attrs._orderByField = attrs.orderby;
    338314                                }
     315
    339316                                if ( 'rand' === attrs.orderby ) {
    340317                                        attrs._orderbyRandom = true;
    341318                                }
    342319
     320                                if ( -1 !== jQuery.inArray( prop, ['playlist', 'video-playlist'] ) ) {
     321                                        _.each(['tracknumbers', 'tracklist', 'images'], function (setting) {
     322                                                if ( 'undefined' === typeof attrs[setting] ) {
     323                                                        attrs['_' + setting] = wp.media[ prop ].defaults[ setting ];
     324                                                } else if ( 'true' === attrs[setting] || true === attrs[setting] ) {
     325                                                        attrs['_' + setting] = true;
     326                                                }
     327                                        });
     328                                }
     329
    343330                                // Map the `orderby` attribute to the corresponding model property.
    344331                                if ( ! attrs.orderby || /^menu_order(?: ID)?$/i.test( attrs.orderby ) ) {
    345332                                        args.orderby = 'menuOrder';
     
    365352                                others = _.omit( attrs, 'id', 'ids', 'include', 'exclude', 'orderby', 'order' );
    366353
    367354                                query = wp.media.query( args );
    368                                 query.gallery = new Backbone.Model( others );
     355                                query[ prop ] = new Backbone.Model( others );
    369356                                return query;
    370                         },
    371                         /**
    372                          * Triggered when clicking 'Insert Gallery' or 'Update Gallery'
    373                          *
    374                          * @global wp.shortcode
    375                          * @global wp.media.model.Attachments
    376                          *
    377                          * @param {wp.media.model.Attachments} attachments A Backbone.Collection containing
    378                          *      the images belonging to a gallery. The 'gallery' prop is a Backbone.Model
    379                          *      containing the 'props' for the gallery.
    380                          * @returns {wp.shortcode}
    381                          */
    382                         shortcode: function( attachments ) {
    383                                 var props = attachments.props.toJSON(),
    384                                         attrs = _.pick( props, 'orderby', 'order' ),
    385                                         shortcode, clone;
     357                        };
     358                },
    386359
    387                                 if ( attachments.gallery ) {
    388                                         _.extend( attrs, attachments.gallery.toJSON() );
    389                                 }
     360                shortcodeAttrs : function ( prop, attachments ) {
     361                        var props = attachments.props.toJSON(),
     362                                attrs = _.pick( props, 'orderby', 'order', 'style' );
    390363
    391                                 // Convert all gallery shortcodes to use the `ids` property.
    392                                 // Ignore `post__in` and `post__not_in`; the attachments in
    393                                 // the collection will already reflect those properties.
    394                                 attrs.ids = attachments.pluck('id');
     364                        if ( attachments[ prop ] ) {
     365                                _.extend( attrs, attachments[ prop ].toJSON() );
     366                        }
    395367
    396                                 // Copy the `uploadedTo` post ID.
    397                                 if ( props.uploadedTo ) {
    398                                         attrs.id = props.uploadedTo;
    399                                 }
     368                        // Convert all collection shortcodes to use the `ids` property.
     369                        // Ignore `post__in` and `post__not_in`; the attachments in
     370                        // the collection will already reflect those properties.
     371                        attrs.ids = attachments.pluck('id');
    400372
    401                                 // Check if the gallery is randomly ordered.
    402                                 delete attrs.orderby;
     373                        // Copy the `uploadedTo` post ID.
     374                        if ( props.uploadedTo ) {
     375                                attrs.id = props.uploadedTo;
     376                        }
    403377
    404                                 if ( attrs._orderbyRandom ) {
    405                                         attrs.orderby = 'rand';
    406                                 } else if ( attrs._orderByField && attrs._orderByField != 'rand' ) {
    407                                         attrs.orderby = attrs._orderByField;
    408                                 }
     378                        // Check if the collection is randomly ordered.
     379                        delete attrs.orderby;
    409380
    410                                 delete attrs._orderbyRandom;
    411                                 delete attrs._orderByField;
     381                        if ( attrs._orderbyRandom ) {
     382                                attrs.orderby = 'rand';
     383                        } else if ( attrs._orderByField && attrs._orderByField != 'rand' ) {
     384                                attrs.orderby = attrs._orderByField;
     385                        }
    412386
    413                                 // If the `ids` attribute is set and `orderby` attribute
    414                                 // is the default value, clear it for cleaner output.
    415                                 if ( attrs.ids && 'post__in' === attrs.orderby ) {
    416                                         delete attrs.orderby;
    417                                 }
     387                        delete attrs._orderbyRandom;
     388                        delete attrs._orderByField;
    418389
    419                                 // Remove default attributes from the shortcode.
    420                                 _.each( wp.media.gallery.defaults, function( value, key ) {
    421                                         if ( value === attrs[ key ] )
    422                                                 delete attrs[ key ];
    423                                 });
     390                        // If the `ids` attribute is set and `orderby` attribute
     391                        // is the default value, clear it for cleaner output.
     392                        if ( attrs.ids && 'post__in' === attrs.orderby ) {
     393                                delete attrs.orderby;
     394                        }
    424395
    425                                 shortcode = new wp.shortcode({
    426                                         tag:    'gallery',
    427                                         attrs:  attrs,
    428                                         type:   'single'
     396                        if ( -1 !== jQuery.inArray( prop, ['playlist', 'video-playlist'] ) ) {
     397                                _.each(['tracknumbers', 'tracklist', 'images'], function (setting) {
     398                                        if ( attrs['_' + setting] ) {
     399                                                attrs[setting] = true;
     400                                        } else {
     401                                                attrs[setting] = false;
     402                                        }
     403                                        delete attrs['_' + setting];
    429404                                });
     405                        }
    430406
    431                                 // Use a cloned version of the gallery.
    432                                 clone = new wp.media.model.Attachments( attachments.models, {
    433                                         props: props
    434                                 });
    435                                 clone.gallery = attachments.gallery;
    436                                 galleries[ shortcode.string() ] = clone;
     407                        // Remove default attributes from the shortcode.
     408                        _.each( this.defaults, function( value, key ) {
     409                                if ( value === attrs[ key ] ) {
     410                                        delete attrs[ key ];
     411                                }
     412                        });
     413                        return attrs;
     414                },
    437415
    438                                 return shortcode;
    439                         },
    440                         /**
    441                          * Triggered when double-clicking a Gallery shortcode placeholder
    442                          *   in the editor
    443                          *
    444                          * @global wp.shortcode
    445                          * @global wp.media.model.Selection
    446                          * @global wp.media.view.l10n
    447                          *
    448                          * @param {string} content Content that is searched for possible
    449                          *    shortcode markup matching the passed tag name,
    450                          *
    451                          * @this wp.media.gallery
    452                          *
    453                          * @returns {wp.media.view.MediaFrame.Select} A media workflow.
    454                          */
    455                         edit: function( content ) {
    456                                 var shortcode = wp.shortcode.next( 'gallery', content ),
    457                                         defaultPostId = wp.media.gallery.defaults.id,
    458                                         attachments, selection;
     416                editSelection : function ( prop, shortcode ) {
     417                        var defaultPostId = wp.media[ prop ].defaults.id,
     418                                attachments, selection;
    459419
    460                                 // Bail if we didn't match the shortcode or all of the content.
    461                                 if ( ! shortcode || shortcode.content !== content ) {
    462                                         return;
    463                                 }
     420                        // Ignore the rest of the match object.
     421                        shortcode = shortcode.shortcode;
    464422
    465                                 // Ignore the rest of the match object.
    466                                 shortcode = shortcode.shortcode;
     423                        if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) ) {
     424                                shortcode.set( 'id', defaultPostId );
     425                        }
    467426
    468                                 if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) ) {
    469                                         shortcode.set( 'id', defaultPostId );
    470                                 }
     427                        attachments = wp.media[ prop ].attachments( shortcode );
    471428
    472                                 attachments = wp.media.gallery.attachments( shortcode );
     429                        selection = new wp.media.model.Selection( attachments.models, {
     430                                props:    attachments.props.toJSON(),
     431                                multiple: true
     432                        });
    473433
    474                                 selection = new wp.media.model.Selection( attachments.models, {
    475                                         props:    attachments.props.toJSON(),
    476                                         multiple: true
    477                                 });
     434                        selection[ prop ] = attachments[ prop ];
    478435
    479                                 selection.gallery = attachments.gallery;
     436                        // Fetch the query's attachments, and then break ties from the
     437                        // query to allow for sorting.
     438                        selection.more().done( function() {
     439                                // Break ties with the query.
     440                                selection.props.set({ query: false });
     441                                selection.unmirror();
     442                                selection.props.unset('orderby');
     443                        });
    480444
    481                                 // Fetch the query's attachments, and then break ties from the
    482                                 // query to allow for sorting.
    483                                 selection.more().done( function() {
    484                                         // Break ties with the query.
    485                                         selection.props.set({ query: false });
    486                                         selection.unmirror();
    487                                         selection.props.unset('orderby');
    488                                 });
     445                        return selection;
     446                },
    489447
    490                                 // Destroy the previous gallery frame.
    491                                 if ( this.frame ) {
    492                                         this.frame.dispose();
    493                                 }
     448                /**
     449                 *
     450                 * @param {string} prop The shortcode slug
     451                 * @param {type} attachments
     452                 * @param {wp.media.shortcode} shortcode
     453                 * @returns {wp.media.shortcode}
     454                 */
     455                cacheShortcode : function ( prop, attachments, shortcode ) {
     456                        // Use a cloned version of the playlist.
     457                        var clone = new wp.media.model.Attachments( attachments.models, {
     458                                props: attachments.props.toJSON()
     459                        });
     460                        clone[ prop ] = attachments[ prop ];
     461                        cache[ shortcode.string() ] = clone;
    494462
    495                                 // Store the current gallery frame.
    496                                 this.frame = wp.media({
    497                                         frame:     'post',
    498                                         state:     'gallery-edit',
    499                                         title:     wp.media.view.l10n.editGalleryTitle,
    500                                         editing:   true,
    501                                         multiple:  true,
    502                                         selection: selection
    503                                 }).open();
     463                        return shortcode;
     464                },
    504465
    505                                 return this.frame;
     466                getEditFrame : function ( args ) {
     467                        // Destroy the previous gallery frame.
     468                        if ( this.frame ) {
     469                                this.frame.dispose();
    506470                        }
    507                 };
    508         }());
    509471
     472                        // Store the current gallery frame.
     473                        this.frame = wp.media( _.extend( {
     474                                frame:     'post',
     475                                editing:   true,
     476                                multiple:  true,
     477                        }, args ) ).open();
     478
     479                        return this.frame;
     480                },
     481
     482                instance : function ( prop, args ) {
     483                        return {
     484                                attachments: this.attachments( prop, args.type ),
     485                                /**
     486                                 * Triggered when clicking 'Insert {label}' or 'Update {label}'
     487                                 *
     488                                 * @global wp.shortcode
     489                                 * @global wp.media.model.Attachments
     490                                 *
     491                                 * @param {wp.media.model.Attachments} attachments A Backbone.Collection containing
     492                                 *      the media items belonging to a collection.
     493                                 *      The 'prop' specified by the passed prop is a Backbone.Model
     494                                 *                      containing the 'props' for the gallery.
     495                                 * @returns {wp.shortcode}
     496                                 */
     497                                shortcode: function( attachments ) {
     498                                        var shortcode = new wp.shortcode({
     499                                                tag: prop,
     500                                                attrs: wp.media.collection.shortcodeAttrs( prop, attachments ),
     501                                                type: 'single'
     502                                        });
     503
     504                                        return wp.media.collection.cacheShortcode( prop, attachments, shortcode );
     505                                },
     506                                /**
     507                                 * Triggered when double-clicking a collection shortcode placeholder
     508                                 *   in the editor
     509                                 *
     510                                 * @global wp.shortcode
     511                                 * @global wp.media.model.Selection
     512                                 * @global wp.media.view.l10n
     513                                 *
     514                                 * @param {string} content Content that is searched for possible
     515                                 *    shortcode markup matching the passed tag name,
     516                                 *
     517                                 * @this wp.media.{prop}
     518                                 *
     519                                 * @returns {wp.media.view.MediaFrame.Select} A media workflow.
     520                                 */
     521                                edit: function( content ) {
     522                                        var shortcode = wp.shortcode.next( prop, content );
     523
     524                                        // Bail if we didn't match the shortcode or all of the content.
     525                                        if ( ! shortcode || shortcode.content !== content ) {
     526                                                return;
     527                                        }
     528
     529                                        return wp.media.collection.getEditFrame( {
     530                                                title: args.title,
     531                                                state: prop + '-edit',
     532                                                selection:      wp.media.collection.editSelection( prop, shortcode )
     533                                        } );
     534                                }
     535                        };
     536                }
     537        };
     538
     539        wp.media.gallery = (function() {
     540                var gallery = {
     541                        defaults : {
     542                                itemtag: 'dl',
     543                                icontag: 'dt',
     544                                captiontag: 'dd',
     545                                columns: '3',
     546                                link: 'post',
     547                                size: 'thumbnail',
     548                                order: 'ASC',
     549                                id: wp.media.view.settings.post.id,
     550                                orderby : 'menu_order ID'
     551                        }
     552                };
     553
     554                return _.extend(gallery, wp.media.collection.instance( 'gallery', {
     555                        type : 'image',
     556                        title : wp.media.view.l10n.editGalleryTitle
     557                }));
     558        }());
     559
     560        wp.media.playlist = (function() {
     561                var playlist = {
     562                        defaults : {
     563                                id: wp.media.view.settings.post.id,
     564                                style: 'light',
     565                                tracklist: true,
     566                                tracknumbers: true,
     567                                images: true
     568                        }
     569                };
     570
     571                return _.extend(playlist, wp.media.collection.instance( 'playlist', {
     572                        type : 'audio',
     573                        title : wp.media.view.l10n.editPlaylistTitle
     574                }));
     575        }());
     576
     577        wp.media['video-playlist'] = (function() {
     578                var playlist = {
     579                        defaults : {
     580                                id: wp.media.view.settings.post.id,
     581                                style: 'light',
     582                                tracklist: false,
     583                                tracknumbers: false,
     584                                images: false
     585                        }
     586                };
     587
     588                return _.extend(playlist, wp.media.collection.instance( 'video-playlist', {
     589                        type : 'video',
     590                        title : wp.media.view.l10n.editVideoPlaylistTitle
     591                }));
     592        }());
     593
    510594        /**
    511595         * wp.media.featuredImage
    512596         * @namespace
     
    725809                                this.insert( wp.media.gallery.shortcode( selection ).string() );
    726810                        }, this );
    727811
     812                        workflow.state('playlist-edit').on( 'update', function( selection ) {
     813                                this.insert( wp.media.playlist.shortcode( selection ).string() );
     814                        }, this );
     815
     816                        workflow.state('video-playlist-edit').on( 'update', function( selection ) {
     817                                this.insert( wp.media['video-playlist'].shortcode( selection ).string() );
     818                        }, this );
     819
    728820                        workflow.state('embed').on( 'select', function() {
    729821                                /**
    730822                                 * @this wp.media.editor
     
    9641056                                if ( elem.hasClass( 'gallery' ) ) {
    9651057                                        options.state = 'gallery';
    9661058                                        options.title = wp.media.view.l10n.createGalleryTitle;
     1059                                } else if ( elem.hasClass( 'playlist' ) ) {
     1060                                        options.state = 'playlist';
     1061                                        options.title = wp.media.view.l10n.createPlaylistTitle;
     1062                                } else if ( elem.hasClass( 'video-playlist' ) ) {
     1063                                        options.state = 'video-playlist';
     1064                                        options.title = wp.media.view.l10n.createVideoPlaylistTitle;
    9671065                                }
    9681066
    9691067                                wp.media.editor.open( editor, options );
  • src/wp-includes/js/media-views.js

     
    760760        });
    761761
    762762        /**
    763          * wp.media.controller.GalleryEdit
    764          *
    765          * @constructor
    766          * @augments wp.media.controller.Library
    767          * @augments wp.media.controller.State
    768          * @augments Backbone.Model
    769          */
    770         media.controller.GalleryEdit = media.controller.Library.extend({
    771                 defaults: {
    772                         id:         'gallery-edit',
    773                         multiple:   false,
    774                         describe:   true,
    775                         edge:       199,
    776                         editing:    false,
    777                         sortable:   true,
    778                         searchable: false,
    779                         toolbar:    'gallery-edit',
    780                         content:    'browse',
    781                         title:      l10n.editGalleryTitle,
    782                         priority:   60,
    783                         dragInfo:   true,
    784 
    785                         // Don't sync the selection, as the Edit Gallery library
    786                         // *is* the selection.
    787                         syncSelection: false
    788                 },
    789 
    790                 initialize: function() {
    791                         // If we haven't been provided a `library`, create a `Selection`.
    792                         if ( ! this.get('library') ) {
    793                                 this.set( 'library', new media.model.Selection() );
    794                         }
    795 
    796                         // The single `Attachment` view to be used in the `Attachments` view.
    797                         if ( ! this.get('AttachmentView') ) {
    798                                 this.set( 'AttachmentView', media.view.Attachment.EditLibrary );
    799                         }
    800 
    801                         media.controller.Library.prototype.initialize.apply( this, arguments );
    802                 },
    803 
    804                 activate: function() {
    805                         var library = this.get('library');
    806 
    807                         // Limit the library to images only.
    808                         library.props.set( 'type', 'image' );
    809 
    810                         // Watch for uploaded attachments.
    811                         this.get('library').observe( wp.Uploader.queue );
    812 
    813                         this.frame.on( 'content:render:browse', this.gallerySettings, this );
    814 
    815                         media.controller.Library.prototype.activate.apply( this, arguments );
    816                 },
    817 
    818                 deactivate: function() {
    819                         // Stop watching for uploaded attachments.
    820                         this.get('library').unobserve( wp.Uploader.queue );
    821 
    822                         this.frame.off( 'content:render:browse', this.gallerySettings, this );
    823 
    824                         media.controller.Library.prototype.deactivate.apply( this, arguments );
    825                 },
    826 
    827                 /**
    828                  * @param {Object} browser
    829                  */
    830                 gallerySettings: function( browser ) {
    831                         var library = this.get('library');
    832 
    833                         if ( ! library || ! browser ) {
    834                                 return;
    835                         }
    836 
    837                         library.gallery = library.gallery || new Backbone.Model();
    838 
    839                         browser.sidebar.set({
    840                                 gallery: new media.view.Settings.Gallery({
    841                                         controller: this,
    842                                         model:      library.gallery,
    843                                         priority:   40
    844                                 })
    845                         });
    846 
    847                         browser.toolbar.set( 'reverse', {
    848                                 text:     l10n.reverseOrder,
    849                                 priority: 80,
    850 
    851                                 click: function() {
    852                                         library.reset( library.toArray().reverse() );
    853                                 }
    854                         });
    855                 }
    856         });
    857 
    858         /**
    859          * wp.media.controller.GalleryAdd
    860          *
    861          * @constructor
    862          * @augments wp.media.controller.Library
    863          * @augments wp.media.controller.State
    864          * @augments Backbone.Model
    865          */
    866         media.controller.GalleryAdd = media.controller.Library.extend({
    867                 defaults: _.defaults({
    868                         id:           'gallery-library',
    869                         filterable:   'uploaded',
    870                         multiple:     'add',
    871                         menu:         'gallery',
    872                         toolbar:      'gallery-add',
    873                         title:        l10n.addToGalleryTitle,
    874                         priority:     100,
    875 
    876                         // Don't sync the selection, as the Edit Gallery library
    877                         // *is* the selection.
    878                         syncSelection: false
    879                 }, media.controller.Library.prototype.defaults ),
    880 
    881                 /**
    882                  * If we haven't been provided a `library`, create a `Selection`.
    883                  */
    884                 initialize: function() {
    885                         if ( ! this.get('library') ) {
    886                                 this.set( 'library', media.query({ type: 'image' }) );
    887                         }
    888                         media.controller.Library.prototype.initialize.apply( this, arguments );
    889                 },
    890 
    891                 activate: function() {
    892                         var library = this.get('library'),
    893                                 edit    = this.frame.state('gallery-edit').get('library');
    894 
    895                         if ( this.editLibrary && this.editLibrary !== edit ) {
    896                                 library.unobserve( this.editLibrary );
    897                         }
    898 
    899                         // Accepts attachments that exist in the original library and
    900                         // that do not exist in gallery's library.
    901                         library.validator = function( attachment ) {
    902                                 return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) &&
    903                                         media.model.Selection.prototype.validator.apply( this, arguments );
    904                         };
    905 
    906                         // Reset the library to ensure that all attachments are re-added
    907                         // to the collection. Do so silently, as calling `observe` will
    908                         // trigger the `reset` event.
    909                         library.reset( library.mirroring.models, { silent: true });
    910                         library.observe( edit );
    911                         this.editLibrary = edit;
    912 
    913                         media.controller.Library.prototype.activate.apply( this, arguments );
    914                 }
    915         });
    916 
    917         /**
    918763         * wp.media.controller.FeaturedImage
    919764         *
    920765         * @constructor
     
    993838                }
    994839        });
    995840
     841        media.controller.CollectionEdit = function ( prop, args ) {
     842                return media.controller.Library.extend({
     843                        defaults : _.defaults(args.defaults || {}, {
     844                                id:         prop + '-edit',
     845                                toolbar:    prop + '-edit',
     846                                multiple:   false,
     847                                describe:   true,
     848                                edge:       199,
     849                                editing:    false,
     850                                sortable:   true,
     851                                searchable: false,
     852                                content:    'browse',
     853                                priority:   60,
     854                                dragInfo:   true,
     855
     856                                // Don't sync the selection, as the Edit {Collection} library
     857                                // *is* the selection.
     858                                syncSelection: false
     859                        }),
     860
     861                        initialize: function() {
     862                                // If we haven't been provided a `library`, create a `Selection`.
     863                                if ( ! this.get('library') ) {
     864                                        this.set( 'library', new media.model.Selection() );
     865                                }
     866                                // The single `Attachment` view to be used in the `Attachments` view.
     867                                if ( ! this.get('AttachmentView') ) {
     868                                        this.set( 'AttachmentView', media.view.Attachment.EditLibrary );
     869                                }
     870                                media.controller.Library.prototype.initialize.apply( this, arguments );
     871                        },
     872
     873                        activate: function() {
     874                                var library = this.get('library');
     875
     876                                // Limit the library to images only.
     877                                library.props.set( 'type', args.type );
     878
     879                                // Watch for uploaded attachments.
     880                                this.get('library').observe( wp.Uploader.queue );
     881
     882                                this.frame.on( 'content:render:browse', this.settings, this );
     883
     884                                media.controller.Library.prototype.activate.apply( this, arguments );
     885                        },
     886
     887                        deactivate: function() {
     888                                // Stop watching for uploaded attachments.
     889                                this.get('library').unobserve( wp.Uploader.queue );
     890
     891                                this.frame.off( 'content:render:browse', this.settings, this );
     892
     893                                media.controller.Library.prototype.deactivate.apply( this, arguments );
     894                        },
     895
     896                        settings: function( browser ) {
     897                                var library = this.get('library'), obj = {};
     898
     899                                if ( ! library || ! browser ) {
     900                                        return;
     901                                }
     902
     903                                library[ prop ] = library[ prop ] || new Backbone.Model();
     904
     905                                obj[ prop ] = new media.view.Settings[ args.settings ]({
     906                                        controller: this,
     907                                        model:      library[ prop ],
     908                                        priority:   40
     909                                });
     910
     911                                browser.sidebar.set( obj );
     912
     913                                if ( args.dragInfoText ) {
     914                                        browser.toolbar.set( 'dragInfo', new media.View({
     915                                                el: $( '<div class="instructions">' + args.dragInfoText + '</div>' )[0],
     916                                                priority: -40
     917                                        }) );
     918                                }
     919
     920                                browser.toolbar.set( 'reverse', {
     921                                        text:     l10n.reverseOrder,
     922                                        priority: 80,
     923
     924                                        click: function() {
     925                                                library.reset( library.toArray().reverse() );
     926                                        }
     927                                });
     928                        }
     929                });
     930        };
     931
     932        media.controller.CollectionAdd = function ( prop, args ) {
     933                return media.controller.Library.extend({
     934                        defaults: _.defaults({
     935                                id:           prop + '-library',
     936                                filterable:   'uploaded',
     937                                multiple:     'add',
     938                                menu:         prop,
     939                                toolbar:      prop + '-add',
     940                                priority:     100,
     941                                syncSelection: false
     942                        }, args.defaults || {}, media.controller.Library.prototype.defaults ),
     943                        initialize: function() {
     944                                // If we haven't been provided a `library`, create a `Selection`.
     945                                if ( ! this.get('library') ) {
     946                                        this.set( 'library', media.query({ type: args.type }) );
     947                                }
     948                                media.controller.Library.prototype.initialize.apply( this, arguments );
     949                        },
     950
     951                        activate: function() {
     952                                var library = this.get('library'),
     953                                        edit    = this.frame.state(prop + '-edit').get('library');
     954
     955                                if ( this.editLibrary && this.editLibrary !== edit ) {
     956                                        library.unobserve( this.editLibrary );
     957                                }
     958
     959                                // Accepts attachments that exist in the original library and
     960                                // that do not exist in gallery's library.
     961                                library.validator = function( attachment ) {
     962                                        return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && media.model.Selection.prototype.validator.apply( this, arguments );
     963                                };
     964
     965                                // Reset the library to ensure that all attachments are re-added
     966                                // to the collection. Do so silently, as calling `observe` will
     967                                // trigger the `reset` event.
     968                                library.reset( library.mirroring.models, { silent: true });
     969                                library.observe( edit );
     970                                this.editLibrary = edit;
     971
     972                                media.controller.Library.prototype.activate.apply( this, arguments );
     973                        }
     974                });
     975        };
     976
     977        // wp.media.controller.GalleryEdit
     978        // -------------------------------
     979        media.controller.GalleryEdit = media.controller.CollectionEdit( 'gallery', {
     980                type: 'image',
     981                settings: 'Gallery',
     982                defaults: {
     983                        title: l10n.editGalleryTitle
     984                }
     985        });
     986
     987        // wp.media.controller.GalleryAdd
     988        // ---------------------------------
     989        media.controller.GalleryAdd = media.controller.CollectionAdd( 'gallery', {
     990                type: 'image',
     991                defaults: {
     992                        title: l10n.addToGalleryTitle
     993                }
     994        });
     995
     996        // wp.media.controller.PlaylistEdit
     997        // -------------------------------
     998        media.controller.PlaylistEdit = media.controller.CollectionEdit( 'playlist', {
     999                type: 'audio',
     1000                settings: 'Playlist',
     1001                dragInfoText: l10n.playlistDragInfo,
     1002                defaults: {
     1003                        title: l10n.editPlaylistTitle,
     1004                        dragInfo : false
     1005                }
     1006        });
     1007
     1008        // wp.media.controller.PlaylistAdd
     1009        // ---------------------------------
     1010        media.controller.PlaylistAdd = media.controller.CollectionAdd( 'playlist', {
     1011                type: 'audio',
     1012                defaults: {
     1013                        title: l10n.addToPlaylistTitle
     1014                }
     1015        });
     1016
     1017        // wp.media.controller.VideoPlaylistEdit
     1018        // -------------------------------
     1019        media.controller.VideoPlaylistEdit = media.controller.CollectionEdit( 'video-playlist', {
     1020                type: 'video',
     1021                settings: 'Playlist',
     1022                dragInfoText: l10n.videoPlaylistDragInfo,
     1023                defaults: {
     1024                        title: l10n.editVideoPlaylistTitle,
     1025                        dragInfo : false
     1026                }
     1027        });
     1028
     1029        // wp.media.controller.VideoPlaylistAdd
     1030        // ---------------------------------
     1031        media.controller.VideoPlaylistAdd = media.controller.CollectionAdd( 'video-playlist', {
     1032                type: 'video',
     1033                defaults: {
     1034                        title: l10n.addToVideoPlaylistTitle
     1035                }
     1036        });
     1037
    9961038        /**
    9971039         * wp.media.controller.ReplaceImage
    9981040         *
     
    17401782                                        menu:    'gallery'
    17411783                                }),
    17421784
    1743                                 new media.controller.GalleryAdd()
     1785                                new media.controller.GalleryAdd(),
     1786
     1787                                new media.controller.Library({
     1788                                        id:         'playlist',
     1789                                        title:      l10n.createPlaylistTitle,
     1790                                        priority:   60,
     1791                                        toolbar:    'main-playlist',
     1792                                        filterable: 'uploaded',
     1793                                        multiple:   'add',
     1794                                        editable:   false,
     1795
     1796                                        library:  media.query( _.defaults({
     1797                                                type: 'audio'
     1798                                        }, options.library ) )
     1799                                }),
     1800
     1801                                // Playlist states.
     1802                                new media.controller.PlaylistEdit({
     1803                                        library: options.selection,
     1804                                        editing: options.editing,
     1805                                        menu:    'playlist'
     1806                                }),
     1807
     1808                                new media.controller.PlaylistAdd(),
     1809
     1810                                new media.controller.Library({
     1811                                        id:         'video-playlist',
     1812                                        title:      l10n.createVideoPlaylistTitle,
     1813                                        priority:   60,
     1814                                        toolbar:    'main-video-playlist',
     1815                                        filterable: 'uploaded',
     1816                                        multiple:   'add',
     1817                                        editable:   false,
     1818
     1819                                        library:  media.query( _.defaults({
     1820                                                type: 'video'
     1821                                        }, options.library ) )
     1822                                }),
     1823
     1824                                // Video Playlist states.
     1825                                new media.controller.VideoPlaylistEdit({
     1826                                        library: options.selection,
     1827                                        editing: options.editing,
     1828                                        menu:    'video-playlist'
     1829                                }),
     1830
     1831                                new media.controller.VideoPlaylistAdd()
    17441832                        ]);
    17451833
    17461834
     
    17551843                         */
    17561844                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
    17571845                        this.on( 'menu:create:gallery', this.createMenu, this );
     1846                        this.on( 'menu:create:playlist', this.createMenu, this );
     1847                        this.on( 'menu:create:video-playlist', this.createMenu, this );
    17581848                        this.on( 'toolbar:create:main-insert', this.createToolbar, this );
    1759                         this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
     1849                        this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
     1850                        this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
     1851                        this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
    17601852                        this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
    17611853                        this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
    17621854
    17631855                        var handlers = {
    17641856                                menu: {
    17651857                                        'default': 'mainMenu',
    1766                                         'gallery': 'galleryMenu'
     1858                                        'gallery': 'galleryMenu',
     1859                                        'playlist': 'playlistMenu',
     1860                                        'video-playlist': 'videoPlaylistMenu'
    17671861                                },
    17681862
    17691863                                content: {
     
    17751869                                        'main-insert':      'mainInsertToolbar',
    17761870                                        'main-gallery':     'mainGalleryToolbar',
    17771871                                        'gallery-edit':     'galleryEditToolbar',
    1778                                         'gallery-add':      'galleryAddToolbar'
     1872                                        'gallery-add':      'galleryAddToolbar',
     1873                                        'main-playlist':        'mainPlaylistToolbar',
     1874                                        'playlist-edit':        'playlistEditToolbar',
     1875                                        'playlist-add':         'playlistAddToolbar',
     1876                                        'main-video-playlist': 'mainVideoPlaylistToolbar',
     1877                                        'video-playlist-edit': 'videoPlaylistEditToolbar',
     1878                                        'video-playlist-add': 'videoPlaylistAddToolbar'
    17791879                                }
    17801880                        };
    17811881
     
    18251925                        });
    18261926                },
    18271927
     1928                playlistMenu: function( view ) {
     1929                        var lastState = this.lastState(),
     1930                                previous = lastState && lastState.id,
     1931                                frame = this;
     1932
     1933                        view.set({
     1934                                cancel: {
     1935                                        text:     l10n.cancelPlaylistTitle,
     1936                                        priority: 20,
     1937                                        click:    function() {
     1938                                                if ( previous )
     1939                                                        frame.setState( previous );
     1940                                                else
     1941                                                        frame.close();
     1942                                        }
     1943                                },
     1944                                separateCancel: new media.View({
     1945                                        className: 'separator',
     1946                                        priority: 60
     1947                                })
     1948                        });
     1949                },
     1950
     1951                videoPlaylistMenu: function( view ) {
     1952                        var lastState = this.lastState(),
     1953                                previous = lastState && lastState.id,
     1954                                frame = this;
     1955
     1956                        view.set({
     1957                                cancel: {
     1958                                        text:     l10n.cancelVideoPlaylistTitle,
     1959                                        priority: 20,
     1960                                        click:    function() {
     1961                                                if ( previous )
     1962                                                        frame.setState( previous );
     1963                                                else
     1964                                                        frame.close();
     1965                                        }
     1966                                },
     1967                                separateCancel: new media.View({
     1968                                        className: 'separator',
     1969                                        priority: 80
     1970                                })
     1971                        });
     1972                },
     1973
    18281974                // Content
    18291975                embedContent: function() {
    18301976                        var view = new media.view.Embed({
     
    19432089                        });
    19442090                },
    19452091
     2092                mainPlaylistToolbar: function( view ) {
     2093                        var controller = this;
     2094
     2095                        this.selectionStatusToolbar( view );
     2096
     2097                        view.set( 'playlist', {
     2098                                style:    'primary',
     2099                                text:     l10n.createNewPlaylist,
     2100                                priority: 100,
     2101                                requires: { selection: true },
     2102
     2103                                click: function() {
     2104                                        var selection = controller.state().get('selection'),
     2105                                                edit = controller.state('playlist-edit'),
     2106                                                models = selection.where({ type: 'audio' });
     2107
     2108                                        edit.set( 'library', new media.model.Selection( models, {
     2109                                                props:    selection.props.toJSON(),
     2110                                                multiple: true
     2111                                        }) );
     2112
     2113                                        this.controller.setState('playlist-edit');
     2114                                }
     2115                        });
     2116                },
     2117
     2118                mainVideoPlaylistToolbar: function( view ) {
     2119                        var controller = this;
     2120
     2121                        this.selectionStatusToolbar( view );
     2122
     2123                        view.set( 'video-playlist', {
     2124                                style:    'primary',
     2125                                text:     l10n.createNewVideoPlaylist,
     2126                                priority: 100,
     2127                                requires: { selection: true },
     2128
     2129                                click: function() {
     2130                                        var selection = controller.state().get('selection'),
     2131                                                edit = controller.state('video-playlist-edit'),
     2132                                                models = selection.where({ type: 'video' });
     2133
     2134                                        edit.set( 'library', new media.model.Selection( models, {
     2135                                                props:    selection.props.toJSON(),
     2136                                                multiple: true
     2137                                        }) );
     2138
     2139                                        this.controller.setState('video-playlist-edit');
     2140                                }
     2141                        });
     2142                },
     2143
    19462144                featuredImageToolbar: function( toolbar ) {
    19472145                        this.createSelectToolbar( toolbar, {
    19482146                                text:  l10n.setFeaturedImage,
     
    20112209                                        }
    20122210                                }
    20132211                        }) );
     2212                },
     2213
     2214                playlistEditToolbar: function() {
     2215                        var editing = this.state().get('editing');
     2216                        this.toolbar.set( new media.view.Toolbar({
     2217                                controller: this,
     2218                                items: {
     2219                                        insert: {
     2220                                                style:    'primary',
     2221                                                text:     editing ? l10n.updatePlaylist : l10n.insertPlaylist,
     2222                                                priority: 80,
     2223                                                requires: { library: true },
     2224
     2225                                                /**
     2226                                                 * @fires wp.media.controller.State#update
     2227                                                 */
     2228                                                click: function() {
     2229                                                        var controller = this.controller,
     2230                                                                state = controller.state();
     2231
     2232                                                        controller.close();
     2233                                                        state.trigger( 'update', state.get('library') );
     2234
     2235                                                        // Restore and reset the default state.
     2236                                                        controller.setState( controller.options.state );
     2237                                                        controller.reset();
     2238                                                }
     2239                                        }
     2240                                }
     2241                        }) );
     2242                },
     2243
     2244                playlistAddToolbar: function() {
     2245                        this.toolbar.set( new media.view.Toolbar({
     2246                                controller: this,
     2247                                items: {
     2248                                        insert: {
     2249                                                style:    'primary',
     2250                                                text:     l10n.addToPlaylist,
     2251                                                priority: 80,
     2252                                                requires: { selection: true },
     2253
     2254                                                /**
     2255                                                 * @fires wp.media.controller.State#reset
     2256                                                 */
     2257                                                click: function() {
     2258                                                        var controller = this.controller,
     2259                                                                state = controller.state(),
     2260                                                                edit = controller.state('playlist-edit');
     2261
     2262                                                        edit.get('library').add( state.get('selection').models );
     2263                                                        state.trigger('reset');
     2264                                                        controller.setState('playlist-edit');
     2265                                                }
     2266                                        }
     2267                                }
     2268                        }) );
     2269                },
     2270
     2271                videoPlaylistEditToolbar: function() {
     2272                        var editing = this.state().get('editing');
     2273                        this.toolbar.set( new media.view.Toolbar({
     2274                                controller: this,
     2275                                items: {
     2276                                        insert: {
     2277                                                style:    'primary',
     2278                                                text:     editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
     2279                                                priority: 140,
     2280                                                requires: { library: true },
     2281
     2282                                                click: function() {
     2283                                                        var controller = this.controller,
     2284                                                                state = controller.state();
     2285
     2286                                                        controller.close();
     2287                                                        state.trigger( 'update', state.get('library') );
     2288
     2289                                                        // Restore and reset the default state.
     2290                                                        controller.setState( controller.options.state );
     2291                                                        controller.reset();
     2292                                                }
     2293                                        }
     2294                                }
     2295                        }) );
     2296                },
     2297
     2298                videoPlaylistAddToolbar: function() {
     2299                        this.toolbar.set( new media.view.Toolbar({
     2300                                controller: this,
     2301                                items: {
     2302                                        insert: {
     2303                                                style:    'primary',
     2304                                                text:     l10n.addToVideoPlaylist,
     2305                                                priority: 140,
     2306                                                requires: { selection: true },
     2307
     2308                                                click: function() {
     2309                                                        var controller = this.controller,
     2310                                                                state = controller.state(),
     2311                                                                edit = controller.state('video-playlist-edit');
     2312
     2313                                                        edit.get('library').add( state.get('selection').models );
     2314                                                        state.trigger('reset');
     2315                                                        controller.setState('video-playlist-edit');
     2316                                                }
     2317                                        }
     2318                                }
     2319                        }) );
    20142320                }
    2015 
    20162321        });
    20172322
    20182323        media.view.MediaFrame.ImageDetails = media.view.MediaFrame.Select.extend({
     
    48375142         * @augments Backbone.View
    48385143         */
    48395144        media.view.Settings.Gallery = media.view.Settings.extend({
    4840                 className: 'gallery-settings',
     5145                className: 'collection-settings gallery-settings',
    48415146                template:  media.template('gallery-settings')
    48425147        });
    48435148
    48445149        /**
     5150         * wp.media.view.Settings.Gallery
     5151         */
     5152        media.view.Settings.Playlist = media.view.Settings.extend({
     5153                className: 'collection-settings playlist-settings',
     5154                template:  media.template('playlist-settings')
     5155        });
     5156
     5157        /**
    48455158         * wp.media.view.Attachment.Details
    48465159         *
    48475160         * @constructor
  • src/wp-includes/js/mediaelement/wp-mediaelement.css

     
    1313.me-cannotplay {
    1414        width: auto !important;
    1515}
     16
     17.wp-playlist {
     18        border: 1px solid #ccc;
     19        padding: 10px;
     20        margin: 12px 0 18px;
     21        font-size: 85%;
     22}
     23
     24.wp-playlist .mejs-container {
     25        margin: 0;
     26        width: 100%;
     27}
     28
     29.wp-playlist .mejs-controls .mejs-button button {
     30        outline: 0;
     31}
     32
     33.wp-playlist-light {
     34        background: #fff;
     35}
     36
     37.wp-playlist-dark {
     38        color: #fff;
     39        background: #000;
     40}
     41
     42.wp-playlist-current-item {
     43        overflow: hidden;
     44        margin-bottom: 10px;
     45}
     46
     47.wp-playlist-current-item img {
     48        float: left;
     49        max-width: 60px;
     50        height: auto;
     51        margin-right: 10px;
     52}
     53
     54.wp-playlist-caption {
     55}
     56
     57.wp-caption-meta {
     58        display: block;
     59}
     60
     61.wp-caption-title {
     62        font-size: 100%;
     63}
     64
     65.wp-caption-album {
     66        font-style: italic;
     67}
     68
     69.wp-caption-artist {
     70        font-size: 80%;
     71        text-transform: uppercase;
     72}
     73
     74.wp-caption-by {
     75        font-size: 65%;
     76        font-weight: bold;
     77}
     78
     79.wp-playlist-item-length {
     80        position: absolute;
     81        right: 0;
     82        top: 0;
     83}
     84
     85.wp-playlist-tracks {
     86        margin-top: 10px;
     87        border-top: 1px solid #ccc;
     88}
     89
     90.wp-playlist-item {
     91        position: relative;
     92        cursor: pointer;
     93        border-bottom: 1px solid #ccc;
     94}
     95 No newline at end of file
  • src/wp-includes/js/mediaelement/wp-playlist.js

     
     1/*globals window, document, $, jQuery */
     2
     3(function ($, _, Backbone) {
     4        "use strict";
     5
     6        var WPPlaylistView = Backbone.View.extend({
     7                index : 0,
     8
     9                itemTemplate : wp.template('wp-playlist-item'),
     10
     11                initialize : function () {
     12                        var settings = {};
     13
     14                        this.data = $.parseJSON( this.$('script').html() );
     15                        this.playerNode = this.$( this.data.type );
     16
     17                        this.tracks = new Backbone.Collection( this.data.tracks );
     18                        this.current = this.tracks.first();
     19
     20                        if ( 'audio' === this.data.type ) {
     21                                this.currentTemplate = wp.template('wp-playlist-current-item');
     22                                this.currentNode = this.$( '.wp-playlist-current-item' );
     23                        }
     24
     25                        this.renderCurrent();
     26
     27                        if ( this.data.tracklist ) {
     28                                this.renderTracks();
     29                        }
     30
     31                        this.playerNode.attr( 'src', this.current.get('src') );
     32
     33                        _.bindAll( this, 'bindPlayer', 'ended', 'clickTrack' );
     34
     35                        if ( typeof _wpmejsSettings !== 'undefined' ) {
     36                                settings.pluginPath = _wpmejsSettings.pluginPath;
     37                        }
     38                        settings.defaultAudioWidth = '100%';
     39                        settings.success = this.bindPlayer;
     40
     41                        new MediaElementPlayer( this.playerNode.get(0), settings );
     42                },
     43
     44                renderCurrent : function () {
     45                        if ( 'video' === this.data.type ) {
     46                                if ( this.data.images && this.current.get( 'image' ) ) {
     47                                        this.playerNode.attr( 'poster', this.current.get( 'image' ).src );
     48                                }
     49                                this.playerNode.attr( 'width', this.current.get( 'width' ) );
     50                                this.playerNode.attr( 'height', this.current.get( 'height' ) );
     51                        } else {
     52                                if ( ! this.data.images ) {
     53                                        this.current.set( 'image', false );
     54                                }
     55                                this.currentNode.html( this.currentTemplate( this.current.toJSON() ) );
     56                        }
     57                },
     58
     59                renderTracks : function () {
     60                        var that = this, i = 1, tracklist = $( '<div class="wp-playlist-tracks"></div>' );
     61                        this.tracks.each(function (model) {
     62                                if ( ! that.data.images ) {
     63                                        model.set( 'image', false );
     64                                }
     65                                model.set( 'index', that.data.tracknumbers ? i : false );
     66                                tracklist.append( that.itemTemplate( model.toJSON() ) );
     67                                i += 1;
     68                        });
     69                        this.$el.append( tracklist );
     70                },
     71
     72                events : {
     73                        'click .wp-playlist-item' : 'clickTrack',
     74                        'click .wp-playlist-next' : 'next',
     75                        'click .wp-playlist-prev' : 'prev'
     76                },
     77
     78                bindPlayer : function (mejs) {
     79                        this.player = mejs;
     80                        this.player.addEventListener( 'ended', this.ended );
     81                },
     82
     83                clickTrack : function (e) {
     84                        this.index = this.$( '.wp-playlist-item' ).index( e.currentTarget );
     85                        this.setCurrent();
     86                },
     87
     88                ended : function () {
     89                        if ( this.index + 1 < this.tracks.length ) {
     90                                this.next();
     91                        } else {
     92                                this.index = 0;
     93                                this.current = this.tracks.at( this.index );
     94                                this.loadCurrent();
     95                        }
     96                },
     97
     98                next : function () {
     99                        this.index = this.index + 1 >= this.tracks.length ? 0 : this.index + 1;
     100                        this.setCurrent();
     101                },
     102
     103                prev : function () {
     104                        this.index = this.index - 1 < 0 ? this.tracks.length - 1 : this.index - 1;
     105                        this.setCurrent();
     106                },
     107
     108                loadCurrent : function () {
     109                        this.player.pause();
     110                        this.playerNode.attr( 'src', this.current.get( 'src' ) );
     111                        this.renderCurrent();
     112                        this.player.load();
     113                },
     114
     115                setCurrent : function () {
     116                        this.current = this.tracks.at( this.index );
     117                        this.loadCurrent();
     118                        this.player.play();
     119                }
     120        });
     121
     122    $(document).ready(function () {
     123                $('.wp-playlist').each(function () {
     124                        return new WPPlaylistView({ el: this });
     125                });
     126    });
     127
     128}(jQuery, _, Backbone));
     129 No newline at end of file
  • src/wp-includes/js/plupload/handlers.js

     
    2222                .appendTo( jQuery('#media-items' ) );
    2323
    2424        // Disable submit
    25         jQuery('#insert-gallery').prop('disabled', true);
     25        jQuery('#insert-gallery, #insert-playlist').prop('disabled', true);
    2626}
    2727
    2828function uploadStart() {
     
    4747
    4848        if ( max > hundredmb && file.size > hundredmb ) {
    4949                setTimeout(function(){
    50                        
     50
    5151                        if ( file.status < 3 && file.loaded === 0 ) { // not uploading
    5252                                wpFileError(file, pluploadL10n.big_upload_failed.replace('%1$s', '<a class="uploader-html" href="#">').replace('%2$s', '</a>'));
    5353                                up.stop(); // stops the whole queue
     
    6464        // Just one file, no need for collapsible part
    6565        if ( items.length == 1 ) {
    6666                items.addClass('open').find('.slidetoggle').show();
    67                 jQuery('.insert-gallery').hide();
     67                jQuery('.insert-gallery, .insert-playlist').hide();
    6868        } else if ( items.length > 1 ) {
    6969                items.removeClass('open');
    70                 // Only show Gallery button when there are at least two files.
    71                 jQuery('.insert-gallery').show();
     70                // Only show Gallery/Playlist buttons when there are at least two files.
     71                jQuery('.insert-gallery, .insert-playlist').show();
    7272        }
    7373
    7474        // Only show Save buttons when there is at least one file.
     
    171171                        success: function( ){
    172172                                var type,
    173173                                        item = jQuery('#media-item-' + fileObj.id);
    174                                
     174
    175175                                if ( type = jQuery('#type-of-' + fileObj.id).val() )
    176176                                        jQuery('#' + type + '-counter').text(jQuery('#' + type + '-counter').text()-0+1);
    177177
     
    257257}
    258258
    259259function uploadComplete() {
    260         jQuery('#insert-gallery').prop('disabled', false);
     260        jQuery('#insert-gallery, #insert-playlist').prop('disabled', false);
    261261}
    262262
    263263function switchUploader(s) {
  • src/wp-includes/js/swfupload/handlers.js

     
    2525        jQuery('.progress', '#media-item-' + fileObj.id).show();
    2626
    2727        // Disable submit and enable cancel
    28         jQuery('#insert-gallery').prop('disabled', true);
     28        jQuery('#insert-gallery, #insert-playlist').prop('disabled', true);
    2929        jQuery('#cancel-upload').prop('disabled', false);
    3030}
    3131
    3232function uploadStart(fileObj) {
    3333        try {
    3434                if ( typeof topWin.tb_remove != 'undefined' )
    35                         topWin.jQuery('#TB_overlay').unbind('click', topWin.tb_remove); 
     35                        topWin.jQuery('#TB_overlay').unbind('click', topWin.tb_remove);
    3636        } catch(e){}
    3737
    3838        return true;
     
    212212        else
    213213                jQuery('.savebutton').hide();
    214214
    215         // Only show Gallery button when there are at least two files.
    216         if ( items.length > 1 )
    217                 jQuery('.insert-gallery').show();
    218         else
    219                 jQuery('.insert-gallery').hide();
     215        // Only show Gallery/Playlist buttons when there are at least two files.
     216        if ( items.length > 1 ) {
     217                jQuery('.insert-gallery, .insert-playlist').show();
     218        } else {
     219                jQuery('.insert-gallery, .insert-playlist').hide();
     220        }
    220221}
    221222
    222223function uploadSuccess(fileObj, serverData) {
     
    238239        // If no more uploads queued, enable the submit button
    239240        if ( swfu.getStats().files_queued == 0 ) {
    240241                jQuery('#cancel-upload').prop('disabled', true);
    241                 jQuery('#insert-gallery').prop('disabled', false);
     242                jQuery('#insert-gallery, #insert-playlist').prop('disabled', false);
    242243        }
    243244}
    244245
  • src/wp-includes/js/tinymce/langs/wp-langs-en.js

     
    478478                add_audio: "Add Audio",
    479479                editgallery: "Edit Gallery",
    480480                delgallery: "Delete Gallery",
     481                editplaylist: "Edit Playlist",
     482                delplaylist: "Delete Playlist",
    481483                wp_fullscreen_desc: "Distraction Free Writing mode (Alt + Shift + W)"
    482484        });
    483485
  • src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js

     
    2525        }
    2626
    2727        function replaceAVShortcodes( content ) {
    28                 var testRegex = /\[(audio|video)[^\]]*\]/,
    29                         replaceRegex = /\[(audio|video)[^\]]*\]([\s\S]*?\[\/\1\])?/;
     28                var testRegex = /\[(video-playlist|audio|video|playlist)[^\]]*\]/,
     29                        replaceRegex = /\[(video-playlist|audio|video|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/;
    3030
    3131                while ( testRegex.test( content ) ) {
    3232                        content = content.replace( replaceRegex, replaceCallback );
     
    6060                }
    6161
    6262                // Check if the `wp.media.gallery` API exists.
    63                 if ( typeof wp === 'undefined' || ! wp.media || ! wp.media.gallery ) {
     63                if ( typeof wp === 'undefined' || ! wp.media ) {
    6464                        return;
    6565                }
    6666
    6767                // Make sure we've selected a gallery node.
    68                 if ( editor.dom.hasClass( node, 'wp-gallery' ) ) {
     68                if ( editor.dom.hasClass( node, 'wp-gallery' ) && wp.media.gallery ) {
    6969                        gallery = wp.media.gallery;
    7070                        data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
    7171                        frame = gallery.edit( data );
     
    7474                                var shortcode = gallery.shortcode( selection ).string();
    7575                                editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
    7676                        });
     77                } else if ( editor.dom.hasClass( node, 'wp-playlist' ) && wp.media.playlist ) {
     78                        data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
     79                        frame = wp.media.playlist.edit( data );
     80
     81                        frame.state('playlist-edit').on( 'update', function( selection ) {
     82                                var shortcode = wp.media.playlist.shortcode( selection ).string();
     83                                editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
     84                        });
     85                } else if ( editor.dom.hasClass( node, 'wp-video-playlist' ) && wp.media['video-playlist'] ) {
     86                        data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
     87                        frame = wp.media['video-playlist'].edit( data );
     88
     89                        frame.state('video-playlist-edit').on( 'update', function( selection ) {
     90                                var shortcode = wp.media['video-playlist'].shortcode( selection ).string();
     91                                editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
     92                        });
    7793                } else {
    7894                        // temp
    7995                        window.console && window.console.log( 'Edit AV shortcode ' + window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) ) );
     
    138154                                event.name = 'video';
    139155                        } else if ( dom.hasClass( node, 'wp-audio' ) ) {
    140156                                event.name = 'audio';
     157                        } else if ( dom.hasClass( node, 'wp-playlist' ) ) {
     158                                event.name = 'playlist';
     159                        } else if ( dom.hasClass( node, 'wp-video-playlist' ) ) {
     160                                event.name = 'video-playlist';
    141161                        }
    142162                }
    143163        });
  • src/wp-includes/js/tinymce/skins/wordpress/wp-content.css

     
    143143        background-image: url("images/audio.png");
    144144}
    145145
     146.mce-content-body img.wp-media.wp-playlist {
     147        background-image: url("images/audio.png");
     148}
     149
     150.mce-content-body img.wp-media.wp-video-playlist {
     151        background-image: url("images/video.png");
     152}
     153
    146154#wp-image-toolbar {
    147155        position: absolute;
    148156}
  • src/wp-includes/media-template.php

     
    411411                </label>
    412412        </script>
    413413
     414        <script type="text/html" id="tmpl-playlist-settings">
     415                <h3><?php _e('Playlist Settings'); ?></h3>
     416
     417                <label class="setting">
     418                        <span><?php _e( 'Random Order' ); ?></span>
     419                        <input type="checkbox" data-setting="_orderbyRandom" />
     420                </label>
     421
     422                <label class="setting">
     423                        <span><?php _e('Style'); ?></span>
     424                        <select class="style" data-setting="style">
     425                                <option value="light">
     426                                        <?php esc_attr_e('Light'); ?>
     427                                </option>
     428                                <option value="dark">
     429                                        <?php esc_attr_e('Dark'); ?>
     430                                </option>
     431                        </select>
     432                </label>
     433
     434                <label class="setting">
     435                        <span><?php _e( 'Show Tracklist' ); ?></span>
     436                        <input type="checkbox" data-setting="_tracklist" />
     437                </label>
     438
     439                <label class="setting">
     440                        <span><?php _e( 'Show Track Numbers' ); ?></span>
     441                        <input type="checkbox" data-setting="_tracknumbers" />
     442                </label>
     443
     444                <label class="setting">
     445                        <span><?php _e( 'Show Images' ); ?></span>
     446                        <input type="checkbox" data-setting="_images" />
     447                </label>
     448        </script>
     449
    414450        <script type="text/html" id="tmpl-embed-link-settings">
    415451                <label class="setting">
    416452                        <span><?php _e('Title'); ?></span>
  • src/wp-includes/media.php

     
    934934}
    935935
    936936/**
     937 * The Playlist shortcode.
     938 *
     939 * This implements the functionality of the Playlist Shortcode for displaying
     940 * a collection of WordPress audio or video files in a post.
     941 *
     942 * @since 3.9.0
     943 *
     944 * @param array $attr Attributes of the shortcode.
     945 * @return string $type Type of playlist. Defaults to audio, video is also supported
     946 */
     947function wp_get_playlist( $attr, $type ) {
     948        global $content_width;
     949        $post = get_post();
     950
     951        if ( ! in_array( $type, array( 'audio', 'video' ) ) ) {
     952                return '';
     953        }
     954
     955        static $instance = 0;
     956        $instance++;
     957
     958        if ( ! empty( $attr['ids'] ) ) {
     959                // 'ids' is explicitly ordered, unless you specify otherwise.
     960                if ( empty( $attr['orderby'] ) ) {
     961                        $attr['orderby'] = 'post__in';
     962                }
     963                $attr['include'] = $attr['ids'];
     964        }
     965
     966        // Allow plugins/themes to override the default gallery template.
     967        $output = apply_filters( 'post_playlist', '', $attr, $type );
     968        if ( $output != '' ) {
     969                return $output;
     970        }
     971
     972        // We're trusting author input, so let's at least make sure it looks like a valid orderby statement
     973        if ( isset( $attr['orderby'] ) ) {
     974                $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
     975                if ( ! $attr['orderby'] )
     976                        unset( $attr['orderby'] );
     977        }
     978
     979        extract( shortcode_atts( array(
     980                'order'         => 'ASC',
     981                'orderby'       => 'menu_order ID',
     982                'id'            => $post ? $post->ID : 0,
     983                'include'       => '',
     984                'exclude'   => '',
     985                'style'         => 'light',
     986                'tracklist' => 'audio' === $type,
     987                'tracknumbers' => 'audio' === $type,
     988                'images'        => true
     989        ), $attr, 'playlist' ) );
     990
     991        // don't pass strings to JSON, will be truthy in JS
     992        $tracklist = filter_var( $tracklist, FILTER_VALIDATE_BOOLEAN );
     993        $tracknumbers = filter_var( $tracknumbers, FILTER_VALIDATE_BOOLEAN );
     994        $images = filter_var( $images, FILTER_VALIDATE_BOOLEAN );
     995
     996        $id = intval( $id );
     997        if ( 'RAND' == $order ) {
     998                $orderby = 'none';
     999        }
     1000
     1001        $args = array(
     1002                'post_status' => 'inherit',
     1003                'post_type' => 'attachment',
     1004                'post_mime_type' => $type,
     1005                'order' => $order,
     1006                'orderby' => $orderby
     1007        );
     1008
     1009        if ( ! empty( $include ) ) {
     1010                $args['include'] = $include;
     1011                $_attachments = get_posts( $args );
     1012
     1013                $attachments = array();
     1014                foreach ( $_attachments as $key => $val ) {
     1015                        $attachments[$val->ID] = $_attachments[$key];
     1016                }
     1017        } elseif ( ! empty( $exclude ) ) {
     1018                $args['post_parent'] = $id;
     1019                $args['exclude'] = $exclude;
     1020                $attachments = get_children( $args );
     1021        } else {
     1022                $args['post_parent'] = $id;
     1023                $attachments = get_children( $args );
     1024        }
     1025
     1026        if ( empty( $attachments ) ) {
     1027                return '';
     1028        }
     1029
     1030        if ( is_feed() ) {
     1031                $output = "\n";
     1032                foreach ( $attachments as $att_id => $attachment ) {
     1033                        $output .= wp_get_attachment_link( $att_id ) . "\n";
     1034                }
     1035                return $output;
     1036        }
     1037
     1038        $supports_thumbs = ( current_theme_supports( 'post-thumbnails', "attachment:$type" ) && post_type_supports( "attachment:$type", 'thumbnail' ) )
     1039                || $images;
     1040
     1041        $outer = 22; // default padding and border of wrapper
     1042        $data = compact( 'type', 'style', 'tracklist', 'tracknumbers', 'images' );
     1043        $tracks = array();
     1044        foreach ( $attachments as $attachment ) {
     1045                $url = wp_get_attachment_url( $attachment->ID );
     1046                $ftype = wp_check_filetype( $url, wp_get_mime_types() );
     1047                $track = array(
     1048                        'type' => $type,
     1049                        'src' => $url,
     1050                        'type' => $ftype['ext'],
     1051                        'title' => get_the_title( $attachment->ID ),
     1052                        'caption' => wptexturize( $attachment->post_excerpt ),
     1053                        'description' => wptexturize( $attachment->post_content )
     1054                );
     1055
     1056                $meta = wp_get_attachment_metadata( $attachment->ID );
     1057                if ( ! empty( $meta ) ) {
     1058                        $track['meta'] = array();
     1059
     1060                        $keys = array( 'title', 'artist', 'band', 'album', 'genre', 'year', 'length', 'length_formatted' );
     1061                        foreach ( $keys as $key ) {
     1062                                if ( ! empty( $meta[ $key ] ) ) {
     1063                                        $track['meta'][ $key ] = $meta[ $key ];
     1064                                }
     1065                        }
     1066
     1067                        if ( 'video' === $type ) {
     1068                                $width = empty( $meta['width'] ) ? 640 : $meta['width'];
     1069                                $height = empty( $meta['height'] ) ? 360 : $meta['height'];
     1070                                $track['width'] = $content_width - $outer;
     1071                                $track['height'] = round( ( $height * $track['width'] ) / $width );
     1072                        }
     1073                }
     1074
     1075                if ( $supports_thumbs ) {
     1076                        $id = get_post_thumbnail_id( $attachment->ID );
     1077                        if ( ! empty( $id ) ) {
     1078                                list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' );
     1079                                $track['image'] = compact( 'src', 'width', 'height' );
     1080                                list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumb' );
     1081                                $track['thumb'] = compact( 'src', 'width', 'height' );
     1082                        }
     1083                }
     1084
     1085                $tracks[] = $track;
     1086        }
     1087        $data['tracks'] = $tracks;
     1088
     1089        ob_start();
     1090
     1091        if ( 1 === $instance ):
     1092                wp_enqueue_style( 'wp-mediaelement' );
     1093                wp_enqueue_script( 'wp-playlist' );
     1094?>
     1095<!--[if lt IE 9]><script>document.createElement('<?php echo $type ?>');</script><![endif]-->
     1096<script type="text/html" id="tmpl-wp-playlist-current-item">
     1097        <# if ( data.image ) { #>
     1098        <img src="{{{ data.image.src }}}"/>
     1099        <# } #>
     1100        <# if ( data.meta.title ) { #>
     1101        <div class="wp-playlist-caption">
     1102                <span class="wp-caption-meta wp-caption-title">&#8220;{{{ data.meta.title }}}&#8221;</span>
     1103                <span class="wp-caption-meta wp-caption-album">{{{ data.meta.album }}}</span>
     1104                <span class="wp-caption-meta wp-caption-artist">{{{ data.meta.artist }}}</span>
     1105        </div>
     1106        <# } else { #>
     1107        <div class="wp-playlist-caption">{{{ data.caption }}}</div>
     1108        <# } #>
     1109</script>
     1110<script type="text/html" id="tmpl-wp-playlist-item">
     1111        <div class="wp-playlist-item">
     1112                <# if ( ( data.title || data.meta.title ) && data.meta.artist ) { #>
     1113                <div class="wp-playlist-caption">
     1114                        {{{ data.index ? ( data.index + '.&nbsp;' ) : '' }}}
     1115                        <span class="wp-caption-title">&#8220;{{{ data.title ? data.title : data.meta.title }}}&#8221;</span>
     1116                        <span class="wp-caption-by"><?php _e( 'by' ) ?></span>
     1117                        <span class="wp-caption-artist">{{{ data.meta.artist }}}</span>
     1118                </div>
     1119                <# } else { #>
     1120                <div class="wp-playlist-caption">{{{ data.index ? ( data.index + '.' ) : '' }}} {{{ data.caption ? data.caption : data.title }}}</div>
     1121                <# } #>
     1122                <# if ( data.meta.length_formatted ) { #>
     1123                <div class="wp-playlist-item-length">{{{ data.meta.length_formatted }}}</div>
     1124                <# } #>
     1125        </div>
     1126</script>
     1127        <?php endif ?>
     1128<div class="wp-playlist wp-<?php echo $type ?>-playlist wp-playlist-<?php echo $style ?>">
     1129        <?php if ( 'audio' === $type ): ?>
     1130        <div class="wp-playlist-current-item"></div>
     1131        <?php endif ?>
     1132        <<?php echo $type ?> controls="controls" preload="metadata" width="<?php echo $content_width - $outer ?>"></<?php echo $type ?>>
     1133        <div class="wp-playlist-next"></div>
     1134        <div class="wp-playlist-prev"></div>
     1135        <noscript>
     1136        <?php
     1137        $output = "\n";
     1138        foreach ( $attachments as $att_id => $attachment ) {
     1139                $output .= wp_get_attachment_link( $att_id ) . "\n";
     1140        }
     1141
     1142        echo $output;
     1143        ?>
     1144        </noscript>
     1145        <script type="application/json"><?php echo json_encode( $data ) ?></script>
     1146</div>
     1147        <?php
     1148        return ob_get_clean();
     1149}
     1150
     1151function wp_playlist_shortcode( $attr ) {
     1152        return wp_get_playlist( $attr, 'audio' );
     1153}
     1154add_shortcode( 'playlist', 'wp_playlist_shortcode' );
     1155
     1156function wp_video_playlist_shortcode( $attr ) {
     1157        return wp_get_playlist( $attr, 'video' );
     1158}
     1159add_shortcode( 'video-playlist', 'wp_video_playlist_shortcode' );
     1160
     1161/**
    9371162 * Provide a No-JS Flash fallback as a last resort for audio / video
    9381163 *
    9391164 * @since 3.6.0
     
    20122237                        'nonce' => wp_create_nonce( 'update-post_' . $post->ID ),
    20132238                );
    20142239
    2015                 if ( current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' ) ) {
     2240                if ( theme_supports_thumbnails( $post ) && post_supports_thumbnails( $post ) ) {
    20162241                        $featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true );
    20172242                        $settings['post']['featuredImageId'] = $featured_image_id ? $featured_image_id : -1;
    20182243                }
     
    20442269                'mediaLibraryTitle'  => __( 'Media Library' ),
    20452270                'insertMediaTitle'   => __( 'Insert Media' ),
    20462271                'createNewGallery'   => __( 'Create a new gallery' ),
     2272                'createNewPlaylist'   => __( 'Create a new playlist' ),
     2273                'createNewVideoPlaylist'   => __( 'Create a new video playlist' ),
    20472274                'returnToLibrary'    => __( '&#8592; Return to library' ),
    20482275                'allMediaItems'      => __( 'All media items' ),
    20492276                'noItemsFound'       => __( 'No items found.' ),
     
    20712298                // Edit Image
    20722299                'imageDetailsTitle'     => __( 'Image Details' ),
    20732300                'imageReplaceTitle'     => __( 'Replace Image' ),
    2074                 'imageDetailsCancel'     => __( 'Cancel Edit' )
     2301                'imageDetailsCancel'    => __( 'Cancel Edit' ),
     2302
     2303                // Playlist
     2304                'playlistDragInfo'    => __( 'Drag and drop to reorder tracks.' ),
     2305                'createPlaylistTitle' => __( 'Create Playlist' ),
     2306                'editPlaylistTitle'   => __( 'Edit Playlist' ),
     2307                'cancelPlaylistTitle' => __( '&#8592; Cancel Playlist' ),
     2308                'insertPlaylist'      => __( 'Insert playlist' ),
     2309                'updatePlaylist'      => __( 'Update playlist' ),
     2310                'addToPlaylist'       => __( 'Add to playlist' ),
     2311                'addToPlaylistTitle'  => __( 'Add to Playlist' ),
     2312
     2313                // Video Playlist
     2314                'videoPlaylistDragInfo'    => __( 'Drag and drop to reorder videos.' ),
     2315                'createVideoPlaylistTitle' => __( 'Create Video Playlist' ),
     2316                'editVideoPlaylistTitle'   => __( 'Edit Video Playlist' ),
     2317                'cancelVideoPlaylistTitle' => __( '&#8592; Cancel Video Playlist' ),
     2318                'insertVideoPlaylist'      => __( 'Insert Video playlist' ),
     2319                'updateVideoPlaylist'      => __( 'Update Video playlist' ),
     2320                'addToVideoPlaylist'       => __( 'Add to Video playlist' ),
     2321                'addToVideoPlaylistTitle'  => __( 'Add to Video Playlist' ),
    20752322        );
    20762323
    20772324        $settings = apply_filters( 'media_view_settings', $settings, $post );
     
    22402487/**
    22412488 * If an attachment is missing its metadata, try to regenerate it
    22422489 *
     2490 * @since 3.9.0
     2491 *
    22432492 * @param post $attachment Post object.
    22442493 */
    22452494function maybe_regenerate_attachment_metadata( $attachment ) {
     
    22582507                        delete_transient( $regeneration_lock );
    22592508                }
    22602509        }
     2510}
     2511
     2512/**
     2513 * Whether a post supports thumbnails
     2514 *
     2515 * @since 3.9.0
     2516 *
     2517 * @param WP_Post $post
     2518 *
     2519 * @return boolean
     2520 */
     2521function post_supports_thumbnails( $post ) {
     2522        if ( 'attachment' === $post->post_type ) {
     2523                if ( 0 === strpos( $post->post_mime_type, 'audio' ) ) {
     2524                        return post_type_supports( 'attachment:audio', 'thumbnail' );
     2525                } elseif ( 0 === strpos( $post->post_mime_type, 'video' ) ) {
     2526                        return post_type_supports( 'attachment:video', 'thumbnail' );
     2527                }
     2528        }
     2529
     2530        return post_type_supports( $post->post_type, 'thumbnail' );
     2531}
     2532
     2533/**
     2534 * Whether a theme supports thumbnails
     2535 *
     2536 * @since 3.9.0
     2537 *
     2538 * @param WP_Post $post
     2539 *
     2540 * @return boolean
     2541 */
     2542function theme_supports_thumbnails( $post ) {
     2543        if ( 'attachment' === $post->post_type ) {
     2544                if ( 0 === strpos( $post->post_mime_type, 'audio' ) ) {
     2545                        return current_theme_supports( 'post-thumbnails', 'attachment:audio' );
     2546                } elseif ( 0 === strpos( $post->post_mime_type, 'video' ) ) {
     2547                        return current_theme_supports( 'post-thumbnails', 'attachment:video' );
     2548                }
     2549        }
     2550
     2551        return current_theme_supports( 'post-thumbnails', $post->post_type );
    22612552}
     2553 No newline at end of file
  • src/wp-includes/script-loader.php

     
    315315                'pluginPath' => includes_url( 'js/mediaelement/', 'relative' ),
    316316        ) );
    317317
     318        $scripts->add( 'wp-playlist', "/wp-includes/js/mediaelement/wp-playlist.js", array( 'wp-util', 'backbone', 'mediaelement' ), false, 1 );
     319
    318320        $scripts->add( 'zxcvbn-async', "/wp-includes/js/zxcvbn-async$suffix.js", array(), '1.0' );
    319321        did_action( 'init' ) && $scripts->localize( 'zxcvbn-async', '_zxcvbnSettings', array(
    320322                'src' => empty( $guessed_url ) ? includes_url( '/js/zxcvbn.min.js' ) : $scripts->base_url . '/wp-includes/js/zxcvbn.min.js',