WordPress.org

Make WordPress Core

Ticket #27016: 27016.6.diff

File 27016.6.diff, 36.9 KB (added by wonderboymusic, 6 years ago)
  • src/wp-includes/css/media-views.css

     
    14601460}
    14611461
    14621462.embed-link-settings,
    1463 .embed-image-settings {
     1463.embed-media-settings {
    14641464        position: absolute;
    14651465        top: 60px;
    14661466        left: 0;
     
    14701470        overflow: auto;
    14711471}
    14721472
    1473 .image-details .embed-image-settings {
     1473.image-details .embed-media-settings {
    14741474        top: 0;
    14751475}
    14761476
     
    15231523        margin: 2px 0;
    15241524}
    15251525
    1526 .media-embed .setting input,
     1526.media-embed .setting input[type="text"],
    15271527.media-embed .setting textarea {
    15281528        display: block;
    15291529        width: 100%;
     
    18721872
    18731873        /* Image From Link */
    18741874        .embed-link-settings,
    1875         .embed-image-settings {
     1875        .embed-media-settings {
    18761876                padding-bottom: 52px;
    18771877        }
    18781878
  • src/wp-includes/js/media-editor.js

     
    274274                }
    275275        };
    276276
     277        wp.media.mixin = {
     278                /**
     279                 * A helper function to avoid truthy and falsey values being
     280                 *   passed as an input that expects booleans. If key is undefined in the map,
     281                 *   but has a default value, set it.
     282                 *
     283                 * @param {object} attrs Map of props from a shortcode or settings.
     284                 * @param {string} key The key within the passed map to check for a value.
     285                 * @returns {mixed|undefined} The original or coerced value of key within attrs
     286                 */
     287                coerce: function ( attrs, key ) {
     288                        if ( _.isUndefined( attrs[ key ] ) && ! _.isUndefined( this.defaults[ key ] ) ) {
     289                                attrs[ key ] = this.defaults[ key ];
     290                        } else if ( 'true' === attrs[ key ] ) {
     291                                attrs[ key ] = true;
     292                        } else if ( 'false' === attrs[ key ] ) {
     293                                attrs[ key ] = false;
     294                        }
     295                        return attrs[ key ];
     296                }
     297        };
     298
    277299        wp.media.collection = function(attributes) {
    278300                var collections = {};
    279301
    280                 return _.extend( attributes, {
     302                return _.extend( attributes, wp.media.mixin, {
    281303                        /**
    282                          * A helper function to avoid truthy and falsey values being
    283                          *   passed as an input that expects booleans. If key is undefined in the map,
    284                          *   but has a default value, set it.
    285                          *
    286                          * @param {object} attrs Map of props from a shortcode or settings.
    287                          * @param {string} key The key within the passed map to check for a value.
    288                          * @returns {mixed|undefined} The original or coerced value of key within attrs
    289                          */
    290                         coerce: function ( attrs, key ) {
    291                                 if ( _.isUndefined( attrs[ key ] ) && ! _.isUndefined( this.defaults[ key ] ) ) {
    292                                         attrs[ key ] = this.defaults[ key ];
    293                                 } else if ( 'true' === attrs[ key ] ) {
    294                                         attrs[ key ] = true;
    295                                 } else if ( 'false' === attrs[ key ] ) {
    296                                         attrs[ key ] = false;
    297                                 }
    298                                 return attrs[ key ];
    299                         },
    300                         /**
    301304                         * Retrieve attachments based on the properties of the passed shortcode
    302305                         *
    303306                         * @global wp.media.query
     
    536539                }
    537540        });
    538541
    539         wp.media['video-playlist'] = new wp.media.collection( {
     542        wp.media['video-playlist'] = new wp.media.collection({
    540543                tag: 'video-playlist',
    541544                type : 'video',
    542545                editTitle : wp.media.view.l10n.editVideoPlaylistTitle,
     
    547550                        tracknumbers: false,
    548551                        images: true
    549552                }
    550         } );
     553        });
    551554
     555        wp.media.audio = _.extend({
     556                defaults : {
     557                        id : wp.media.view.settings.post.id,
     558                        src      : '',
     559                        loop     : false,
     560                        autoplay : false,
     561                        preload  : 'none'
     562                },
     563
     564                edit : function (data) {
     565                        var frame, shortcode = wp.shortcode.next( 'audio', data ).shortcode;
     566                        frame = wp.media({
     567                                frame: 'audio',
     568                                state: 'audio-details',
     569                                metadata: _.defaults(
     570                                        shortcode.attrs.named,
     571                                        wp.media.audio.defaults
     572                                )
     573                        });
     574
     575                        return frame;
     576                },
     577
     578                shortcode : function (shortcode) {
     579                        var self = this;
     580
     581                        _.each( wp.media.audio.defaults, function( value, key ) {
     582                                shortcode[ key ] = self.coerce( shortcode, key );
     583
     584                                if ( value === shortcode[ key ] ) {
     585                                        delete shortcode[ key ];
     586                                }
     587                        });
     588
     589                        return wp.shortcode.string({
     590                                tag:     'audio',
     591                                attrs:   shortcode
     592                        });
     593                }
     594        }, wp.media.mixin);
     595
     596        wp.media.video = _.extend({
     597                defaults : {
     598                        id : wp.media.view.settings.post.id,
     599                        src : '',
     600                        poster : '',
     601                        loop : false,
     602                        autoplay : false,
     603                        preload : 'metadata'
     604                },
     605
     606                edit : function (data) {
     607                        var frame, shortcode = wp.shortcode.next( 'video', data ).shortcode;
     608                        frame = wp.media({
     609                                frame: 'video',
     610                                state: 'video-details',
     611                                metadata: _.defaults(
     612                                        shortcode.attrs.named,
     613                                        wp.media.video.defaults
     614                                )
     615                        });
     616
     617                        return frame;
     618                },
     619
     620                shortcode : function (shortcode) {
     621                        var self = this;
     622                        _.each( wp.media.video.defaults, function( value, key ) {
     623                                shortcode[ key ] = self.coerce( shortcode, key );
     624
     625                                if ( value === shortcode[ key ] ) {
     626                                        delete shortcode[ key ];
     627                                }
     628                        });
     629
     630                        return wp.shortcode.string({
     631                                tag:     'video',
     632                                attrs:   shortcode
     633                        });
     634                }
     635        }, wp.media.mixin);
     636
    552637        /**
    553638         * wp.media.featuredImage
    554639         * @namespace
  • src/wp-includes/js/media-models.js

     
    3232                        frame = new MediaFrame.Post( attributes );
    3333                } else if ( 'image' === attributes.frame && MediaFrame.ImageDetails ) {
    3434                        frame = new MediaFrame.ImageDetails( attributes );
     35                } else if ( 'audio' === attributes.frame && MediaFrame.AudioDetails ) {
     36                        frame = new MediaFrame.AudioDetails( attributes );
     37                } else if ( 'video' === attributes.frame && MediaFrame.VideoDetails ) {
     38                        frame = new MediaFrame.VideoDetails( attributes );
    3539                }
    3640
    3741                delete attributes.frame;
     
    448452        });
    449453
    450454        /**
     455         * wp.media.model.PostAudio
     456         *
     457         * @constructor
     458         * @augments Backbone.Model
     459         **/
     460        PostAudio = media.model.PostAudio = Backbone.Model.extend({
     461                initialize: function() {
     462                        this.attachment = false;
     463                },
     464
     465                changeAttachment: function( attachment, props ) {
     466                        var self = this;
     467
     468                        this.attachment = attachment;
     469                        this.extension = attachment.get('filename' ).split('.').pop();
     470
     471                        if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
     472                                this.set( this.extension, attachment.get( 'url' ) );
     473                        } else {
     474                                this.set( this.extension, '' );
     475                        }
     476
     477                        _.each( _.without( wp.media.view.settings.embedExts, this.extension ), function (ext) {
     478                                self.set( ext, '' );
     479                        } );
     480                }
     481        });
     482
     483        /**
     484         * wp.media.model.PostVideo
     485         *
     486         * @constructor
     487         * @augments Backbone.Model
     488         **/
     489        PostVideo = media.model.PostVideo = Backbone.Model.extend({
     490                initialize: function() {
     491                        this.attachment = false;
     492                },
     493
     494                changeAttachment: function( attachment, props ) {
     495                        var self = this;
     496
     497                        this.attachment = attachment;
     498                        this.extension = attachment.get('filename' ).split('.').pop();
     499
     500                        if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
     501                                this.set( this.extension, attachment.get( 'url' ) );
     502                        } else {
     503                                this.set( this.extension, '' );
     504                        }
     505
     506                        _.each( _.without( wp.media.view.settings.embedExts, this.extension ), function (ext) {
     507                                self.set( ext, '' );
     508                        } );
     509                }
     510        });
     511
     512        /**
    451513         * wp.media.model.Attachments
    452514         *
    453515         * @constructor
  • src/wp-includes/js/media-views.js

     
    11/* global _wpMediaViewsL10n, confirm, getUserSetting, setUserSetting */
    2 (function($){
     2(function($, _){
    33        var media = wp.media, l10n;
    44
    55        // Link any localized strings.
     
    760760        });
    761761
    762762        /**
     763         * wp.media.controller.AudioDetails
     764         *
     765         * @constructor
     766         * @augments wp.media.controller.State
     767         * @augments Backbone.Model
     768         */
     769        media.controller.AudioDetails = media.controller.State.extend({
     770                defaults: _.defaults({
     771                        id: 'audio-details',
     772                        toolbar: 'audio-details',
     773                        title: l10n.audioDetailsTitle,
     774                        content: 'audio-details',
     775                        menu: 'audio-details',
     776                        router: false,
     777                        attachment: false,
     778                        priority: 60,
     779                        editing: false
     780                }, media.controller.Library.prototype.defaults ),
     781
     782                initialize: function( options ) {
     783                        this.audio = options.audio;
     784                        media.controller.State.prototype.initialize.apply( this, arguments );
     785                }
     786        });
     787
     788        /**
     789         * wp.media.controller.VideoDetails
     790         *
     791         * @constructor
     792         * @augments wp.media.controller.State
     793         * @augments Backbone.Model
     794         */
     795        media.controller.VideoDetails = media.controller.State.extend({
     796                defaults: _.defaults({
     797                        id: 'video-details',
     798                        toolbar: 'video-details',
     799                        title: l10n.videoDetailsTitle,
     800                        content: 'video-details',
     801                        menu: 'video-details',
     802                        router: false,
     803                        attachment: false,
     804                        priority: 60,
     805                        editing: false
     806                }, media.controller.Library.prototype.defaults ),
     807
     808                initialize: function( options ) {
     809                        this.video = options.video;
     810                        media.controller.State.prototype.initialize.apply( this, arguments );
     811                }
     812        });
     813
     814        /**
    763815         * wp.media.controller.CollectionEdit
    764816         *
    765817         * @constructor
     
    10681120        });
    10691121
    10701122        /**
     1123         * wp.media.controller.ReplaceVideo
     1124         *
     1125         * Replace a selected single video
     1126         *
     1127         * @constructor
     1128         * @augments wp.media.controller.Library
     1129         * @augments wp.media.controller.State
     1130         * @augments Backbone.Model
     1131         */
     1132        media.controller.ReplaceVideo = media.controller.Library.extend({
     1133                defaults: _.defaults({
     1134                        id:         'replace-video',
     1135                        filterable: 'uploaded',
     1136                        multiple:   false,
     1137                        toolbar:    'replace',
     1138                        title:      l10n.replaceVideoTitle,
     1139                        priority:   60,
     1140                        syncSelection: false
     1141                }, media.controller.Library.prototype.defaults ),
     1142
     1143                initialize: function( options ) {
     1144                        var library, comparator;
     1145
     1146                        this.video = options.video;
     1147                        // If we haven't been provided a `library`, create a `Selection`.
     1148                        if ( ! this.get('library') ) {
     1149                                this.set( 'library', media.query({ type: 'video' }) );
     1150                        }
     1151
     1152                        media.controller.Library.prototype.initialize.apply( this, arguments );
     1153
     1154                        library    = this.get('library');
     1155                        comparator = library.comparator;
     1156
     1157                        // Overload the library's comparator to push items that are not in
     1158                        // the mirrored query to the front of the aggregate collection.
     1159                        library.comparator = function( a, b ) {
     1160                                var aInQuery = !! this.mirroring.get( a.cid ),
     1161                                        bInQuery = !! this.mirroring.get( b.cid );
     1162
     1163                                if ( ! aInQuery && bInQuery ) {
     1164                                        return -1;
     1165                                } else if ( aInQuery && ! bInQuery ) {
     1166                                        return 1;
     1167                                } else {
     1168                                        return comparator.apply( this, arguments );
     1169                                }
     1170                        };
     1171
     1172                        // Add all items in the selection to the library, so any featured
     1173                        // images that are not initially loaded still appear.
     1174                        library.observe( this.get('selection') );
     1175                },
     1176
     1177                activate: function() {
     1178                        this.updateSelection();
     1179                        media.controller.Library.prototype.activate.apply( this, arguments );
     1180                },
     1181
     1182                updateSelection: function() {
     1183                        var selection = this.get('selection'),
     1184                                attachment = this.video.attachment;
     1185
     1186                        selection.reset( attachment ? [ attachment ] : [] );
     1187                }
     1188        });
     1189
     1190        /**
     1191         * wp.media.controller.ReplaceAudio
     1192         *
     1193         * Replace a selected single audio file
     1194         *
     1195         * @constructor
     1196         * @augments wp.media.controller.Library
     1197         * @augments wp.media.controller.State
     1198         * @augments Backbone.Model
     1199         */
     1200        media.controller.ReplaceAudio = media.controller.Library.extend({
     1201                defaults: _.defaults({
     1202                        id:         'replace-audio',
     1203                        filterable: 'uploaded',
     1204                        multiple:   false,
     1205                        toolbar:    'replace',
     1206                        title:      l10n.replaceAudioTitle,
     1207                        priority:   60,
     1208                        syncSelection: false
     1209                }, media.controller.Library.prototype.defaults ),
     1210
     1211                initialize: function( options ) {
     1212                        var library, comparator;
     1213
     1214                        this.audio = options.audio;
     1215                        // If we haven't been provided a `library`, create a `Selection`.
     1216                        if ( ! this.get('library') ) {
     1217                                this.set( 'library', media.query({ type: 'audio' }) );
     1218                        }
     1219
     1220                        media.controller.Library.prototype.initialize.apply( this, arguments );
     1221
     1222                        library    = this.get('library');
     1223                        comparator = library.comparator;
     1224
     1225                        // Overload the library's comparator to push items that are not in
     1226                        // the mirrored query to the front of the aggregate collection.
     1227                        library.comparator = function( a, b ) {
     1228                                var aInQuery = !! this.mirroring.get( a.cid ),
     1229                                        bInQuery = !! this.mirroring.get( b.cid );
     1230
     1231                                if ( ! aInQuery && bInQuery ) {
     1232                                        return -1;
     1233                                } else if ( aInQuery && ! bInQuery ) {
     1234                                        return 1;
     1235                                } else {
     1236                                        return comparator.apply( this, arguments );
     1237                                }
     1238                        };
     1239
     1240                        // Add all items in the selection to the library, so any featured
     1241                        // images that are not initially loaded still appear.
     1242                        library.observe( this.get('selection') );
     1243                },
     1244
     1245                activate: function() {
     1246                        this.updateSelection();
     1247                        media.controller.Library.prototype.activate.apply( this, arguments );
     1248                },
     1249
     1250                updateSelection: function() {
     1251                        var selection = this.get('selection'),
     1252                                attachment = this.audio.attachment;
     1253
     1254                        selection.reset( attachment ? [ attachment ] : [] );
     1255                }
     1256        });
     1257
     1258        /**
    10711259         * wp.media.controller.Embed
    10721260         *
    10731261         * @constructor
     
    24612649
    24622650        });
    24632651
     2652        media.view.MediaFrame.AudioDetails = media.view.MediaFrame.Select.extend({
     2653                defaults: {
     2654                        id:      'audio',
     2655                        url:     '',
     2656                        menu:    'audio-details',
     2657                        content: 'audio-details',
     2658                        toolbar: 'audio-details',
     2659                        type:    'link',
     2660                        title:    l10n.audioDetailsTitle,
     2661                        priority: 120
     2662                },
    24642663
     2664                initialize: function( options ) {
     2665                        this.audio = new media.model.PostAudio( options.metadata );
     2666                        this.options.selection = new media.model.Selection( this.audio.attachment, { multiple: false } );
     2667                        media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
     2668                },
     2669
     2670                bindHandlers: function() {
     2671                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
     2672                        this.on( 'menu:create:audio-details', this.createMenu, this );
     2673                        this.on( 'content:render:audio-details', this.renderAudioDetailsContent, this );
     2674                        this.on( 'menu:render:audio-details', this.renderMenu, this );
     2675                        this.on( 'toolbar:render:audio-details', this.renderAudioDetailsToolbar, this );
     2676                        // override the select toolbar
     2677                        this.on( 'toolbar:render:replace', this.renderReplaceAudioToolbar, this );
     2678                },
     2679
     2680                createStates: function() {
     2681                        this.states.add([
     2682                                new media.controller.AudioDetails({
     2683                                        audio: this.audio,
     2684                                        editable: false,
     2685                                        menu: 'audio-details'
     2686                                }),
     2687                                new media.controller.ReplaceAudio({
     2688                                        id: 'replace-audio',
     2689                                        library:   media.query( { type: 'audio' } ),
     2690                                        audio: this.audio,
     2691                                        multiple:  false,
     2692                                        title:     l10n.audioReplaceTitle,
     2693                                        menu: 'audio-details',
     2694                                        toolbar: 'replace',
     2695                                        priority:  80,
     2696                                        displaySettings: true
     2697                                })
     2698                        ]);
     2699                },
     2700
     2701                renderAudioDetailsContent: function() {
     2702                        var view = new media.view.AudioDetails({
     2703                                controller: this,
     2704                                model: this.state().audio,
     2705                                attachment: this.state().audio.attachment
     2706                        }).render();
     2707
     2708                        this.content.set( view );
     2709                },
     2710
     2711                renderMenu: function( view ) {
     2712                        var lastState = this.lastState(),
     2713                                previous = lastState && lastState.id,
     2714                                frame = this;
     2715
     2716                        view.set({
     2717                                cancel: {
     2718                                        text:     l10n.audioDetailsCancel,
     2719                                        priority: 20,
     2720                                        click:    function() {
     2721                                                if ( previous ) {
     2722                                                        frame.setState( previous );
     2723                                                } else {
     2724                                                        frame.close();
     2725                                                }
     2726                                        }
     2727                                },
     2728                                separateCancel: new media.View({
     2729                                        className: 'separator',
     2730                                        priority: 40
     2731                                })
     2732                        });
     2733
     2734                },
     2735
     2736                renderAudioDetailsToolbar: function() {
     2737                        this.toolbar.set( new media.view.Toolbar({
     2738                                controller: this,
     2739                                items: {
     2740                                        select: {
     2741                                                style:    'primary',
     2742                                                text:     l10n.update,
     2743                                                priority: 80,
     2744
     2745                                                click: function() {
     2746                                                        var controller = this.controller,
     2747                                                                state = controller.state();
     2748
     2749                                                        controller.close();
     2750
     2751                                                        // not sure if we want to use wp.media.string.image which will create a shortcode or
     2752                                                        // perhaps wp.html.string to at least to build the <img />
     2753                                                        state.trigger( 'update', controller.audio.toJSON() );
     2754
     2755                                                        // Restore and reset the default state.
     2756                                                        controller.setState( controller.options.state );
     2757                                                        controller.reset();
     2758                                                }
     2759                                        }
     2760                                }
     2761                        }) );
     2762                },
     2763
     2764                renderReplaceAudioToolbar: function() {
     2765                        this.toolbar.set( new media.view.Toolbar({
     2766                                controller: this,
     2767                                items: {
     2768                                        replace: {
     2769                                                style:    'primary',
     2770                                                text:     l10n.replace,
     2771                                                priority: 80,
     2772
     2773                                                click: function() {
     2774                                                        var controller = this.controller,
     2775                                                                state = controller.state(),
     2776                                                                selection = state.get( 'selection' ),
     2777                                                                attachment = selection.single();
     2778
     2779                                                        controller.audio.changeAttachment( attachment, state.display( attachment ) );
     2780
     2781                                                        // not sure if we want to use wp.media.string.image which will create a shortcode or
     2782                                                        // perhaps wp.html.string to at least to build the <img />
     2783                                                        state.trigger( 'replace', controller.audio.toJSON() );
     2784
     2785                                                        // Restore and reset the default state.
     2786                                                        controller.setState( controller.options.state );
     2787                                                        controller.reset();
     2788                                                }
     2789                                        }
     2790                                }
     2791                        }) );
     2792                }
     2793        });
     2794
     2795        media.view.MediaFrame.VideoDetails = media.view.MediaFrame.Select.extend({
     2796                defaults: {
     2797                        id:      'video',
     2798                        url:     '',
     2799                        menu:    'video-details',
     2800                        content: 'video-details',
     2801                        toolbar: 'video-details',
     2802                        type:    'link',
     2803                        title:    l10n.videoDetailsTitle,
     2804                        priority: 120
     2805                },
     2806
     2807                initialize: function( options ) {
     2808                        this.video = new media.model.PostVideo( options.metadata );
     2809                        this.options.selection = new media.model.Selection( this.video.attachment, { multiple: false } );
     2810                        media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
     2811                },
     2812
     2813                bindHandlers: function() {
     2814                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
     2815                        this.on( 'menu:create:video-details', this.createMenu, this );
     2816                        this.on( 'content:render:video-details', this.renderVideoDetailsContent, this );
     2817                        this.on( 'menu:render:video-details', this.renderMenu, this );
     2818                        this.on( 'toolbar:render:video-details', this.renderVideoDetailsToolbar, this );
     2819                        // override the select toolbar
     2820                        this.on( 'toolbar:render:replace', this.renderReplaceVideoToolbar, this );
     2821                },
     2822
     2823                createStates: function() {
     2824                        this.states.add([
     2825                                new media.controller.VideoDetails({
     2826                                        video: this.video,
     2827                                        editable: false,
     2828                                        menu: 'video-details'
     2829                                }),
     2830                                new media.controller.ReplaceVideo({
     2831                                        id: 'replace-video',
     2832                                        library:   media.query( { type: 'video' } ),
     2833                                        video: this.video,
     2834                                        multiple:  false,
     2835                                        title:     l10n.videoReplaceTitle,
     2836                                        menu: 'video-details',
     2837                                        toolbar: 'replace',
     2838                                        priority:  80,
     2839                                        displaySettings: true
     2840                                })
     2841                        ]);
     2842                },
     2843
     2844                renderVideoDetailsContent: function() {
     2845                        var view = new media.view.VideoDetails({
     2846                                controller: this,
     2847                                model: this.state().video,
     2848                                attachment: this.state().video.attachment
     2849                        }).render();
     2850
     2851                        this.content.set( view );
     2852                },
     2853
     2854                renderMenu: function( view ) {
     2855                        var lastState = this.lastState(),
     2856                                previous = lastState && lastState.id,
     2857                                frame = this;
     2858
     2859                        view.set({
     2860                                cancel: {
     2861                                        text:     l10n.videoDetailsCancel,
     2862                                        priority: 20,
     2863                                        click:    function() {
     2864                                                if ( previous ) {
     2865                                                        frame.setState( previous );
     2866                                                } else {
     2867                                                        frame.close();
     2868                                                }
     2869                                        }
     2870                                },
     2871                                separateCancel: new media.View({
     2872                                        className: 'separator',
     2873                                        priority: 40
     2874                                })
     2875                        });
     2876
     2877                },
     2878
     2879                renderVideoDetailsToolbar: function() {
     2880                        this.toolbar.set( new media.view.Toolbar({
     2881                                controller: this,
     2882                                items: {
     2883                                        select: {
     2884                                                style:    'primary',
     2885                                                text:     l10n.update,
     2886                                                priority: 80,
     2887
     2888                                                click: function() {
     2889                                                        var controller = this.controller,
     2890                                                                state = controller.state();
     2891
     2892                                                        controller.close();
     2893
     2894                                                        // not sure if we want to use wp.media.string.image which will create a shortcode or
     2895                                                        // perhaps wp.html.string to at least to build the <img />
     2896                                                        state.trigger( 'update', controller.video.toJSON() );
     2897
     2898                                                        // Restore and reset the default state.
     2899                                                        controller.setState( controller.options.state );
     2900                                                        controller.reset();
     2901                                                }
     2902                                        }
     2903                                }
     2904                        }) );
     2905                },
     2906
     2907                renderReplaceVideoToolbar: function() {
     2908                        this.toolbar.set( new media.view.Toolbar({
     2909                                controller: this,
     2910                                items: {
     2911                                        replace: {
     2912                                                style:    'primary',
     2913                                                text:     l10n.replace,
     2914                                                priority: 80,
     2915
     2916                                                click: function() {
     2917                                                        var controller = this.controller,
     2918                                                                state = controller.state(),
     2919                                                                selection = state.get( 'selection' ),
     2920                                                                attachment = selection.single();
     2921
     2922                                                        controller.video.changeAttachment( attachment, state.display( attachment ) );
     2923
     2924                                                        state.trigger( 'replace', controller.video.toJSON() );
     2925
     2926                                                        // Restore and reset the default state.
     2927                                                        controller.setState( controller.options.state );
     2928                                                        controller.reset();
     2929                                                }
     2930                                        }
     2931                                }
     2932                        }) );
     2933                }
     2934        });
     2935
    24652936        /**
    24662937         * wp.media.view.Modal
    24672938         *
     
    56056076         * @augments Backbone.View
    56066077         */
    56076078        media.view.EmbedImage =  media.view.Settings.AttachmentDisplay.extend({
    5608                 className: 'embed-image-settings',
     6079                className: 'embed-media-settings',
    56096080                template:  media.template('embed-image-settings'),
    56106081
    56116082                initialize: function() {
     
    56666137                        this.$( '.embed-image-settings' ).scrollTop( 0 );
    56676138                }
    56686139        });
    5669 }(jQuery));
     6140
     6141        media.view.AudioDetails = media.view.Settings.AttachmentDisplay.extend({
     6142                className: 'audio-details',
     6143                template:  media.template('audio-details'),
     6144
     6145                initialize: function() {
     6146                        _.bindAll(this, 'player', 'close');
     6147
     6148                        this.listenTo( this.controller, 'close', this.close );
     6149
     6150                        // used in AttachmentDisplay.prototype.updateLinkTo
     6151                        this.options.attachment = this.model.attachment;
     6152                        media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
     6153                },
     6154
     6155                prepare: function() {
     6156                        var attachment = false;
     6157
     6158                        if ( this.model.attachment ) {
     6159                                attachment = this.model.attachment.toJSON();
     6160                        }
     6161                        return _.defaults({
     6162                                model: this.model.toJSON(),
     6163                                attachment: attachment
     6164                        }, this.options );
     6165                },
     6166
     6167                close : function() {
     6168                        this.mejs.pause();
     6169                        this.remove();
     6170                        delete this.mejs;
     6171                        delete this.mejsInstance;
     6172                },
     6173
     6174                player : function (mejs) {
     6175                        this.mejs = mejs;
     6176                },
     6177
     6178                render: function() {
     6179                        var self = this, settings = {
     6180                                success : this.player
     6181                        };
     6182
     6183                        if ( ! _.isUndefined( window._wpmejsSettings ) ) {
     6184                                settings.pluginPath = _wpmejsSettings.pluginPath;
     6185                        }
     6186
     6187                        media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments );
     6188                        setTimeout( function() { self.resetFocus(); }, 10 );
     6189
     6190                        this.mejsInstance = new MediaElementPlayer( this.$('audio').get(0), settings );
     6191
     6192                        return this;
     6193                },
     6194
     6195                resetFocus: function() {
     6196                        this.$( '.embed-media-settings' ).scrollTop( 0 );
     6197                }
     6198        });
     6199
     6200        media.view.VideoDetails = media.view.Settings.AttachmentDisplay.extend({
     6201                className: 'video-details',
     6202                template:  media.template('video-details'),
     6203
     6204                initialize: function() {
     6205                        _.bindAll(this, 'player', 'played');
     6206
     6207                        this.removable = false;
     6208                        this.listenTo( this.controller, 'close', this.close );
     6209
     6210                        // used in AttachmentDisplay.prototype.updateLinkTo
     6211                        this.options.attachment = this.model.attachment;
     6212                        media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
     6213                },
     6214
     6215                prepare: function() {
     6216                        var attachment = false;
     6217
     6218                        if ( this.model.attachment ) {
     6219                                attachment = this.model.attachment.toJSON();
     6220                        }
     6221                        return _.defaults({
     6222                                model: this.model.toJSON(),
     6223                                attachment: attachment
     6224                        }, this.options );
     6225                },
     6226
     6227                close : function() {
     6228                        if ( this.removable ) {
     6229                                this.mejs.pause();
     6230                        }
     6231                        this.remove();
     6232                        this.mejs = this.mejsInstance = null;
     6233                },
     6234
     6235                played : function () {
     6236                        this.removable = true;
     6237                },
     6238
     6239                player : function (mejs) {
     6240                        this.mejs = mejs;
     6241                        this.mejs.addEventListener( 'play', this.played );
     6242                },
     6243
     6244                render: function() {
     6245                        var self = this, settings = {
     6246                                success : this.player
     6247                        };
     6248
     6249                        if ( ! _.isUndefined( window._wpmejsSettings ) ) {
     6250                                settings.pluginPath = _wpmejsSettings.pluginPath;
     6251                        }
     6252
     6253                        media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments );
     6254                        setTimeout( function() { self.resetFocus(); }, 10 );
     6255
     6256                        if ( ! this.mejsInstance ) {
     6257                                this.mejsInstance = new MediaElementPlayer( this.$('video').get(0), settings );
     6258                        }
     6259
     6260                        return this;
     6261                },
     6262
     6263                resetFocus: function() {
     6264                        this.$( '.embed-media-settings' ).scrollTop( 0 );
     6265                }
     6266        });
     6267}(jQuery, _));
  • src/wp-includes/js/mediaelement/wp-mediaelement.css

     
    1414        width: auto !important;
    1515}
    1616
     17.audio-details .wp-audio-shortcode {
     18        display: inline-block;
     19        max-width: 400px;
     20}
     21
     22.video-details .embed-video-settings,
     23.audio-details .embed-audio-settings {
     24        top: 10px;
     25}
     26
     27.video-details .embed-video-settings .checkbox-setting,
     28.audio-details .embed-audio-settings .checkbox-setting {
     29        width: 100px;
     30        clear: none;
     31}
     32
     33.video-details .wp-video-holder {
     34        width: 100%;
     35        max-width: 640px;
     36}
     37
    1738.wp-playlist {
    1839        border: 1px solid #ccc;
    1940        padding: 10px;
  • src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js

     
    5353        }
    5454
    5555        function editMedia( node ) {
    56                 var gallery, frame, data;
     56                var gallery, frame, data, shortcode;
    5757
    5858                if ( node.nodeName !== 'IMG' ) {
    5959                        return;
     
    6464                        return;
    6565                }
    6666
     67                data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
     68
    6769                // Make sure we've selected a gallery node.
    6870                if ( editor.dom.hasClass( node, 'wp-gallery' ) && wp.media.gallery ) {
    6971                        gallery = wp.media.gallery;
    70                         data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
    7172                        frame = gallery.edit( data );
    7273
    7374                        frame.state('gallery-edit').on( 'update', function( selection ) {
     
    7677                                frame.detach();
    7778                        });
    7879                } else if ( editor.dom.hasClass( node, 'wp-playlist' ) && wp.media.playlist ) {
    79                         data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
    8080                        frame = wp.media.playlist.edit( data );
    8181
    8282                        frame.state('playlist-edit').on( 'update', function( selection ) {
     
    8585                                frame.detach();
    8686                        });
    8787                } else if ( editor.dom.hasClass( node, 'wp-video-playlist' ) && wp.media['video-playlist'] ) {
    88                         data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
    8988                        frame = wp.media['video-playlist'].edit( data );
    9089
    9190                        frame.state('video-playlist-edit').on( 'update', function( selection ) {
     
    9392                                editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
    9493                                frame.detach();
    9594                        });
     95                } else if ( editor.dom.hasClass( node, 'wp-video' ) ) {
     96                        frame = wp.media.video.edit( data );
     97                        frame.state( 'video-details' ).on( 'update replace', function ( selection ) {
     98                                var shortcode = wp.media.video.shortcode( selection );
     99                                editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
     100                        } );
     101                        frame.open();
     102                } else if ( editor.dom.hasClass( node, 'wp-audio' ) ) {
     103                        frame = wp.media.audio.edit( data );
     104                        frame.state( 'audio-details' ).on( 'update replace', function ( selection ) {
     105                                var shortcode = wp.media.audio.shortcode( selection );
     106                                editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
     107                        } );
     108                        frame.open();
    96109                } else {
    97110                        // temp
    98                         window.console && window.console.log( 'Edit AV shortcode ' + window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) ) );
     111                        window.console && window.console.log( 'Edit AV shortcode ' + data );
    99112                }
    100113        }
    101114
  • src/wp-includes/media-template.php

     
    555555        <script type="text/html" id="tmpl-image-details">
    556556                <?php // reusing .media-embed to pick up the styles for now ?>
    557557                <div class="media-embed">
    558                         <div class="embed-image-settings">
     558                        <div class="embed-media-settings">
    559559                                <div class="thumbnail">
    560560                                        <img src="{{ data.model.url }}" draggable="false" />
    561561                                </div>
     
    648648                        </div>
    649649                </div>
    650650        </script>
     651
     652        <script type="text/html" id="tmpl-audio-details">
     653                <?php // reusing .media-embed to pick up the styles for now ?>
     654                <# var rendered = false; #>
     655                <div class="media-embed">
     656                        <div class="embed-media-settings embed-audio-settings">
     657                                <# if ( data.model.src ) { #>
     658                                        <audio class="wp-audio-shortcode" src="{{{ data.model.src }}}"
     659                                                preload="{{{ _.isUndefined( data.model.preload ) ? 'none' : data.model.preload }}}"
     660                                                <# if ( ! _.isUndefined( data.model.autoplay ) && data.model.autoplay ) { #>autoplay<# } #>
     661                                                <# if ( ! _.isUndefined( data.model.loop ) && data.model.loop ) { #>loop<# } #>
     662                                        />
     663                                        <# rendered = true; #>
     664                                <label class="setting">
     665                                        <span>SRC</span>
     666                                        <input type="text" disabled="disabled" data-setting="src" value="{{{ data.model.src }}}" />
     667                                </label>
     668                                <# } #>
     669                                <?php
     670                                $default_types = wp_get_audio_extensions();
     671
     672                                foreach ( $default_types as $type ): ?>
     673                                <# if ( data.model.<?php echo $type ?> ) { #>
     674                                        <# if ( ! rendered ) { #>
     675                                        <audio class="wp-audio-shortcode" src="{{{ data.model.<?php echo $type ?> }}}"
     676                                                preload="{{{ _.isUndefined( data.model.preload ) ? 'none' : data.model.preload }}}"
     677                                                <# if ( ! _.isUndefined( data.model.autoplay ) && data.model.autoplay ) { #>autoplay<# } #>
     678                                                <# if ( ! _.isUndefined( data.model.loop ) && data.model.loop ) { #>loop<# } #>
     679                                        />
     680                                        <#
     681                                                rendered = true;
     682                                        } #>
     683                                <label class="setting">
     684                                        <span><?php echo strtoupper( $type ) ?></span>
     685                                        <input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{{ data.model.<?php echo $type ?> }}}" />
     686                                </label>
     687                                <# } #>
     688                                <?php endforeach ?>
     689
     690                                <div class="setting preload">
     691                                        <span><?php _e( 'Preload' ); ?></span>
     692                                        <div class="button-group button-large" data-setting="preload">
     693                                                <button class="button" value="auto">
     694                                                        <?php esc_attr_e( 'Auto' ); ?>
     695                                                </button>
     696                                                <button class="button" value="metadata">
     697                                                        <?php esc_attr_e( 'Metadata' ); ?>
     698                                                </button>
     699                                                <button class="button active" value="none">
     700                                                        <?php esc_attr_e( 'None' ); ?>
     701                                                </button>
     702                                        </div>
     703                                </div>
     704
     705                                <label class="setting checkbox-setting">
     706                                        <span><?php _e( 'Autoplay' ); ?></span>
     707                                        <input type="checkbox" data-setting="autoplay" />
     708                                </label>
     709
     710                                <label class="setting checkbox-setting">
     711                                        <span><?php _e( 'Loop' ); ?></span>
     712                                        <input type="checkbox" data-setting="loop" />
     713                                </label>
     714                                <div class="clear"></div>
     715                        </div>
     716                </div>
     717        </script>
     718
     719        <script type="text/html" id="tmpl-video-details">
     720                <?php // reusing .media-embed to pick up the styles for now ?>
     721                <# var rendered = false; #>
     722                <div class="media-embed">
     723                        <div class="embed-media-settings embed-video-settings">
     724                                <div class="wp-video-holder">
     725                                <#
     726                                var w = ! data.model.width || data.model.width > 640 ? 640 : data.model.width,
     727                                        h = ! data.model.height ? 320 : data.model.height;
     728
     729                                if ( w !== data.model.width ) {
     730                                        h = Math.ceil( ( h * w ) / data.model.width );
     731                                }
     732
     733                                if ( data.model.src ) { #>
     734                                        <video class="wp-video-shortcode"
     735                                                width="{{{ w }}}"
     736                                                height="{{{ h }}}"
     737                                                src="{{{ data.model.src }}}"
     738                                                <# if ( ! _.isUndefined( data.model.poster ) ) { #>poster="{{{ data.model.poster }}}"<# } #>
     739                                                preload="{{{ _.isUndefined( data.model.preload ) ? 'metadata' : data.model.preload }}}"
     740                                                <# if ( ! _.isUndefined( data.model.autoplay ) && data.model.autoplay ) { #>autoplay<# } #>
     741                                                <# if ( ! _.isUndefined( data.model.loop ) && data.model.loop ) { #>loop<# } #>
     742                                        />
     743                                        <# rendered = true; #>
     744                                <label class="setting">
     745                                        <span>SRC</span>
     746                                        <input type="text" disabled="disabled" data-setting="src" value="{{{ data.model.src }}}" />
     747                                </label>
     748                                <# } #>
     749                                <?php
     750                                $default_types = wp_get_video_extensions();
     751
     752                                foreach ( $default_types as $type ): ?>
     753                                <# if ( data.model.<?php echo $type ?> ) { #>
     754                                        <# if ( ! rendered ) { #>
     755                                        <video class="wp-video-shortcode"
     756                                                width="{{{ w }}}"
     757                                                height="{{{ h }}}"
     758                                                src="{{{ data.model.<?php echo $type ?> }}}"
     759                                                <# if ( ! _.isUndefined( data.model.poster ) ) { #>poster="{{{ data.model.poster }}}"<# } #>
     760                                                preload="{{{ _.isUndefined( data.model.preload ) ? 'metadata' : data.model.preload }}}"
     761                                                <# if ( ! _.isUndefined( data.model.autoplay ) && data.model.autoplay ) { #>autoplay<# } #>
     762                                                <# if ( ! _.isUndefined( data.model.loop ) && data.model.loop ) { #>loop<# } #>
     763                                        />
     764                                        <#
     765                                                rendered = true;
     766                                        } #>
     767                                <label class="setting">
     768                                        <span><?php echo strtoupper( $type ) ?></span>
     769                                        <input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{{ data.model.<?php echo $type ?> }}}" />
     770                                </label>
     771                                <# } #>
     772                                <?php endforeach ?>
     773                                </div>
     774                                <label class="setting">
     775                                        <span><?php _e( 'Poster Image' ); ?></span>
     776                                        <input type="text" data-setting="poster" value="{{{ data.model.poster }}}" />
     777                                </label>
     778                                <div class="setting preload">
     779                                        <span><?php _e( 'Preload' ); ?></span>
     780                                        <div class="button-group button-large" data-setting="preload">
     781                                                <button class="button" value="auto">
     782                                                        <?php esc_attr_e( 'Auto' ); ?>
     783                                                </button>
     784                                                <button class="button" value="metadata">
     785                                                        <?php esc_attr_e( 'Metadata' ); ?>
     786                                                </button>
     787                                                <button class="button active" value="none">
     788                                                        <?php esc_attr_e( 'None' ); ?>
     789                                                </button>
     790                                        </div>
     791                                </div>
     792
     793                                <label class="setting checkbox-setting">
     794                                        <span><?php _e( 'Autoplay' ); ?></span>
     795                                        <input type="checkbox" data-setting="autoplay" />
     796                                </label>
     797
     798                                <label class="setting checkbox-setting">
     799                                        <span><?php _e( 'Loop' ); ?></span>
     800                                        <input type="checkbox" data-setting="loop" />
     801                                </label>
     802                                <div class="clear"></div>
     803                        </div>
     804                </div>
     805        </script>
    651806        <?php
    652807
    653808                //TODO: do we want to deal with the fact that the elements used for gallery items are filterable and can be overriden via shortcode attributes
  • src/wp-includes/media.php

     
    23812381                'imageReplaceTitle'     => __( 'Replace Image' ),
    23822382                'imageDetailsCancel'    => __( 'Cancel Edit' ),
    23832383
     2384                // Edit Image
     2385                'audioDetailsTitle'     => __( 'Audio Details' ),
     2386                'audioReplaceTitle'     => __( 'Replace Audio' ),
     2387                'audioDetailsCancel'    => __( 'Cancel Edit' ),
     2388
     2389                // Edit Image
     2390                'videoDetailsTitle'     => __( 'Video Details' ),
     2391                'videoReplaceTitle'     => __( 'Replace Video' ),
     2392                'videoDetailsCancel'    => __( 'Cancel Edit' ),
     2393
    23842394                // Playlist
    23852395                'playlistDragInfo'    => __( 'Drag and drop to reorder tracks.' ),
    23862396                'createPlaylistTitle' => __( 'Create Playlist' ),
  • src/wp-includes/script-loader.php

     
    389389
    390390        // To enqueue media-views or media-editor, call wp_enqueue_media().
    391391        // Both rely on numerous settings, styles, and templates to operate correctly.
    392         $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable' ), false, 1 );
     392        $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement' ), false, 1 );
    393393        $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
    394394        $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 );
    395395
     
    614614        $styles->add( 'admin-bar',      "/wp-includes/css/admin-bar$suffix.css", array( 'open-sans', 'dashicons' ) );
    615615        $styles->add( 'wp-auth-check',  "/wp-includes/css/wp-auth-check$suffix.css", array( 'dashicons' ) );
    616616        $styles->add( 'editor-buttons', "/wp-includes/css/editor$suffix.css", array( 'dashicons' ) );
    617         $styles->add( 'media-views',    "/wp-includes/css/media-views$suffix.css", array( 'buttons', 'dashicons' ) );
     617        $styles->add( 'media-views',    "/wp-includes/css/media-views$suffix.css", array( 'buttons', 'dashicons', 'wp-mediaelement' ) );
    618618        $styles->add( 'wp-pointer',     "/wp-includes/css/wp-pointer$suffix.css", array( 'dashicons' ) );
    619619
    620620        // External libraries and friends