WordPress.org

Make WordPress Core

Ticket #26631: 26631.9.diff

File 26631.9.diff, 36.4 KB (added by wonderboymusic, 7 years ago)
  • 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

     
    558558                }));
    559559        }());
    560560
     561        wp.media.playlist = (function() {
     562                var playlist = {
     563                        defaults : {
     564                                id: wp.media.view.settings.post.id,
     565                                style: 'light',
     566                                tracklist: true,
     567                                tracknumbers: true,
     568                                images: true
     569                        }
     570                };
     571
     572                return _.extend(playlist, wp.media.collection.instance( 'playlist', {
     573                        type : 'audio',
     574                        title : wp.media.view.l10n.editPlaylistTitle
     575                }));
     576        }());
     577
     578        wp.media['video-playlist'] = (function() {
     579                var playlist = {
     580                        defaults : {
     581                                id: wp.media.view.settings.post.id,
     582                                style: 'light',
     583                                tracklist: false,
     584                                tracknumbers: false,
     585                                images: false
     586                        }
     587                };
     588
     589                return _.extend(playlist, wp.media.collection.instance( 'video-playlist', {
     590                        type : 'video',
     591                        title : wp.media.view.l10n.editVideoPlaylistTitle
     592                }));
     593        }());
     594
    561595        /**
    562596         * wp.media.featuredImage
    563597         * @namespace
     
    776810                                this.insert( wp.media.gallery.shortcode( selection ).string() );
    777811                        }, this );
    778812
     813                        workflow.state('playlist-edit').on( 'update', function( selection ) {
     814                                this.insert( wp.media.playlist.shortcode( selection ).string() );
     815                        }, this );
     816
     817                        workflow.state('video-playlist-edit').on( 'update', function( selection ) {
     818                                this.insert( wp.media['video-playlist'].shortcode( selection ).string() );
     819                        }, this );
     820
    779821                        workflow.state('embed').on( 'select', function() {
    780822                                /**
    781823                                 * @this wp.media.editor
     
    10151057                                if ( elem.hasClass( 'gallery' ) ) {
    10161058                                        options.state = 'gallery';
    10171059                                        options.title = wp.media.view.l10n.createGalleryTitle;
     1060                                } else if ( elem.hasClass( 'playlist' ) ) {
     1061                                        options.state = 'playlist';
     1062                                        options.title = wp.media.view.l10n.createPlaylistTitle;
     1063                                } else if ( elem.hasClass( 'video-playlist' ) ) {
     1064                                        options.state = 'video-playlist';
     1065                                        options.title = wp.media.view.l10n.createVideoPlaylistTitle;
    10181066                                }
    10191067
    10201068                                wp.media.editor.open( editor, options );
  • src/wp-includes/js/media-views.js

     
    941941                        title: l10n.addToGalleryTitle
    942942                }
    943943        });
     944
     945        // wp.media.controller.PlaylistEdit
     946        // -------------------------------
     947        media.controller.PlaylistEdit = media.controller.CollectionEdit( 'playlist', {
     948                type: 'audio',
     949                settings: 'Playlist',
     950                dragInfoText: l10n.playlistDragInfo,
     951                defaults: {
     952                        title: l10n.editPlaylistTitle,
     953                        dragInfo : false
     954                }
     955        });
     956
     957        // wp.media.controller.PlaylistAdd
     958        // ---------------------------------
     959        media.controller.PlaylistAdd = media.controller.CollectionAdd( 'playlist', {
     960                type: 'audio',
     961                defaults: {
     962                        title: l10n.addToPlaylistTitle
     963                }
     964        });
     965
     966        // wp.media.controller.VideoPlaylistEdit
     967        // -------------------------------
     968        media.controller.VideoPlaylistEdit = media.controller.CollectionEdit( 'video-playlist', {
     969                type: 'video',
     970                settings: 'Playlist',
     971                dragInfoText: l10n.videoPlaylistDragInfo,
     972                defaults: {
     973                        title: l10n.editVideoPlaylistTitle,
     974                        dragInfo : false
     975                }
     976        });
     977
     978        // wp.media.controller.VideoPlaylistAdd
     979        // ---------------------------------
     980        media.controller.VideoPlaylistAdd = media.controller.CollectionAdd( 'video-playlist', {
     981                type: 'video',
     982                defaults: {
     983                        title: l10n.addToVideoPlaylistTitle
     984                }
     985        });
     986
    944987        /**
    945988         * wp.media.controller.FeaturedImage
    946989         *
     
    17671810                                        menu:    'gallery'
    17681811                                }),
    17691812
    1770                                 new media.controller.GalleryAdd()
     1813                                new media.controller.GalleryAdd(),
     1814
     1815                                new media.controller.Library({
     1816                                        id:         'playlist',
     1817                                        title:      l10n.createPlaylistTitle,
     1818                                        priority:   60,
     1819                                        toolbar:    'main-playlist',
     1820                                        filterable: 'uploaded',
     1821                                        multiple:   'add',
     1822                                        editable:   false,
     1823
     1824                                        library:  media.query( _.defaults({
     1825                                                type: 'audio'
     1826                                        }, options.library ) )
     1827                                }),
     1828
     1829                                // Playlist states.
     1830                                new media.controller.PlaylistEdit({
     1831                                        library: options.selection,
     1832                                        editing: options.editing,
     1833                                        menu:    'playlist'
     1834                                }),
     1835
     1836                                new media.controller.PlaylistAdd(),
     1837
     1838                                new media.controller.Library({
     1839                                        id:         'video-playlist',
     1840                                        title:      l10n.createVideoPlaylistTitle,
     1841                                        priority:   60,
     1842                                        toolbar:    'main-video-playlist',
     1843                                        filterable: 'uploaded',
     1844                                        multiple:   'add',
     1845                                        editable:   false,
     1846
     1847                                        library:  media.query( _.defaults({
     1848                                                type: 'video'
     1849                                        }, options.library ) )
     1850                                }),
     1851
     1852                                // Video Playlist states.
     1853                                new media.controller.VideoPlaylistEdit({
     1854                                        library: options.selection,
     1855                                        editing: options.editing,
     1856                                        menu:    'video-playlist'
     1857                                }),
     1858
     1859                                new media.controller.VideoPlaylistAdd()
    17711860                        ]);
    17721861
    17731862
     
    17821871                         */
    17831872                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
    17841873                        this.on( 'menu:create:gallery', this.createMenu, this );
     1874                        this.on( 'menu:create:playlist', this.createMenu, this );
     1875                        this.on( 'menu:create:video-playlist', this.createMenu, this );
    17851876                        this.on( 'toolbar:create:main-insert', this.createToolbar, this );
    1786                         this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
     1877                        this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
     1878                        this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
     1879                        this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
    17871880                        this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
    17881881                        this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
    17891882
     
    17901883                        var handlers = {
    17911884                                menu: {
    17921885                                        'default': 'mainMenu',
    1793                                         'gallery': 'galleryMenu'
     1886                                        'gallery': 'galleryMenu',
     1887                                        'playlist': 'playlistMenu',
     1888                                        'video-playlist': 'videoPlaylistMenu'
    17941889                                },
    17951890
    17961891                                content: {
     
    18021897                                        'main-insert':      'mainInsertToolbar',
    18031898                                        'main-gallery':     'mainGalleryToolbar',
    18041899                                        'gallery-edit':     'galleryEditToolbar',
    1805                                         'gallery-add':      'galleryAddToolbar'
     1900                                        'gallery-add':      'galleryAddToolbar',
     1901                                        'main-playlist':        'mainPlaylistToolbar',
     1902                                        'playlist-edit':        'playlistEditToolbar',
     1903                                        'playlist-add':         'playlistAddToolbar',
     1904                                        'main-video-playlist': 'mainVideoPlaylistToolbar',
     1905                                        'video-playlist-edit': 'videoPlaylistEditToolbar',
     1906                                        'video-playlist-add': 'videoPlaylistAddToolbar'
    18061907                                }
    18071908                        };
    18081909
     
    18521953                        });
    18531954                },
    18541955
     1956                playlistMenu: function( view ) {
     1957                        var lastState = this.lastState(),
     1958                                previous = lastState && lastState.id,
     1959                                frame = this;
     1960
     1961                        view.set({
     1962                                cancel: {
     1963                                        text:     l10n.cancelPlaylistTitle,
     1964                                        priority: 20,
     1965                                        click:    function() {
     1966                                                if ( previous )
     1967                                                        frame.setState( previous );
     1968                                                else
     1969                                                        frame.close();
     1970                                        }
     1971                                },
     1972                                separateCancel: new media.View({
     1973                                        className: 'separator',
     1974                                        priority: 60
     1975                                })
     1976                        });
     1977                },
     1978
     1979                videoPlaylistMenu: function( view ) {
     1980                        var lastState = this.lastState(),
     1981                                previous = lastState && lastState.id,
     1982                                frame = this;
     1983
     1984                        view.set({
     1985                                cancel: {
     1986                                        text:     l10n.cancelVideoPlaylistTitle,
     1987                                        priority: 20,
     1988                                        click:    function() {
     1989                                                if ( previous )
     1990                                                        frame.setState( previous );
     1991                                                else
     1992                                                        frame.close();
     1993                                        }
     1994                                },
     1995                                separateCancel: new media.View({
     1996                                        className: 'separator',
     1997                                        priority: 80
     1998                                })
     1999                        });
     2000                },
     2001
    18552002                // Content
    18562003                embedContent: function() {
    18572004                        var view = new media.view.Embed({
     
    19702117                        });
    19712118                },
    19722119
     2120                mainPlaylistToolbar: function( view ) {
     2121                        var controller = this;
     2122
     2123                        this.selectionStatusToolbar( view );
     2124
     2125                        view.set( 'playlist', {
     2126                                style:    'primary',
     2127                                text:     l10n.createNewPlaylist,
     2128                                priority: 100,
     2129                                requires: { selection: true },
     2130
     2131                                click: function() {
     2132                                        var selection = controller.state().get('selection'),
     2133                                                edit = controller.state('playlist-edit'),
     2134                                                models = selection.where({ type: 'audio' });
     2135
     2136                                        edit.set( 'library', new media.model.Selection( models, {
     2137                                                props:    selection.props.toJSON(),
     2138                                                multiple: true
     2139                                        }) );
     2140
     2141                                        this.controller.setState('playlist-edit');
     2142                                }
     2143                        });
     2144                },
     2145
     2146                mainVideoPlaylistToolbar: function( view ) {
     2147                        var controller = this;
     2148
     2149                        this.selectionStatusToolbar( view );
     2150
     2151                        view.set( 'video-playlist', {
     2152                                style:    'primary',
     2153                                text:     l10n.createNewVideoPlaylist,
     2154                                priority: 100,
     2155                                requires: { selection: true },
     2156
     2157                                click: function() {
     2158                                        var selection = controller.state().get('selection'),
     2159                                                edit = controller.state('video-playlist-edit'),
     2160                                                models = selection.where({ type: 'video' });
     2161
     2162                                        edit.set( 'library', new media.model.Selection( models, {
     2163                                                props:    selection.props.toJSON(),
     2164                                                multiple: true
     2165                                        }) );
     2166
     2167                                        this.controller.setState('video-playlist-edit');
     2168                                }
     2169                        });
     2170                },
     2171
    19732172                featuredImageToolbar: function( toolbar ) {
    19742173                        this.createSelectToolbar( toolbar, {
    19752174                                text:  l10n.setFeaturedImage,
     
    20382237                                        }
    20392238                                }
    20402239                        }) );
     2240                },
     2241
     2242                playlistEditToolbar: function() {
     2243                        var editing = this.state().get('editing');
     2244                        this.toolbar.set( new media.view.Toolbar({
     2245                                controller: this,
     2246                                items: {
     2247                                        insert: {
     2248                                                style:    'primary',
     2249                                                text:     editing ? l10n.updatePlaylist : l10n.insertPlaylist,
     2250                                                priority: 80,
     2251                                                requires: { library: true },
     2252
     2253                                                /**
     2254                                                 * @fires wp.media.controller.State#update
     2255                                                 */
     2256                                                click: function() {
     2257                                                        var controller = this.controller,
     2258                                                                state = controller.state();
     2259
     2260                                                        controller.close();
     2261                                                        state.trigger( 'update', state.get('library') );
     2262
     2263                                                        // Restore and reset the default state.
     2264                                                        controller.setState( controller.options.state );
     2265                                                        controller.reset();
     2266                                                }
     2267                                        }
     2268                                }
     2269                        }) );
     2270                },
     2271
     2272                playlistAddToolbar: function() {
     2273                        this.toolbar.set( new media.view.Toolbar({
     2274                                controller: this,
     2275                                items: {
     2276                                        insert: {
     2277                                                style:    'primary',
     2278                                                text:     l10n.addToPlaylist,
     2279                                                priority: 80,
     2280                                                requires: { selection: true },
     2281
     2282                                                /**
     2283                                                 * @fires wp.media.controller.State#reset
     2284                                                 */
     2285                                                click: function() {
     2286                                                        var controller = this.controller,
     2287                                                                state = controller.state(),
     2288                                                                edit = controller.state('playlist-edit');
     2289
     2290                                                        edit.get('library').add( state.get('selection').models );
     2291                                                        state.trigger('reset');
     2292                                                        controller.setState('playlist-edit');
     2293                                                }
     2294                                        }
     2295                                }
     2296                        }) );
     2297                },
     2298
     2299                videoPlaylistEditToolbar: function() {
     2300                        var editing = this.state().get('editing');
     2301                        this.toolbar.set( new media.view.Toolbar({
     2302                                controller: this,
     2303                                items: {
     2304                                        insert: {
     2305                                                style:    'primary',
     2306                                                text:     editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
     2307                                                priority: 140,
     2308                                                requires: { library: true },
     2309
     2310                                                click: function() {
     2311                                                        var controller = this.controller,
     2312                                                                state = controller.state();
     2313
     2314                                                        controller.close();
     2315                                                        state.trigger( 'update', state.get('library') );
     2316
     2317                                                        // Restore and reset the default state.
     2318                                                        controller.setState( controller.options.state );
     2319                                                        controller.reset();
     2320                                                }
     2321                                        }
     2322                                }
     2323                        }) );
     2324                },
     2325
     2326                videoPlaylistAddToolbar: function() {
     2327                        this.toolbar.set( new media.view.Toolbar({
     2328                                controller: this,
     2329                                items: {
     2330                                        insert: {
     2331                                                style:    'primary',
     2332                                                text:     l10n.addToVideoPlaylist,
     2333                                                priority: 140,
     2334                                                requires: { selection: true },
     2335
     2336                                                click: function() {
     2337                                                        var controller = this.controller,
     2338                                                                state = controller.state(),
     2339                                                                edit = controller.state('video-playlist-edit');
     2340
     2341                                                        edit.get('library').add( state.get('selection').models );
     2342                                                        state.trigger('reset');
     2343                                                        controller.setState('video-playlist-edit');
     2344                                                }
     2345                                        }
     2346                                }
     2347                        }) );
    20412348                }
    2042 
    20432349        });
    20442350
    20452351        media.view.MediaFrame.ImageDetails = media.view.MediaFrame.Select.extend({
     
    48645170         * @augments Backbone.View
    48655171         */
    48665172        media.view.Settings.Gallery = media.view.Settings.extend({
    4867                 className: 'gallery-settings',
     5173                className: 'collection-settings gallery-settings',
    48685174                template:  media.template('gallery-settings')
    48695175        });
    48705176
    48715177        /**
     5178         * wp.media.view.Settings.Gallery
     5179         */
     5180        media.view.Settings.Playlist = media.view.Settings.extend({
     5181                className: 'collection-settings playlist-settings',
     5182                template:  media.template('playlist-settings')
     5183        });
     5184
     5185        /**
    48725186         * wp.media.view.Attachment.Details
    48735187         *
    48745188         * @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() {
     
    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.
     
    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

     
    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
     
    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 );
  • 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',