Make WordPress Core

Changeset 41590


Ignore:
Timestamp:
09/25/2017 06:27:32 AM (9 years ago)
Author:
westonruter
Message:

Widgets: Introduce Gallery widget for displaying image galleries.

  • Galleries are managed in the widget in the same way they are managed in the post editor, both using the media manager.
  • Gallery widget is merged from the Core Media Widgets v0.2.0 feature plugin and it extends WP_Widget_Media in the same way as is done for image, audio, and video widgets.
  • Model syncing logic is updated to support booleans and arrays (of integers).
  • Placeholder areas in media widgets are now clickable shortcuts for selecting media.
  • Image widget placeholder is updated to match gallery widget where clicking preview is shortcut for editing media.

Props westonruter, joemcgill, timmydcrawford, m1tk00, obenland, melchoyce.
See #32417.
Fixes #41914.

Location:
trunk
Files:
4 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/widgets.css

    r41376 r41590  
    8888        border: 1px dashed #b4b9be;
    8989        box-sizing: border-box;
    90         cursor: default;
     90        cursor: pointer;
    9191        line-height: 20px;
    9292        padding: 9px 0;
     
    162162        margin: 1em 0;
    163163}
     164
     165.media-widget-gallery-preview {
     166        display: -webkit-box;
     167        display: flex;
     168        -webkit-box-pack: start;
     169        justify-content: flex-start;
     170        flex-wrap: wrap;
     171}
     172
     173.media-widget-preview.media_gallery,
     174.media-widget-preview.media_image {
     175        cursor: pointer;
     176}
     177
     178.media-widget-gallery-preview .gallery-item {
     179        box-sizing: border-box;
     180        width: 50%;
     181        margin: 0;
     182        padding: 1.79104477%;
     183}
     184
     185/*
     186 * Use targeted nth-last-child selectors to control the size of each image
     187 * based on how many gallery items are present in the grid.
     188 * See: https://alistapart.com/article/quantity-queries-for-css
     189 */
     190.media-widget-gallery-preview .gallery-item:nth-last-child(3):first-child,
     191.media-widget-gallery-preview .gallery-item:nth-last-child(3):first-child ~ .gallery-item,
     192.media-widget-gallery-preview .gallery-item:nth-last-child(n+5),
     193.media-widget-gallery-preview .gallery-item:nth-last-child(n+5) ~ .gallery-item,
     194.media-widget-gallery-preview .gallery-item:nth-last-child(n+6),
     195.media-widget-gallery-preview .gallery-item:nth-last-child(n+6) ~ .gallery-item {
     196        max-width: 33.33%;
     197}
     198
     199.media-widget-gallery-preview .gallery-item img {
     200        height: auto;
     201        vertical-align: bottom;
     202}
     203
     204.media-widget-gallery-preview .gallery-icon {
     205        position: relative;
     206}
     207
     208.media-widget-gallery-preview .gallery-icon-placeholder {
     209        position: absolute;
     210        top: 0;
     211        bottom: 0;
     212        width: 100%;
     213        box-sizing: border-box;
     214        display: -webkit-box;
     215        display: flex;
     216        -webkit-box-align: center;
     217        align-items: center;
     218        -webkit-box-pack: center;
     219        justify-content: center;
     220        background-color: rgba( 0, 0, 0, .5 );
     221}
     222
     223.media-widget-gallery-preview .gallery-icon-placeholder-text {
     224        font-weight: 600;
     225        font-size: 2em;
     226        color: white;
     227}
     228
    164229
    165230/* Widget Dragging Helpers */
  • trunk/src/wp-admin/js/widgets/media-image-widget.js

    r41252 r41590  
    2626
    2727                /**
     28                 * View events.
     29                 *
     30                 * @type {object}
     31                 */
     32                events: _.extend( {}, component.MediaWidgetControl.prototype.events, {
     33                        'click .media-widget-preview.populated': 'editMedia'
     34                } ),
     35
     36                /**
    2837                 * Render preview.
    2938                 *
     
    3948                        previewTemplate = wp.template( 'wp-media-widget-image-preview' );
    4049                        previewContainer.html( previewTemplate( control.previewTemplateProps.toJSON() ) );
     50                        previewContainer.addClass( 'populated' );
    4151
    4252                        linkInput = control.$el.find( '.link' );
  • trunk/src/wp-admin/js/widgets/media-widgets.js

    r41350 r41590  
    430430                        'click .notice-missing-attachment a': 'handleMediaLibraryLinkClick',
    431431                        'click .select-media': 'selectMedia',
     432                        'click .placeholder': 'selectMedia',
    432433                        'click .edit-media': 'editMedia'
    433434                },
     
    592593                        var control = this;
    593594                        control.syncContainer.find( '.media-widget-instance-property' ).each( function() {
    594                                 var input = $( this ), value;
    595                                 value = control.model.get( input.data( 'property' ) );
     595                                var input = $( this ), value, propertyName;
     596                                propertyName = input.data( 'property' );
     597                                value = control.model.get( propertyName );
    596598                                if ( _.isUndefined( value ) ) {
    597599                                        return;
    598600                                }
    599                                 value = String( value );
    600                                 if ( input.val() === value ) {
    601                                         return;
    602                                 }
    603                                 input.val( value );
    604                                 input.trigger( 'change' );
     601
     602                                if ( 'array' === control.model.schema[ propertyName ].type && _.isArray( value ) ) {
     603                                        value = value.join( ',' );
     604                                } else if ( 'boolean' === control.model.schema[ propertyName ].type ) {
     605                                        value = value ? '1' : ''; // Because in PHP, strval( true ) === '1' && strval( false ) === ''.
     606                                } else {
     607                                        value = String( value );
     608                                }
     609
     610                                if ( input.val() !== value ) {
     611                                        input.val( value );
     612                                        input.trigger( 'change' );
     613                                }
    605614                        });
    606615                },
     
    10031012                                }
    10041013                                type = model.schema[ name ].type;
    1005                                 if ( 'integer' === type ) {
     1014                                if ( 'array' === type ) {
     1015                                        castedAttrs[ name ] = value;
     1016                                        if ( ! _.isArray( castedAttrs[ name ] ) ) {
     1017                                                castedAttrs[ name ] = castedAttrs[ name ].split( /,/ ); // Good enough for parsing an ID list.
     1018                                        }
     1019                                        if ( model.schema[ name ].items && 'integer' === model.schema[ name ].items.type ) {
     1020                                                castedAttrs[ name ] = _.filter(
     1021                                                        _.map( castedAttrs[ name ], function( id ) {
     1022                                                                return parseInt( id, 10 );
     1023                                                        },
     1024                                                        function( id ) {
     1025                                                                return 'number' === typeof id;
     1026                                                        }
     1027                                                ) );
     1028                                        }
     1029                                } else if ( 'integer' === type ) {
    10061030                                        castedAttrs[ name ] = parseInt( value, 10 );
    10071031                                } else if ( 'boolean' === type ) {
  • trunk/src/wp-includes/default-widgets.php

    r41312 r41590  
    3232require_once( ABSPATH . WPINC . '/widgets/class-wp-widget-media-video.php' );
    3333
     34/** WP_Widget_Media_Gallery class */
     35require_once( ABSPATH . WPINC . '/widgets/class-wp-widget-media-gallery.php' );
     36
    3437/** WP_Widget_Meta class */
    3538require_once( ABSPATH . WPINC . '/widgets/class-wp-widget-meta.php' );
  • trunk/src/wp-includes/script-loader.php

    r41584 r41590  
    700700                $scripts->add( 'media-audio-widget', "/wp-admin/js/widgets/media-audio-widget$suffix.js", array( 'media-widgets', 'media-audiovideo' ) );
    701701                $scripts->add( 'media-image-widget', "/wp-admin/js/widgets/media-image-widget$suffix.js", array( 'media-widgets' ) );
     702                $scripts->add( 'media-gallery-widget', "/wp-admin/js/widgets/media-gallery-widget$suffix.js", array( 'media-widgets' ) );
    702703                $scripts->add( 'media-video-widget', "/wp-admin/js/widgets/media-video-widget$suffix.js", array( 'media-widgets', 'media-audiovideo', 'wp-api-request' ) );
    703704                $scripts->add( 'text-widgets', "/wp-admin/js/widgets/text-widgets$suffix.js", array( 'jquery', 'backbone', 'editor', 'wp-util', 'wp-a11y' ) );
  • trunk/src/wp-includes/widgets.php

    r41555 r41590  
    16101610        register_widget( 'WP_Widget_Media_Image' );
    16111611
     1612        register_widget( 'WP_Widget_Media_Gallery' );
     1613
    16121614        register_widget( 'WP_Widget_Media_Video' );
    16131615
  • trunk/src/wp-includes/widgets/class-wp-widget-media.php

    r41252 r41590  
    258258                        }
    259259                        $value = $new_instance[ $field ];
     260
     261                        // Workaround for rest_validate_value_from_schema() due to the fact that rest_is_boolean( '' ) === false, while rest_is_boolean( '1' ) is true.
     262                        if ( 'boolean' === $field_schema['type'] && '' === $value ) {
     263                                $value = false;
     264                        }
     265
    260266                        if ( true !== rest_validate_value_from_schema( $value, $field_schema, $field ) ) {
    261267                                continue;
     
    317323                                name="<?php echo esc_attr( $this->get_field_name( $name ) ); ?>"
    318324                                id="<?php echo esc_attr( $this->get_field_id( $name ) ); // Needed specifically by wpWidgets.appendTitle(). ?>"
    319                                 value="<?php echo esc_attr( strval( $value ) ); ?>"
     325                                value="<?php echo esc_attr( is_array( $value ) ? join( ',', $value ) : strval( $value ) ); ?>"
    320326                        />
    321327                <?php
     
    389395                                <input id="{{ elementIdPrefix }}title" type="text" class="widefat title">
    390396                        </p>
    391                         <div class="media-widget-preview">
     397                        <div class="media-widget-preview <?php echo esc_attr( $this->id_base ); ?>">
    392398                                <div class="attachment-media-view">
    393399                                        <div class="placeholder"><?php echo esc_html( $this->l10n['no_media_selected'] ); ?></div>
  • trunk/tests/qunit/index.html

    r41375 r41590  
    120120                        _.extend( wp.mediaWidgets.controlConstructors[ "media_audio" ].prototype.l10n, {"no_media_selected":"No audio selected","select_media":"Select File","change_media":"Change Audio","edit_media":"Edit Audio","add_to_widget":"Add to Widget","missing_attachment":"We can&#8217;t find that audio file. Check your <a href=\"http:\/\/src.wordpress-develop.dev\/wp-admin\/upload.php\">media library<\/a> and make sure it wasn&#8217;t deleted.","media_library_state_multi":{"0":"Audio Widget (%d)","1":"Audio Widget (%d)","singular":"Audio Widget (%d)","plural":"Audio Widget (%d)","context":null,"domain":null},"media_library_state_single":"Audio Widget"} );
    121121                </script>
     122                <script type='text/javascript' src='../../src/wp-admin/js/widgets/media-gallery-widget.js'></script>
     123                <script type='text/javascript'>
     124                        wp.mediaWidgets.modelConstructors[ "media_gallery" ].prototype.schema = {"title":{"type":"string","default":"","should_preview_update":false},"ids":{"type":"string","default":""},"columns":{"type":"integer","default":3},"size":{"type":"string","default":"thumbnail","enum":["thumbnail","medium","medium_large","large","post-thumbnail","full","custom"]},"link_type":{"type":"string","default":"none","enum":["none","file","post"],"media_prop":"link","should_preview_update":false},"orderby_random":{"type":"boolean","default":false,"media_prop":"_orderbyRandom","should_preview_update":false},"attachments":{"type":"string","default":""}};
     125                        wp.mediaWidgets.controlConstructors[ "media_gallery" ].prototype.mime_type = "image";
     126
     127                        _.extend( wp.mediaWidgets.controlConstructors[ "media_gallery" ].prototype.l10n, {"no_media_selected":"No images selected","add_media":"Add Media","replace_media":"Replace Media","edit_media":"Edit Gallery","add_to_widget":"Add to Widget","missing_attachment":"We can&#8217;t find that gallery. Check your <a href=\"http:\/\/src.wordpress-develop.dev\/wp-admin\/upload.php\">media library<\/a> and make sure it wasn&#8217;t deleted.","media_library_state_multi":"","media_library_state_single":"","unsupported_file_type":"Looks like this isn&#8217;t the correct kind of file. Please link to an appropriate file instead.","select_media":"Select Images","change_media":"Add Image"} );
     128                </script>
    122129
    123130                <!-- Unit tests -->
     
    137144                <script src="wp-admin/js/widgets/test-media-widgets.js"></script>
    138145                <script src="wp-admin/js/widgets/test-media-image-widget.js"></script>
     146                <script src="wp-admin/js/widgets/test-media-gallery-widget.js"></script>
    139147                <script src="wp-admin/js/widgets/test-media-video-widget.js"></script>
    140148
     
    570578                                </div><!-- #available-widgets -->
    571579                        </div><!-- #widgets-left -->
    572                        
     580
    573581                        <script type="text/html" id="tmpl-widget-media-media_image-control">
    574582                        <# var elementIdPrefix = 'el' + String( Math.random() ) + '_' #>
     
    811819                <div class="media-frame-uploader"></div>
    812820        </script>
     821
     822        <script type="text/html" id="tmpl-widget-media-media_gallery-control">
     823                <# var elementIdPrefix = 'el' + String( Math.random() ) + '_' #>
     824                <p>
     825                        <label for="{{ elementIdPrefix }}title">Title:</label>
     826                        <input id="{{ elementIdPrefix }}title" type="text" class="widefat title">
     827                </p>
     828                <div class="media-widget-preview">
     829                        <div class="attachment-media-view">
     830                                <div class="placeholder">No images selected</div>
     831                        </div>
     832                        </div>
     833                        <p class="media-widget-buttons">
     834                                <button type="button" class="button edit-media selected">
     835                                        Edit Gallery                            </button>
     836                                <button type="button" class="button change-media select-media selected">
     837                                        Replace Media                           </button>
     838                                <button type="button" class="button select-media not-selected">
     839                                        Add Media                               </button>
     840                        </p>
     841                <div class="media-widget-fields">
     842                </div>
     843        </script>
     844                                <script type="text/html" id="tmpl-wp-media-widget-gallery-preview">
     845                        <# var describedById = 'describedBy-' + String( Math.random() ); #>
     846                        <# data.attachments = data.attachments ? JSON.parse(data.attachments) : ''; #>
     847                        <# if ( Array.isArray( data.attachments ) && data.attachments.length ) { #>
     848                                <div class="gallery gallery-columns-{{ data.columns }}">
     849                                        <# _.each( data.attachments, function( attachment, index ) { #>
     850                                                <dl class="gallery-item">
     851                                                        <dt class="gallery-icon">
     852                                                        <# if ( attachment.sizes.thumbnail ) { #>
     853                                                                <img src="{{ attachment.sizes.thumbnail.url }}" width="{{ attachment.sizes.thumbnail.width }}" height="{{ attachment.sizes.thumbnail.height }}" alt="" />
     854                                                        <# } else { #>
     855                                                                <img src="{{ attachment.url }}" alt="" />
     856                                                        <# } #>
     857                                                        </dt>
     858                                                        <# if ( attachment.caption ) { #>
     859                                                                <dd class="wp-caption-text gallery-caption">
     860                                                                        {{{ data.verifyHTML( attachment.caption ) }}}
     861                                                                </dd>
     862                                                        <# } #>
     863                                                </dl>
     864                                                <# if ( index % data.columns === data.columns - 1 ) { #>
     865                                                        <br style="clear: both;">
     866                                                <# } #>
     867                                        <# } ); #>
     868                                </div>
     869                        <# } else { #>
     870                                <div class="attachment-media-view">
     871                                        <p class="placeholder">No images selected</p>
     872                                </div>
     873                        <# } #>
     874                </script>
    813875
    814876        <script type="text/html" id="tmpl-media-modal">
Note: See TracChangeset for help on using the changeset viewer.