Make WordPress Core

Changeset 22547


Ignore:
Timestamp:
11/12/2012 05:57:12 AM (13 years ago)
Author:
koopersmith
Message:

Media: Add Embed from URL tab.

Note: There is a bug that currently blocks adding several successive embeds.

see #21390.

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-admin/includes/meta-boxes.php

    r22528 r22547  
    10541054
    10551055            frame.toolbar.on( 'activate:select', function() {
    1056                 frame.toolbar.view().add({
     1056                frame.toolbar.view().set({
    10571057                    select: {
    10581058                        style: 'primary',
  • trunk/wp-admin/js/custom-background.js

    r22502 r22547  
    3939
    4040            frame.toolbar.on( 'activate:select', function() {
    41                 frame.toolbar.view().add({
     41                frame.toolbar.view().set({
    4242                    select: {
    4343                        style: 'primary',
  • trunk/wp-admin/js/custom-header.js

    r22505 r22547  
    2626
    2727            frame.toolbar.on( 'activate:select', function() {
    28                 frame.toolbar.view().add({
     28                frame.toolbar.view().set({
    2929                    select: {
    3030                        style: 'primary',
  • trunk/wp-admin/js/media-upload.js

    r22537 r22547  
    145145            }, this );
    146146
     147            workflow.get('embed').on( 'select', function() {
     148                var embed = workflow.state().toJSON(),
     149                    options;
     150
     151                if ( 'link' === embed.type ) {
     152                    this.insert( wp.html.string({
     153                        tag:     'a',
     154                        content: embed.title || embed.url,
     155                        attrs:   {
     156                            href: embed.url
     157                        }
     158                    }) );
     159
     160                } else if ( 'image' === embed.type ) {
     161                    _.defaults( embed, {
     162                        align:   'none',
     163                        url:     '',
     164                        alt:     '',
     165                        linkUrl: '',
     166                        link:    'none'
     167                    });
     168
     169                    options = {
     170                        single: true,
     171                        tag:    'img',
     172                        attrs:  {
     173                            'class': 'align' + embed.align,
     174                            src:     embed.url,
     175                            alt:     embed.alt
     176                        }
     177                    };
     178
     179                    if ( 'custom' === embed.link || 'file' === embed.link ) {
     180                        options = {
     181                            tag:     'a',
     182                            content: options,
     183                            attrs:   {
     184                                href: 'custom' === embed.link ? embed.linkUrl : embed.url
     185                            }
     186                        };
     187                    }
     188
     189                    this.insert( wp.html.string( options ) );
     190                }
     191            }, this );
     192
    147193            return workflow;
    148194        },
  • trunk/wp-includes/css/media-views.css

    r22543 r22547  
     1/**
     2 * Base Styles
     3 */
     4
     5.media-frame input,
     6.media-frame textarea {
     7    padding: 6px 8px;
     8    line-height: 16px;
     9}
     10
     11.media-frame select,
     12.wp-admin .media-frame select {
     13    height: 28px;
     14    line-height: 28px;
     15    margin-top: 3px;
     16}
     17
    118/**
    219 * Modal
     
    97114    bottom: 0;
    98115    border-width: 1px 0 0 0;
     116    box-shadow: 0 -4px 4px -4px rgba( 0, 0, 0, 0.1 );
    99117}
    100118
     
    218236
    219237.media-sidebar .setting input,
    220 .media-sidebar .setting textarea,
    221 .compat-item .field input,
    222 .compat-item .field textarea {
    223     padding: 6px 8px;
    224     line-height: 16px;
    225 }
    226 
    227 .media-sidebar .setting input,
    228238.media-sidebar .setting textarea {
    229239    width: 65%;
     
    237247}
    238248
    239 .media-sidebar .setting select,
    240 .compat-item .field select {
    241     height: 28px;
    242     line-height: 28px;
     249.media-sidebar select {
    243250    margin-top: 3px;
    244251}
     
    986993    overflow: hidden;
    987994}
     995
     996/**
     997 * Embed from URL
     998 */
     999.embed-url {
     1000    display: block;
     1001    position: relative;
     1002    height: 75px;
     1003    padding: 16px 16px;
     1004    margin: 0;
     1005    z-index: 50;
     1006    border-bottom: 1px solid #dfdfdf;
     1007    box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
     1008    font-size: 18px;
     1009    font-weight: 200;
     1010}
     1011
     1012.embed-url span {
     1013    display: block;
     1014    padding: 4px 0 6px 2px;
     1015}
     1016
     1017.embed-url input {
     1018    padding: 12px 14px;
     1019    width: 100%;
     1020    min-width: 200px;
     1021    /*max-width: 500px;*/
     1022    box-shadow: inset 2px 2px 4px -2px rgba( 0, 0, 0, 0.1 );
     1023}
     1024
     1025.embed-link-settings,
     1026.embed-image-settings {
     1027    position: absolute;
     1028    background: #f5f5f5;
     1029    top: 108px;
     1030    left: 0;
     1031    right: 0;
     1032    bottom: 0;
     1033    padding: 16px 16px 32px;
     1034    overflow: auto;
     1035}
     1036
     1037.media-embed .thumbnail {
     1038    max-width: 100%;
     1039    max-height: 200px;
     1040    position: relative;
     1041    float: left;
     1042}
     1043
     1044.media-embed .thumbnail img {
     1045    max-height: 200px;
     1046}
     1047
     1048.media-embed .thumbnail:after {
     1049    content: '';
     1050    display: block;
     1051    position: absolute;
     1052    top: 0;
     1053    left: 0;
     1054    right: 0;
     1055    bottom: 0;
     1056    box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.1 );
     1057    overflow: hidden;
     1058}
     1059
     1060.media-embed .setting {
     1061    width: 100%;
     1062    margin-top: 10px;
     1063    float: left;
     1064    display: block;
     1065    clear: both;
     1066}
     1067
     1068.media-embed .setting span {
     1069    display: block;
     1070    width: 200px;
     1071    font-size: 13px;
     1072    line-height: 24px;
     1073    color: #999;
     1074    text-shadow: 0 1px 0 #fff;
     1075}
     1076
     1077.media-embed .setting .button-group {
     1078    margin: 2px 0;
     1079}
     1080
     1081.media-embed .setting input,
     1082.media-embed .setting textarea {
     1083    display: block;
     1084    width: 100%;
     1085    max-width: 400px;
     1086    margin: 1px 0;
     1087}
  • trunk/wp-includes/js/media-views.js

    r22543 r22547  
    317317
    318318        deactivate: function() {
    319             this.off( 'change:library change:exclude', this.buildComposite, this );
    320             this.off( 'change:excludeState', this._excludeState, this );
    321             this.destroyComposite();
    322 
    323             wp.Uploader.queue.off( 'add', this.selectUpload, this );
     319            this.off( 'change:empty', this.refresh, this );
     320            this.get('library').off( 'add remove reset', this._updateEmpty, this );
    324321
    325322            // Unbind all event handlers that use this state as the context
    326323            // from the selection.
    327324            this.get('selection').off( null, null, this );
    328             this.get('library').off( 'add remove reset', this._updateEmpty, this );
    329             this.off( 'change:empty', this.refresh, this );
     325
     326            wp.Uploader.queue.off( 'add', this.selectUpload, this );
     327
     328            this.off( 'change:excludeState', this._excludeState, this );
     329            this.off( 'change:library change:exclude', this.buildComposite, this );
     330
     331            this.destroyComposite();
    330332        },
    331333
     
    526528    });
    527529
     530
     531    // wp.media.controller.Embed
     532    // -------------------------
     533    media.controller.Embed = media.controller.State.extend({
     534        defaults: {
     535            id:      'embed',
     536            url:     '',
     537            menu:    'main',
     538            content: 'embed',
     539            toolbar: 'main-embed',
     540            type:    'link'
     541        },
     542
     543        initialize: function() {
     544            this.on( 'change:url', this.scan, this );
     545            media.controller.State.prototype.initialize.apply( this, arguments );
     546        },
     547
     548        scan: function() {
     549            var attributes = { type: 'link' };
     550
     551            if ( /(?:jpe?g|png|gif)$/i.test( this.get('url') ) )
     552                attributes.type = 'image';
     553
     554            this.trigger( 'scan', attributes );
     555            this.set( attributes );
     556        },
     557
     558        reset: function() {
     559            _.each( _.without( _.keys( this.attributes ), _.keys( this.defaults ) ), function( key ) {
     560                this.unset( key );
     561            }, this );
     562
     563            this.set( 'url', '' );
     564            this.frame.toolbar.view().refresh();
     565        }
     566    });
     567
    528568    /**
    529569     * ========================================================================
     
    859899
    860900        // Toolbars
    861         selectToolbar: function() {
     901        selectToolbar: function( options ) {
     902            options = _.defaults( options || {}, {
     903                event:  'select',
     904                silent: false,
     905                state:  false
     906            });
     907
    862908            this.toolbar.view( new media.view.Toolbar({
    863909                controller: this,
     910                silent:     options.silent,
     911
    864912                items: {
    865913                    select: {
     
    872920
    873921                            controller.close();
    874                             controller.state().trigger('select');
    875                             controller.reset().state( controller.options.state );
     922                            controller.state().trigger( options.event );
     923                            controller.reset();
     924                            if ( options.state )
     925                                controller.state( options.state );
    876926                        }
    877927                    }
     
    941991
    942992                new media.controller.Upload( main ),
     993
     994                // Embed states.
     995                new media.controller.Embed(),
    943996
    944997                // Gallery states.
     
    9921045
    9931046                    content: {
    994                         embed:  'embedContent'
     1047                        embed: 'embedContent'
    9951048                    },
    9961049
     
    11221175
    11231176        // Content
    1124         embedContent: function() {},
     1177        embedContent: function() {
     1178            var view = new media.view.Embed({
     1179                controller: this,
     1180                model:      this.state()
     1181            }).render();
     1182
     1183            this.$el.addClass('hide-sidebar');
     1184            this.content.view( view );
     1185            view.url.focus();
     1186        },
    11251187
    11261188        // Sidebars
    11271189        onSidebarGallerySettings: function( options ) {
    11281190            var library = this.state().get('library');
     1191
     1192            if ( ! library )
     1193                return;
    11291194
    11301195            library.gallery = library.gallery || new Backbone.Model();
     
    11701235        },
    11711236
    1172         mainEmbedToolbar: function() {},
     1237        mainEmbedToolbar: function() {
     1238            this.toolbar.view( new media.view.Toolbar.Embed({
     1239                controller: this
     1240            }) );
     1241
     1242            this.$el.removeClass('hide-toolbar');
     1243        },
    11731244
    11741245        batchEditToolbar: function() {
     
    14961567
    14971568            if ( this.options.items )
    1498                 this.add( this.options.items, { silent: true });
     1569                this.set( this.options.items, { silent: true });
    14991570
    15001571            if ( ! this.options.silent )
     
    15041575        destroy: function() {
    15051576            this.remove();
     1577
     1578            if ( this.model )
     1579                this.model.off( null, null, this );
     1580
     1581            if ( this.collection )
     1582                this.collection.off( null, null, this );
     1583
     1584            this.controller.off( null, null, this );
     1585
    15061586            _.each( this._views, function( view ) {
    15071587                if ( view.destroy )
     
    15281608        },
    15291609
    1530         add: function( id, view, options ) {
     1610        set: function( id, view, options ) {
    15311611            options = options || {};
    15321612
     
    15341614            if ( _.isObject( id ) ) {
    15351615                _.each( id, function( view, id ) {
    1536                     this.add( id, view, { silent: true });
     1616                    this.set( id, view, { silent: true });
    15371617                }, this );
    15381618
    1539                 if ( ! options.silent )
    1540                     this.render();
    1541                 return this;
     1619            } else {
     1620                if ( ! ( view instanceof Backbone.View ) ) {
     1621                    view.classes = [ id ].concat( view.classes || [] );
     1622                    view = new media.view.Button( view ).render();
     1623                }
     1624
     1625                view.controller = view.controller || this.controller;
     1626
     1627                this._views[ id ] = view;
    15421628            }
    15431629
    1544             if ( ! ( view instanceof Backbone.View ) ) {
    1545                 view.classes = [ id ].concat( view.classes || [] );
    1546                 view = new media.view.Button( view ).render();
    1547             }
    1548 
    1549             view.controller = view.controller || this.controller;
    1550 
    1551             this._views[ id ] = view;
    15521630            if ( ! options.silent )
    15531631                this.render();
     
    15591637        },
    15601638
    1561         remove: function( id, options ) {
     1639        unset: function( id, options ) {
    15621640            delete this._views[ id ];
    15631641            if ( ! options || ! options.silent )
     
    15691647    });
    15701648
     1649    // wp.media.view.Toolbar.Select
     1650    // ----------------------------
     1651    media.view.Toolbar.Select = media.view.Toolbar.extend({
     1652        initialize: function() {
     1653            var options = this.options,
     1654                controller = options.controller,
     1655                selection = controller.state().get('selection');
     1656
     1657            _.bindAll( this, 'clickSelect' );
     1658
     1659            _.defaults( options, {
     1660                event: 'select',
     1661                state: false,
     1662                reset: true,
     1663                close: true,
     1664                text:  l10n.select
     1665            });
     1666
     1667            options.items = _.defaults( options.items || {}, {
     1668                select: {
     1669                    style:    'primary',
     1670                    text:     options.text,
     1671                    priority: 80,
     1672                    click:    this.clickSelect
     1673                }
     1674            });
     1675
     1676            media.view.Toolbar.prototype.initialize.apply( this, arguments );
     1677        },
     1678
     1679        clickSelect: function() {
     1680            var options = this.options,
     1681                controller = this.controller;
     1682
     1683            if ( options.close )
     1684                controller.close();
     1685
     1686            if ( options.event )
     1687                controller.state().trigger( options.event );
     1688
     1689            if ( options.reset )
     1690                controller.reset();
     1691
     1692            if ( options.state )
     1693                controller.state( options.state );
     1694        }
     1695    });
     1696
     1697    // wp.media.view.Toolbar.Embed
     1698    // ---------------------------
     1699    media.view.Toolbar.Embed = media.view.Toolbar.Select.extend({
     1700        initialize: function() {
     1701            var controller = this.options.controller;
     1702
     1703            _.defaults( this.options, {
     1704                text: l10n.insertEmbed
     1705            });
     1706
     1707            media.view.Toolbar.Select.prototype.initialize.apply( this, arguments );
     1708            controller.on( 'change:url', this.refresh, this );
     1709        },
     1710
     1711        refresh: function() {
     1712            var url = this.controller.state().get('url');
     1713            this.get('select').model.set( 'disabled', ! url || /^https?:\/\/$/.test(url) );
     1714        }
     1715    });
     1716
    15711717    // wp.media.view.Toolbar.Insert
    1572     // ---------------------------------
     1718    // ----------------------------
    15731719    media.view.Toolbar.Insert = media.view.Toolbar.extend({
    15741720        initialize: function() {
     
    18872033        click: function() {
    18882034            var options = this.options;
     2035
    18892036            if ( options.click )
    18902037                options.click.call( this );
     
    23452492
    23462493            if ( this.options.search ) {
    2347                 this.toolbar.add( 'search', new media.view.Search({
     2494                this.toolbar.set( 'search', new media.view.Search({
    23482495                    controller: this.controller,
    23492496                    model:      this.collection.props,
     
    23532500
    23542501            if ( this.options.sortable ) {
    2355                 this.toolbar.add( 'dragInfo', new Backbone.View({
     2502                this.toolbar.set( 'dragInfo', new Backbone.View({
    23562503                    el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
    23572504                    priority: -40
     
    25652712                $buttons = $setting.find('button').removeClass('active');
    25662713                $buttons.filter( '[value="' + value + '"]' ).addClass('active');
     2714
     2715            // Handle text inputs and textareas.
     2716            } else if ( $setting.is('input[type="text"], textarea') ) {
     2717                if ( ! $setting.is(':focus') )
     2718                    $setting.val( value );
    25672719            }
    25682720        },
     
    27192871        }
    27202872    });
     2873
     2874    /**
     2875     * wp.media.view.Embed
     2876     */
     2877    media.view.Embed = Backbone.View.extend({
     2878        className: 'media-embed',
     2879
     2880        initialize: function() {
     2881            this.controller = this.options.controller;
     2882
     2883            this.url = new media.view.EmbedUrl({
     2884                controller: this.controller,
     2885                model:      this.model
     2886            }).render();
     2887
     2888            this._settings = new Backbone.View();
     2889            this.refresh();
     2890            this.model.on( 'change:type', this.refresh, this );
     2891        },
     2892
     2893        render: function() {
     2894            this.$el.html([ this.url.el, this._settings.el ]);
     2895            this.url.focus();
     2896            return this;
     2897        },
     2898
     2899        settings: function( view ) {
     2900            view.render();
     2901            this._settings.$el.replaceWith( view.$el );
     2902            if ( this._settings.destroy )
     2903                this._settings.destroy();
     2904            this._settings.remove();
     2905            this._settings = view;
     2906        },
     2907
     2908        refresh: function() {
     2909            var type = this.model.get('type'),
     2910                constructor;
     2911
     2912            if ( 'image' === type )
     2913                constructor = media.view.EmbedImage;
     2914            else if ( 'link' === type )
     2915                constructor = media.view.EmbedLink;
     2916            else
     2917                return;
     2918
     2919            this.settings( new constructor({
     2920                controller: this.controller,
     2921                model:      this.model,
     2922                priority:   40
     2923            }) );
     2924        }
     2925    });
     2926
     2927    /**
     2928     * wp.media.view.EmbedUrl
     2929     */
     2930    media.view.EmbedUrl = Backbone.View.extend({
     2931        tagName:   'label',
     2932        className: 'embed-url',
     2933
     2934        events: {
     2935            'keyup': 'url'
     2936        },
     2937
     2938        initialize: function() {
     2939            this.label = this.make( 'span', null, this.options.label || l10n.url );
     2940            this.input = this.make( 'input', {
     2941                type:  'text',
     2942                value: this.model.get('url') || ''
     2943            });
     2944
     2945            this.$label = $( this.label );
     2946            this.$input = $( this.input );
     2947            this.$el.append([ this.label, this.input ]);
     2948
     2949            this.model.on( 'change:url', this.render, this );
     2950        },
     2951
     2952        destroy: function() {
     2953            this.model.off( null, null, this );
     2954        },
     2955
     2956        render: function() {
     2957            var $input = this.$input;
     2958
     2959            if ( $input.is(':focus') )
     2960                return;
     2961
     2962            this.input.value = this.model.get('url') || 'http://';
     2963            return this;
     2964        },
     2965
     2966        url: function( event ) {
     2967            this.model.set( 'url', event.target.value );
     2968        },
     2969
     2970        focus: function() {
     2971            var $input = this.$input;
     2972            // If the input is visible, focus and select its contents.
     2973            if ( $input.is(':visible') )
     2974                $input.focus()[0].select();
     2975        }
     2976    });
     2977
     2978    /**
     2979     * wp.media.view.EmbedLink
     2980     */
     2981    media.view.EmbedLink = media.view.Settings.extend({
     2982        className: 'embed-link-settings',
     2983        template:  media.template('embed-link-settings')
     2984    });
     2985
     2986    /**
     2987     * wp.media.view.EmbedImage
     2988     */
     2989    media.view.EmbedImage =  media.view.Settings.AttachmentDisplay.extend({
     2990        className: 'embed-image-settings',
     2991        template:  media.template('embed-image-settings'),
     2992
     2993        initialize: function() {
     2994            media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
     2995            this.model.on( 'change:url', this.updateImage, this );
     2996        },
     2997
     2998        destroy: function() {
     2999            this.model.off( null, null, this );
     3000            media.view.Settings.AttachmentDisplay.prototype.destroy.apply( this, arguments );
     3001        },
     3002
     3003        updateImage: function() {
     3004            this.$('img').attr( 'src', this.model.get('url') );
     3005        }
     3006    });
    27213007}(jQuery));
  • trunk/wp-includes/media.php

    r22543 r22547  
    13271327
    13281328        // Generic
     1329        'url'         => __( 'URL' ),
    13291330        'insertMedia' => __( 'Insert Media' ),
    13301331        'search'      => __( 'Search' ),
     
    13471348        // Embed
    13481349        'embedFromUrlTitle' => __( 'Embed From URL' ),
     1350        'insertEmbed'       => __( 'Insert embed' ),
    13491351
    13501352        // Batch
     
    15711573        </div>
    15721574
    1573         <# if ( ! _.isUndefined( sizes ) ) { #>
     1575        <# if ( 'undefined' !== typeof sizes ) { #>
    15741576            <label class="setting">
    15751577                <span><?php _e('Size'); ?></span>
     
    15881590
    15891591                    foreach ( $sizes as $value => $name ) : ?>
    1590                         <# if ( ! _.isUndefined( sizes['<?php echo esc_js( $value ); ?>'] ) ) { #>
     1592                        <# if ( sizes['<?php echo esc_js( $value ); ?>'] ) { #>
    15911593                            <option value="<?php echo esc_attr( $value ); ?>" <?php selected( $value, 'medium' ); ?>>
    15921594                                <?php echo esc_html( $name ); ?>
     
    16361638    </script>
    16371639
     1640    <script type="text/html" id="tmpl-embed-link-settings">
     1641        <label class="setting">
     1642            <span><?php _e('Title'); ?></span>
     1643            <input type="text" class="alignment" data-setting="title" />
     1644        </label>
     1645    </script>
     1646
     1647    <script type="text/html" id="tmpl-embed-image-settings">
     1648        <div class="thumbnail">
     1649            <img src="{{ model.url }}" draggable="false" />
     1650        </div>
     1651
     1652        <label class="setting caption">
     1653            <span><?php _e('Caption'); ?></span>
     1654            <textarea data-setting="caption" />
     1655        </label>
     1656
     1657        <label class="setting alt-text">
     1658            <span><?php _e('Alt Text'); ?></span>
     1659            <input type="text" data-setting="alt" />
     1660        </label>
     1661
     1662        <label class="setting align">
     1663            <span><?php _e('Align'); ?></span>
     1664            <div class="button-group button-large" data-setting="align">
     1665                <button class="button" value="left">
     1666                    <?php esc_attr_e('Left'); ?>
     1667                </button>
     1668                <button class="button" value="center">
     1669                    <?php esc_attr_e('Center'); ?>
     1670                </button>
     1671                <button class="button" value="right">
     1672                    <?php esc_attr_e('Right'); ?>
     1673                </button>
     1674                <button class="button active" value="none">
     1675                    <?php esc_attr_e('None'); ?>
     1676                </button>
     1677            </div>
     1678        </label>
     1679
     1680        <div class="setting link-to">
     1681            <span><?php _e('Link To'); ?></span>
     1682            <div class="button-group button-large" data-setting="link">
     1683                <button class="button" value="file">
     1684                    <?php esc_attr_e('Image URL'); ?>
     1685                </button>
     1686                <button class="button" value="custom">
     1687                    <?php esc_attr_e('Custom URL'); ?>
     1688                </button>
     1689                <button class="button active" value="none">
     1690                    <?php esc_attr_e('None'); ?>
     1691                </button>
     1692            </div>
     1693            <input type="text" class="link-to-custom" data-setting="linkUrl" />
     1694        </div>
     1695    </script>
     1696
    16381697    <script type="text/html" id="tmpl-editor-attachment">
    16391698        <div class="editor-attachment-preview">
Note: See TracChangeset for help on using the changeset viewer.