WordPress.org

Make WordPress Core

Changeset 41590


Ignore:
Timestamp:
09/25/17 06:27:32 (2 months 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.