Make WordPress Core

Ticket #28458: 28458.diff

File 28458.diff, 18.0 KB (added by wonderboymusic, 10 years ago)
  • src/wp-includes/js/mce-view.js

     
    2222         *
    2323         * A Backbone-like View constructor intended for use when rendering a TinyMCE View. The main difference is
    2424         * that the TinyMCE View is not tied to a particular DOM node.
     25         *
     26         * @param {Object} [options={}]
    2527         */
    2628        wp.mce.View = function( options ) {
    27                 options || (options = {});
    28                 _.extend(this, _.pick(options, viewOptions));
    29                 this.initialize.apply(this, arguments);
     29                options = options || {};
     30                _.extend( this, _.pick( options, viewOptions ) );
     31                this.initialize.apply( this, arguments );
    3032        };
    3133
    3234        _.extend( wp.mce.View.prototype, {
     
    3638                        var html = this.getHtml();
    3739                        // Search all tinymce editor instances and update the placeholders
    3840                        _.each( tinymce.editors, function( editor ) {
    39                                 var doc, self = this;
     41                                var self = this;
    4042                                if ( editor.plugins.wpview ) {
    41                                         doc = editor.getDoc();
    42                                         $( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each(function (i, elem) {
    43                                                 var node = $( elem );
     43                                        $( editor.getDoc() ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each( function ( i, element ) {
     44                                                var node = $( element );
    4445                                                // The <ins> is used to mark the end of the wrapper div. Needed when comparing
    4546                                                // the content as string for preventing extra undo levels.
    4647                                                node.html( html ).append( '<ins data-wpview-end="1"></ins>' );
    47                                                 $( self ).trigger( 'ready', elem );
     48                                                $( self ).trigger( 'ready', element );
    4849                                        });
    4950                                }
    5051                        }, this );
     
    7475                 *
    7576                 */
    7677                register: function( type, constructor ) {
     78                        var defaultConstructor = {
     79                                        type: type,
     80                                        View: {},
     81                                        toView: function( content ) {
     82                                                var match = wp.shortcode.next( this.type, content );
     83
     84                                                if ( ! match ) {
     85                                                        return;
     86                                                }
     87
     88                                                return {
     89                                                        index: match.index,
     90                                                        content: match.content,
     91                                                        options: {
     92                                                                shortcode: match.shortcode
     93                                                        }
     94                                                };
     95                                        }
     96                                };
     97
     98                        constructor = _.defaults( constructor, defaultConstructor );
     99                        constructor.View = wp.mce.View.extend( constructor.View );
     100
    77101                        views[ type ] = constructor;
    78102                },
    79103
     
    81105                 * wp.mce.views.get( id )
    82106                 *
    83107                 * Returns a TinyMCE view constructor.
     108                 *
     109                 * @param type
    84110                 */
    85111                get: function( type ) {
    86112                        return views[ type ];
     
    90116                 * wp.mce.views.unregister( type )
    91117                 *
    92118                 * Unregisters a TinyMCE view.
     119                 *
     120                 * @param type
    93121                 */
    94122                unregister: function( type ) {
    95123                        delete views[ type ];
     
    112140                 * matches with wrapper elements, and creates a new instance for
    113141                 * every match, which triggers the related data to be fetched.
    114142                 *
     143                 * @param content
    115144                 */
    116145                toViews: function( content ) {
    117146                        var pieces = [ { content: content } ],
     
    252281                }
    253282        };
    254283
    255         wp.mce.gallery = {
    256                 shortcode: 'gallery',
    257                 toView:  function( content ) {
    258                         var match = wp.shortcode.next( this.shortcode, content );
     284        wp.mce.views.register( 'gallery', {
     285                View: {
     286                        template: media.template( 'editor-gallery' ),
    259287
    260                         if ( ! match ) {
    261                                 return;
    262                         }
    263 
    264                         return {
    265                                 index:   match.index,
    266                                 content: match.content,
    267                                 options: {
    268                                         shortcode: match.shortcode
    269                                 }
    270                         };
    271                 },
    272                 View: wp.mce.View.extend({
    273                         className: 'editor-gallery',
    274                         template:  media.template('editor-gallery'),
    275 
    276288                        // The fallback post ID to use as a parent for galleries that don't
    277289                        // specify the `ids` or `include` parameters.
    278290                        //
     
    321333                                return this.template( options );
    322334
    323335                        }
    324                 }),
     336                },
    325337
    326338                edit: function( node ) {
    327339                        var gallery = wp.media.gallery,
     
    338350                                frame.detach();
    339351                        });
    340352                }
     353        } );
    341354
    342         };
    343         wp.mce.views.register( 'gallery', wp.mce.gallery );
    344 
    345355        /**
    346          * Tiny MCE Views for Audio / Video
     356         * These are base methods that are shared by the audio and video shortcode's MCE controller.
    347357         *
    348          */
    349 
    350         /**
    351          * These are base methods that are shared by each shortcode's MCE controller
    352          *
    353358         * @mixin
    354359         */
    355         wp.mce.media = {
     360        wp.mce.av = {
    356361                loaded: false,
    357                 toView: wp.mce.gallery.toView,
    358362
     363                View: _.extend( {}, wp.media.mixin, {
     364                        initialize: function( options ) {
     365                                this.players = [];
     366                                this.shortcode = options.shortcode;
     367                                _.bindAll( this, 'setPlayer', 'pausePlayers' );
     368                                $( this ).on( 'ready', this.setPlayer );
     369                                $( 'body' ).on( 'click', '.wp-switch-editor', this.pausePlayers );
     370                                $( document ).on( 'media:edit', this.pausePlayers );
     371                        },
     372
     373                        /**
     374                         * Creates the player instance for the current node
     375                         *
     376                         * @global MediaElementPlayer
     377                         *
     378                         * @param {Event} e
     379                         * @param {HTMLElement} node
     380                         */
     381                        setPlayer: function(e, node) {
     382                                // if the ready event fires on an empty node
     383                                if ( ! node ) {
     384                                        return;
     385                                }
     386
     387                                var self = this,
     388                                        media,
     389                                        firefox = this.ua.is( 'ff' ),
     390                                        className = '.wp-' +  this.shortcode.tag + '-shortcode';
     391
     392                                media = $( node ).find( className );
     393
     394                                if ( ! this.isCompatible( media ) ) {
     395                                        media.closest( '.wpview-wrap' ).addClass( 'wont-play' );
     396                                        if ( ! media.parent().hasClass( 'wpview-wrap' ) ) {
     397                                                media.parent().replaceWith( media );
     398                                        }
     399                                        media.replaceWith( '<p>' + media.find( 'source' ).eq(0).prop( 'src' ) + '</p>' );
     400                                        return;
     401                                } else {
     402                                        media.closest( '.wpview-wrap' ).removeClass( 'wont-play' );
     403                                        if ( firefox ) {
     404                                                media.prop( 'preload', 'metadata' );
     405                                        } else {
     406                                                media.prop( 'preload', 'none' );
     407                                        }
     408                                }
     409
     410                                media = wp.media.view.MediaDetails.prepareSrc( media.get(0) );
     411
     412                                setTimeout( function() {
     413                                        wp.mce.av.loaded = true;
     414                                        self.players.push( new MediaElementPlayer( media, self.mejsSettings ) );
     415                                }, wp.mce.av.loaded ? 10 : 500 );
     416                        },
     417
     418                        /**
     419                         * Pass data to the View's Underscore template and return the compiled output
     420                         *
     421                         * @returns {string}
     422                         */
     423                        getHtml: function() {
     424                                var attrs = this.shortcode.attrs.named;
     425                                attrs.content = this.shortcode.content;
     426
     427                                return this.template({ model: _.defaults(
     428                                        attrs,
     429                                        wp.media[ this.shortcode.tag ].defaults )
     430                                });
     431                        },
     432
     433                        unbind: function() {
     434                                this.unsetPlayers();
     435                        }
     436                } ),
     437
    359438                /**
    360439                 * Called when a TinyMCE view is clicked for editing.
    361440                 * - Parses the shortcode out of the element's data attribute
     
    397476        };
    398477
    399478        /**
    400          * Base View class for audio and video shortcodes
    401          *
    402          * @constructor
    403          * @augments wp.mce.View
    404          * @mixes wp.media.mixin
    405          */
    406         wp.mce.media.View = wp.mce.View.extend({
    407                 initialize: function( options ) {
    408                         this.players = [];
    409                         this.shortcode = options.shortcode;
    410                         _.bindAll( this, 'setPlayer', 'pausePlayers' );
    411                         $( this ).on( 'ready', this.setPlayer );
    412                         $( 'body' ).on( 'click', '.wp-switch-editor', this.pausePlayers );
    413                         $( document ).on( 'media:edit', this.pausePlayers );
    414                 },
    415 
    416                 /**
    417                  * Creates the player instance for the current node
    418                  *
    419                  * @global MediaElementPlayer
    420                  * @global _wpmejsSettings
    421                  *
    422                  * @param {Event} e
    423                  * @param {HTMLElement} node
    424                  */
    425                 setPlayer: function(e, node) {
    426                         // if the ready event fires on an empty node
    427                         if ( ! node ) {
    428                                 return;
    429                         }
    430 
    431                         var self = this,
    432                                 media,
    433                                 firefox = this.ua.is( 'ff' ),
    434                                 className = '.wp-' +  this.shortcode.tag + '-shortcode';
    435 
    436                         media = $( node ).find( className );
    437 
    438                         if ( ! this.isCompatible( media ) ) {
    439                                 media.closest( '.wpview-wrap' ).addClass( 'wont-play' );
    440                                 if ( ! media.parent().hasClass( 'wpview-wrap' ) ) {
    441                                         media.parent().replaceWith( media );
    442                                 }
    443                                 media.replaceWith( '<p>' + media.find( 'source' ).eq(0).prop( 'src' ) + '</p>' );
    444                                 return;
    445                         } else {
    446                                 media.closest( '.wpview-wrap' ).removeClass( 'wont-play' );
    447                                 if ( firefox ) {
    448                                         media.prop( 'preload', 'metadata' );
    449                                 } else {
    450                                         media.prop( 'preload', 'none' );
    451                                 }
    452                         }
    453 
    454                         media = wp.media.view.MediaDetails.prepareSrc( media.get(0) );
    455 
    456                         setTimeout( function() {
    457                                 wp.mce.media.loaded = true;
    458                                 self.players.push( new MediaElementPlayer( media, self.mejsSettings ) );
    459                         }, wp.mce.media.loaded ? 10 : 500 );
    460                 },
    461 
    462                 /**
    463                  * Pass data to the View's Underscore template and return the compiled output
    464                  *
    465                  * @returns {string}
    466                  */
    467                 getHtml: function() {
    468                         var attrs = this.shortcode.attrs.named;
    469                         attrs.content = this.shortcode.content;
    470 
    471                         return this.template({ model: _.defaults(
    472                                 attrs,
    473                                 wp.media[ this.shortcode.tag ].defaults )
    474                         });
    475                 },
    476 
    477                 unbind: function() {
    478                         this.unsetPlayers();
    479                 }
    480         });
    481         _.extend( wp.mce.media.View.prototype, wp.media.mixin );
    482 
    483         /**
    484479         * TinyMCE handler for the video shortcode
    485480         *
    486          * @mixes wp.mce.media
     481         * @mixes wp.mce.av
    487482         */
    488         wp.mce.video = _.extend( {}, wp.mce.media, {
     483        wp.mce.views.register( 'video', _.extend( {}, wp.mce.av, {
    489484                shortcode: 'video',
    490485                state: 'video-details',
    491                 View: wp.mce.media.View.extend({
    492                         className: 'editor-video',
    493                         template:  media.template('editor-video')
    494                 })
    495         } );
    496         wp.mce.views.register( 'video', wp.mce.video );
     486                View: _.extend( {}, wp.mce.av.View, {
     487                        template: media.template( 'editor-video' )
     488                } )
     489        } ) );
    497490
    498491        /**
    499492         * TinyMCE handler for the audio shortcode
    500493         *
    501          * @mixes wp.mce.media
     494         * @mixes wp.mce.av
    502495         */
    503         wp.mce.audio = _.extend( {}, wp.mce.media, {
     496        wp.mce.views.register( 'audio', _.extend( {}, wp.mce.av, {
    504497                shortcode: 'audio',
    505498                state: 'audio-details',
    506                 View: wp.mce.media.View.extend({
    507                         className: 'editor-audio',
    508                         template:  media.template('editor-audio')
    509                 })
    510         } );
    511         wp.mce.views.register( 'audio', wp.mce.audio );
     499                View: _.extend( {}, wp.mce.av.View, {
     500                        template: media.template( 'editor-audio' )
     501                } )
     502        } ) );
    512503
    513504        /**
    514          * Base View class for playlist shortcodes
     505         * TinyMCE handler for the playlist shortcode
    515506         *
    516          * @constructor
    517          * @augments wp.mce.View
    518          * @mixes wp.media.mixin
     507         * @mixes wp.mce.av
    519508         */
    520         wp.mce.media.PlaylistView = wp.mce.View.extend({
    521                 className: 'editor-playlist',
    522                 template:  media.template('editor-playlist'),
     509        wp.mce.views.register( 'playlist', _.extend( {}, wp.mce.av, {
     510                shortcode: 'playlist',
     511                state: ['playlist-edit', 'video-playlist-edit'],
     512                View: _.extend( {}, wp.media.mixin, {
     513                        template:  media.template( 'editor-playlist' ),
    523514
    524                 initialize: function( options ) {
    525                         this.players = [];
    526                         this.data = {};
    527                         this.attachments = [];
    528                         this.shortcode = options.shortcode;
     515                        initialize: function( options ) {
     516                                this.players = [];
     517                                this.data = {};
     518                                this.attachments = [];
     519                                this.shortcode = options.shortcode;
    529520
    530                         $( 'body' ).on( 'click', '.wp-switch-editor', this.pausePlayers );
    531                         $( document ).on( 'media:edit', this.pausePlayers );
     521                                $( 'body' ).on( 'click', '.wp-switch-editor', this.pausePlayers );
     522                                $( document ).on( 'media:edit', this.pausePlayers );
    532523
    533                         this.fetch();
    534                 },
     524                                this.fetch();
    535525
    536                 /**
    537                  * Asynchronously fetch the shortcode's attachments
    538                  */
    539                 fetch: function() {
    540                         this.attachments = wp.media.playlist.attachments( this.shortcode );
    541                         this.dfd = this.attachments.more().done( _.bind( this.render, this ) );
    542                 },
     526                                $( this ).on( 'ready', this.setPlaylist );
     527                        },
    543528
    544                 /**
    545                  * Get the HTML for the view (which also set's the data), replace the
    546                  *   current HTML, and then invoke the WPPlaylistView instance to render
    547                  *   the playlist in the editor
    548                  *
    549                  * @global WPPlaylistView
    550                  * @global tinymce.editors
    551                  */
    552                 render: function() {
    553                         var html = this.getHtml(), self = this;
     529                        /**
     530                         * Asynchronously fetch the shortcode's attachments
     531                         */
     532                        fetch: function() {
     533                                this.attachments = wp.media.playlist.attachments( this.shortcode );
     534                                this.dfd = this.attachments.more().done( _.bind( this.render, this ) );
     535                        },
    554536
    555                         _.each( tinymce.editors, function( editor ) {
    556                                 var doc;
    557                                 if ( editor.plugins.wpview ) {
    558                                         doc = editor.getDoc();
    559                                         $( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each(function (i, elem) {
    560                                                 var node = $( elem );
     537                        setPlaylist: function( event, element ) {
     538                                if ( ! this.data.tracks ) {
     539                                        return;
     540                                }
    561541
    562                                                 // The <ins> is used to mark the end of the wrapper div. Needed when comparing
    563                                                 // the content as string for preventing extra undo levels.
    564                                                 node.html( html ).append( '<ins data-wpview-end="1"></ins>' );
     542                                this.players.push( new WPPlaylistView( {
     543                                        el: $( element ).find( '.wp-playlist' ).get( 0 ),
     544                                        metadata: this.data
     545                                } ).player );
     546                        },
    565547
    566                                                 if ( ! self.data.tracks ) {
    567                                                         return;
    568                                                 }
     548                        /**
     549                         * Set the data that will be used to compile the Underscore template,
     550                         *  compile the template, and then return it.
     551                         *
     552                         * @returns {string}
     553                         */
     554                        getHtml: function() {
     555                                var data = this.shortcode.attrs.named,
     556                                        model = wp.media.playlist,
     557                                        options,
     558                                        attachments,
     559                                        tracks = [];
    569560
    570                                                 self.players.push( new WPPlaylistView({
    571                                                         el: $( elem ).find( '.wp-playlist' ).get(0),
    572                                                         metadata: self.data
    573                                                 }).player );
    574                                         });
     561                                // Don't render errors while still fetching attachments
     562                                if ( this.dfd && 'pending' === this.dfd.state() && ! this.attachments.length ) {
     563                                        return;
    575564                                }
    576                         }, this );
    577                 },
    578565
    579                 /**
    580                  * Set the data that will be used to compile the Underscore template,
    581                  *  compile the template, and then return it.
    582                  *
    583                  * @returns {string}
    584                  */
    585                 getHtml: function() {
    586                         var data = this.shortcode.attrs.named,
    587                                 model = wp.media.playlist,
    588                                 options,
    589                                 attachments,
    590                                 tracks = [];
     566                                _.each( model.defaults, function( value, key ) {
     567                                        data[ key ] = model.coerce( data, key );
     568                                });
    591569
    592                         // Don't render errors while still fetching attachments
    593                         if ( this.dfd && 'pending' === this.dfd.state() && ! this.attachments.length ) {
    594                                 return;
    595                         }
     570                                options = {
     571                                        type: data.type,
     572                                        style: data.style,
     573                                        tracklist: data.tracklist,
     574                                        tracknumbers: data.tracknumbers,
     575                                        images: data.images,
     576                                        artists: data.artists
     577                                };
    596578
    597                         _.each( model.defaults, function( value, key ) {
    598                                 data[ key ] = model.coerce( data, key );
    599                         });
     579                                if ( ! this.attachments.length ) {
     580                                        return this.template( options );
     581                                }
    600582
    601                         options = {
    602                                 type: data.type,
    603                                 style: data.style,
    604                                 tracklist: data.tracklist,
    605                                 tracknumbers: data.tracknumbers,
    606                                 images: data.images,
    607                                 artists: data.artists
    608                         };
     583                                attachments = this.attachments.toJSON();
    609584
    610                         if ( ! this.attachments.length ) {
    611                                 return this.template( options );
    612                         }
     585                                _.each( attachments, function( attachment ) {
     586                                        var size = {}, resize = {}, track = {
     587                                                src : attachment.url,
     588                                                type : attachment.mime,
     589                                                title : attachment.title,
     590                                                caption : attachment.caption,
     591                                                description : attachment.description,
     592                                                meta : attachment.meta
     593                                        };
    613594
    614                         attachments = this.attachments.toJSON();
    615 
    616                         _.each( attachments, function( attachment ) {
    617                                 var size = {}, resize = {}, track = {
    618                                         src : attachment.url,
    619                                         type : attachment.mime,
    620                                         title : attachment.title,
    621                                         caption : attachment.caption,
    622                                         description : attachment.description,
    623                                         meta : attachment.meta
    624                                 };
    625 
    626                                 if ( 'video' === data.type ) {
    627                                         size.width = attachment.width;
    628                                         size.height = attachment.height;
    629                                         if ( media.view.settings.contentWidth ) {
    630                                                 resize.width = media.view.settings.contentWidth - 22;
    631                                                 resize.height = Math.ceil( ( size.height * resize.width ) / size.width );
    632                                                 if ( ! options.width ) {
    633                                                         options.width = resize.width;
    634                                                         options.height = resize.height;
     595                                        if ( 'video' === data.type ) {
     596                                                size.width = attachment.width;
     597                                                size.height = attachment.height;
     598                                                if ( media.view.settings.contentWidth ) {
     599                                                        resize.width = media.view.settings.contentWidth - 22;
     600                                                        resize.height = Math.ceil( ( size.height * resize.width ) / size.width );
     601                                                        if ( ! options.width ) {
     602                                                                options.width = resize.width;
     603                                                                options.height = resize.height;
     604                                                        }
     605                                                } else {
     606                                                        if ( ! options.width ) {
     607                                                                options.width = attachment.width;
     608                                                                options.height = attachment.height;
     609                                                        }
    635610                                                }
     611                                                track.dimensions = {
     612                                                        original : size,
     613                                                        resized : _.isEmpty( resize ) ? size : resize
     614                                                };
    636615                                        } else {
    637                                                 if ( ! options.width ) {
    638                                                         options.width = attachment.width;
    639                                                         options.height = attachment.height;
    640                                                 }
     616                                                options.width = 400;
    641617                                        }
    642                                         track.dimensions = {
    643                                                 original : size,
    644                                                 resized : _.isEmpty( resize ) ? size : resize
    645                                         };
    646                                 } else {
    647                                         options.width = 400;
    648                                 }
    649618
    650                                 track.image = attachment.image;
    651                                 track.thumb = attachment.thumb;
     619                                        track.image = attachment.image;
     620                                        track.thumb = attachment.thumb;
    652621
    653                                 tracks.push( track );
    654                         } );
     622                                        tracks.push( track );
     623                                } );
    655624
    656                         options.tracks = tracks;
    657                         this.data = options;
     625                                options.tracks = tracks;
     626                                this.data = options;
    658627
    659                         return this.template( options );
    660                 },
     628                                return this.template( options );
     629                        },
    661630
    662                 unbind: function() {
    663                         this.unsetPlayers();
    664                 }
    665         });
    666         _.extend( wp.mce.media.PlaylistView.prototype, wp.media.mixin );
     631                        unbind: function() {
     632                                this.unsetPlayers();
     633                        }
     634                } )
     635        } ) );
    667636
    668637        /**
    669          * TinyMCE handler for the playlist shortcode
    670          *
    671          * @mixes wp.mce.media
    672          */
    673         wp.mce.playlist = _.extend( {}, wp.mce.media, {
    674                 shortcode: 'playlist',
    675                 state: ['playlist-edit', 'video-playlist-edit'],
    676                 View: wp.mce.media.PlaylistView
    677         } );
    678         wp.mce.views.register( 'playlist', wp.mce.playlist );
    679 
    680         /**
    681638         * TinyMCE handler for the embed shortcode
    682639         */
    683         wp.mce.embed = {
     640        wp.mce.views.register( 'embed', {
    684641                shortcode: 'embed',
    685                 toView: wp.mce.gallery.toView,
    686                 View: wp.mce.View.extend( {
    687                         className: 'editor-embed',
     642                View: _.extend( {}, wp.media.mixin, {
    688643                        template: media.template( 'editor-embed' ),
    689644                        initialize: function( options ) {
    690645                                this.players = [];
     
    737692                        }
    738693                } ),
    739694                edit: function() {}
    740         };
     695        } );
    741696
    742         _.extend( wp.mce.embed.View.prototype, wp.media.mixin );
    743 
    744         wp.mce.views.register( 'embed', wp.mce.embed );
    745 
    746697}(jQuery));