WordPress.org

Make WordPress Core

Changeset 27411


Ignore:
Timestamp:
03/05/2014 03:06:00 PM (4 years ago)
Author:
wonderboymusic
Message:

Add TinyMCE placeholders for audio and video shortcodes.

  • Add wp.media.mixin.
  • Add wp.media.audio and wp.media.video.
  • Add wp.media.model.PostAudio and wp.media.model.PostVideo
  • Add wp.media.controller.AudioDetails and wp.media.controller.VideoDetails.
  • Add wp.media.controller.ReplaceAudio and wp.media.controller.ReplaceVideo.
  • Add wp.media.view.MediaFrame.AudioDetails and wp.media.view.MediaFrame.VideoDetails.
  • Add wp.media.view.AudioDetails and wp.media.view.VideoDetails.
  • Update the wpgallery TinyMCE plugin.
  • Display audio and video players in the media modal when shortcode is clicked.
  • Provide a UI to edit shortcode attributes in the media modal.
  • Provide a UI to replace the src media file in an audio or video shortcode.

See #27016.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/css/media-views.css

    r27289 r27411  
    14611461
    14621462.embed-link-settings,
    1463 .embed-image-settings {
     1463.embed-media-settings {
    14641464    position: absolute;
    14651465    top: 60px;
     
    14711471}
    14721472
    1473 .image-details .embed-image-settings {
     1473.image-details .embed-media-settings {
    14741474    top: 0;
    14751475}
     
    15241524}
    15251525
    1526 .media-embed .setting input,
     1526.media-embed .setting input[type="text"],
    15271527.media-embed .setting textarea {
    15281528    display: block;
     
    18731873    /* Image From Link */
    18741874    .embed-link-settings,
    1875     .embed-image-settings {
     1875    .embed-media-settings {
    18761876        padding-bottom: 52px;
    18771877    }
  • trunk/src/wp-includes/js/media-editor.js

    r27343 r27411  
    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, {
    281             /**
    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             },
     302        return _.extend( attributes, wp.media.mixin, {
    300303            /**
    301304             * Retrieve attachments based on the properties of the passed shortcode
     
    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',
     
    548551            images: true
    549552        }
    550     } );
     553    });
     554
     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);
    551636
    552637    /**
  • trunk/src/wp-includes/js/media-models.js

    r27051 r27411  
    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
     
    445449            this.set( 'width', size.width );
    446450            this.set( 'height', size.height );
     451        }
     452    });
     453
     454    /**
     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            } );
    447509        }
    448510    });
  • trunk/src/wp-includes/js/media-views.js

    r27378 r27411  
    11/* global _wpMediaViewsL10n, confirm, getUserSetting, setUserSetting */
    2 (function($){
     2(function($, _){
    33    var media = wp.media, l10n;
    44
     
    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     *
     
    10631115            var selection = this.get('selection'),
    10641116                attachment = this.image.attachment;
     1117
     1118            selection.reset( attachment ? [ attachment ] : [] );
     1119        }
     1120    });
     1121
     1122    /**
     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;
    10651253
    10661254            selection.reset( attachment ? [ attachment ] : [] );
     
    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        },
     2663
     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    });
    24642935
    24652936    /**
     
    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
     
    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, _));
  • trunk/src/wp-includes/js/mediaelement/wp-mediaelement.css

    r27239 r27411  
    1313.me-cannotplay {
    1414    width: auto !important;
     15}
     16
     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;
    1536}
    1637
  • trunk/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js

    r27408 r27411  
    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
     
    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
     
    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
     
    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    }
  • trunk/src/wp-includes/media-template.php

    r27408 r27411  
    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" />
     
    646646                    </div>
    647647                <# } #>
     648            </div>
     649        </div>
     650    </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>
    648803            </div>
    649804        </div>
  • trunk/src/wp-includes/media.php

    r27404 r27411  
    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.' ),
  • trunk/src/wp-includes/script-loader.php

    r27403 r27411  
    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 );
     
    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
Note: See TracChangeset for help on using the changeset viewer.