Make WordPress Core

Ticket #38342: 38342.22.diff

File 38342.22.diff, 26.8 KB (added by adamsilverstein, 8 years ago)
  • src/wp-admin/css/dashboard.css

    diff --git src/wp-admin/css/dashboard.css src/wp-admin/css/dashboard.css
    index 72b0230..3c7b618 100644
    form.initial-form.quickpress-open input#title { 
    518518        resize: none;
    519519}
    520520
     521#quick-press.is-saving .spinner {
     522        visibility: inherit;
     523}
     524
    521525/* Dashboard Quick Draft - Drafts list */
    522526
    523527.js #dashboard_quick_press .drafts {
    form.initial-form.quickpress-open input#title { 
    541545        margin: 0 12px;
    542546}
    543547
     548#dashboard_quick_press .drafts ul.is-placeholder li {
     549        padding: 3px 0;
     550        color: transparent;
     551}
     552
     553@-webkit-keyframes loading-fade {
     554
     555        0% {
     556                opacity: 0.5;
     557        }
     558
     559        50% {
     560                opacity: 1;
     561        }
     562
     563        100% {
     564                opacity: 0.5;
     565        }
     566}
     567
     568@keyframes loading-fade {
     569
     570        0% {
     571                opacity: 0.5;
     572        }
     573
     574        50% {
     575                opacity: 1;
     576        }
     577
     578        100% {
     579                opacity: 0.5;
     580        }
     581}
     582
     583#dashboard_quick_press .drafts ul.is-placeholder li:before,
     584#dashboard_quick_press .drafts ul.is-placeholder li:after {
     585        content: "";
     586        display: block;
     587        height: 13px;
     588        background: #eee;
     589        -webkit-animation: loading-fade 1.6s ease-in-out infinite;
     590        animation: loading-fade 1.6s ease-in-out infinite;
     591}
     592
     593#dashboard_quick_press .drafts ul.is-placeholder li:before {
     594        margin-bottom: 5px;
     595        width: 40%;
     596}
     597
     598#dashboard_quick_press .drafts ul.is-placeholder li:after {
     599        width: 80%;
     600}
     601
    544602#dashboard_quick_press .drafts li {
    545603        margin-bottom: 1em;
    546604}
     605
     606#dashboard_quick_press .drafts li.is-new {
     607        background-color: #fffbe5;
     608}
     609
    547610#dashboard_quick_press .drafts li time {
    548611        color: #72777c;
    549612}
  • src/wp-admin/includes/dashboard.php

    diff --git src/wp-admin/includes/dashboard.php src/wp-admin/includes/dashboard.php
    index 0ecf0a2..7107f3a 100644
    function wp_dashboard_quick_press( $error_msg = false ) { 
    494494        $post_ID = (int) $post->ID;
    495495?>
    496496
    497         <form name="post" action="<?php echo esc_url( admin_url( 'post.php' ) ); ?>" method="post" id="quick-press" class="initial-form hide-if-no-js">
    498 
    499                 <?php if ( $error_msg ) : ?>
    500                 <div class="error"><?php echo $error_msg; ?></div>
    501                 <?php endif; ?>
    502 
     497        <form name="post" method="post" id="quick-press" class="initial-form hide-if-no-js">
     498                <div class="notice notice-error notice-alt inline hidden"><p></p></div>
    503499                <div class="input-text-wrap" id="title-wrap">
    504                         <label class="screen-reader-text prompt" for="title" id="title-prompt-text">
     500                        <label class="prompt" for="title" id="title-prompt-text">
    505501
    506502                                <?php
    507503                                /** This filter is documented in wp-admin/edit-form-advanced.php */
    508504                                echo apply_filters( 'enter_title_here', __( 'Title' ), $post );
    509505                                ?>
    510506                        </label>
    511                         <input type="text" name="post_title" id="title" autocomplete="off" />
     507                        <input type="text" name="title" id="title" autocomplete="off" />
    512508                </div>
    513509
    514510                <div class="textarea-wrap" id="description-wrap">
    515                         <label class="screen-reader-text prompt" for="content" id="content-prompt-text"><?php _e( 'What&#8217;s on your mind?' ); ?></label>
     511                        <label class="prompt" for="content" id="content-prompt-text"><?php _e( 'What&#8217;s on your mind?' ); ?></label>
    516512                        <textarea name="content" id="content" class="mceEditor" rows="3" cols="15" autocomplete="off"></textarea>
    517513                </div>
    518 
    519514                <p class="submit">
    520                         <input type="hidden" name="action" id="quickpost-action" value="post-quickdraft-save" />
    521                         <input type="hidden" name="post_ID" value="<?php echo $post_ID; ?>" />
    522                         <input type="hidden" name="post_type" value="post" />
    523                         <?php wp_nonce_field( 'add-post' ); ?>
     515                        <div class="spinner no-float"></div>
    524516                        <?php submit_button( __( 'Save Draft' ), 'primary', 'save', false, array( 'id' => 'save-post' ) ); ?>
    525517                        <br class="clear" />
    526518                </p>
    527519
    528520        </form>
     521        <div id="quick-press-drafts" class="drafts">
     522                <p class="view-all" style="display: none;">
     523                        <a href="<?php echo esc_url( admin_url( 'edit.php?post_status=draft' ) ) ?>" aria-label="<?php esc_attr_e( 'View all drafts' ) ?>"><?php _ex( 'View all', 'drafts' ) ?></a>
     524                </p>
     525                <h2 class="hide-if-no-js"><?php _e( 'Drafts' ) ?></h2>
     526                <ul class="drafts-list is-placeholder">
     527                        <li><span class="screen-reader-text"><?php _e( 'Loading&hellip;' ) ?></span></li>
     528                </ul>
     529        </div>
     530        <script id="tmpl-item-quick-press-draft" type="text/template">
     531                <div class="draft-title">
     532                        <a href="<?php echo ( esc_url( admin_url( 'post.php?post={{ data.id }}&action=edit' ) ) ); ?>" aria-label="<?php esc_attr_e( 'Edit Post' ) ?>">{{ data.formattedTitle }}</a>
     533                        <time datetime="{{ data.date }}">{{ data.formattedDate }}</time>
     534                </div>
     535                {{{ data.formattedContent }}}
     536        </script>
    529537        <?php
    530         wp_dashboard_recent_drafts();
    531538}
    532539
    533540/**
    534541 * Show recent drafts of the user on the dashboard.
    535542 *
    536543 * @since 2.7.0
     544 * @deprecated 4.8.0
    537545 *
    538546 * @param array $drafts
    539547 */
    function wp_dashboard_recent_drafts( $drafts = false ) { 
    548556                        'order'          => 'DESC'
    549557                );
    550558
    551                 /**
    552                  * Filters the post query arguments for the 'Recent Drafts' dashboard widget.
    553                  *
    554                  * @since 4.4.0
    555                  *
    556                  * @param array $query_args The query arguments for the 'Recent Drafts' dashboard widget.
    557                  */
     559                /** This filter is documented in wp-includes/rest-api.php */
    558560                $query_args = apply_filters( 'dashboard_recent_drafts_query_args', $query_args );
    559561
    560562                $drafts = get_posts( $query_args );
  • src/wp-admin/js/dashboard.js

    diff --git src/wp-admin/js/dashboard.js src/wp-admin/js/dashboard.js
    index fa100dd..1e914f1 100644
     
    1 /* global pagenow, ajaxurl, postboxes, wpActiveEditor:true */
    2 var ajaxWidgets, ajaxPopulateWidgets, quickPressLoad;
     1/* global _, wp, quickDraft, pagenow, ajaxurl, postboxes, wpActiveEditor:true */
     2var ajaxWidgets, ajaxPopulateWidgets, QuickDraft = {};
    33
    44jQuery(document).ready( function($) {
    55        var welcomePanel = $( '#welcome-panel' ),
    jQuery(document).ready( function($) { 
    5959        };
    6060        ajaxPopulateWidgets();
    6161
    62         postboxes.add_postbox_toggles(pagenow, { pbshow: ajaxPopulateWidgets } );
    63 
    64         /* QuickPress */
    65         quickPressLoad = function() {
    66                 var act = $('#quickpost-action'), t;
    67 
    68                 $( '#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]' ).prop( 'disabled' , false );
    69 
    70                 t = $('#quick-press').submit( function( e ) {
    71                         e.preventDefault();
    72                         $('#dashboard_quick_press #publishing-action .spinner').show();
    73                         $('#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]').prop('disabled', true);
    74 
    75                         $.post( t.attr( 'action' ), t.serializeArray(), function( data ) {
    76                                 // Replace the form, and prepend the published post.
    77                                 $('#dashboard_quick_press .inside').html( data );
    78                                 $('#quick-press').removeClass('initial-form');
    79                                 quickPressLoad();
    80                                 highlightLatestPost();
    81                                 $('#title').focus();
    82                         });
    83 
    84                         function highlightLatestPost () {
    85                                 var latestPost = $('.drafts ul li').first();
    86                                 latestPost.css('background', '#fffbe5');
    87                                 setTimeout(function () {
    88                                         latestPost.css('background', 'none');
    89                                 }, 1000);
    90                         }
    91                 } );
    92 
    93                 $('#publish').click( function() { act.val( 'post-quickpress-publish' ); } );
    94 
    95                 $('#title, #tags-input, #content').each( function() {
    96                         var input = $(this), prompt = $('#' + this.id + '-prompt-text');
    97 
    98                         if ( '' === this.value ) {
    99                                 prompt.removeClass('screen-reader-text');
    100                         }
    101 
    102                         prompt.click( function() {
    103                                 $(this).addClass('screen-reader-text');
    104                                 input.focus();
    105                         });
    106 
    107                         input.blur( function() {
    108                                 if ( '' === this.value ) {
    109                                         prompt.removeClass('screen-reader-text');
    110                                 }
    111                         });
    112 
    113                         input.focus( function() {
    114                                 prompt.addClass('screen-reader-text');
    115                         });
    116                 });
     62        postboxes.add_postbox_toggles(pagenow, { pbshow: function( id ) {
     63                ajaxPopulateWidgets();
    11764
    118                 $('#quick-press').on( 'click focusin', function() {
    119                         wpActiveEditor = 'content';
    120                 });
    121 
    122                 autoResizeTextarea();
    123         };
    124         quickPressLoad();
     65                if ( 'dashboard_quick_press' === id ) {
     66                        QuickDraft.init();
     67                }
     68        } } );
    12569
    12670        $( '.meta-box-sortables' ).sortable( 'option', 'containment', '#wpwrap' );
    12771
    jQuery(document).ready( function($) { 
    186130                });
    187131        }
    188132
     133        autoResizeTextarea();
     134
     135        if ( jQuery( '#dashboard_quick_press' ).is( ':visible' ) ) {
     136                QuickDraft.init();
     137        }
     138});
     139
     140// Set up the QuickDraft views.
     141QuickDraft.Views = {};
     142
     143/**
     144 * Set up a view object for the quick draft form.
     145 *
     146 * @since 4.8.0
     147 *
     148 * @augments wp.Backbone.View
     149 */
     150QuickDraft.Views.Form = wp.Backbone.View.extend( {
     151
     152        // Set up our default action handlers.
     153        events: {
     154
     155                // Hide the prompt whena field receives focus.
     156                'focus :input': 'hidePrompt',
     157
     158                // Possibly re-display the prompt when a field looses focus.
     159                'blur :input':  'showPrompt',
     160
     161                // Listen for a reset event, showing all prompts.
     162                'reset':        'showAllPrompts',
     163
     164                // Listed for and handle form submissions.
     165                'submit':       'handleFormSubmission'
     166        },
     167
     168        // Initialize the QuickDraft Form view.
     169        initialize: function() {
     170
     171                // Show all prompts in the form to begin.
     172                this.showAllPrompts();
     173
     174                // Rerender if the error state changes.
     175                quickDraft.state.on( 'change:errorState', _.bind( this.render, this ) );
     176        },
     177
     178        /**
     179         * Handle toggling of the helper prompts shown inside each field.
     180         *
     181         * Will only show the prompt if the field is empty.
     182         *
     183         * @param  {object}  element Field element containing the helper prompt.
     184         * @param  {boolean} visible Should the prompt be visible?
     185         */
     186        togglePrompt: function( element, visible ) {
     187                var $input = jQuery( element ),
     188                        hasContent = $input.val().length > 0;
     189
     190                // Set the visibility of the elements nearest prompt to passed 'visible' value.
     191                jQuery( element ).siblings( '.prompt' ).toggleClass( 'screen-reader-text', ! visible || hasContent );
     192        },
     193
     194        // Show all of the field promts.
     195        showAllPrompts: function() {
     196
     197                // Show all of the field prompts.
     198                this.$el.find( ':input' ).each( _.bind( function( i, input ) {
     199                        _.defer( _.bind( this.togglePrompt, this, input, true ) );
     200                }, this ) );
     201        },
     202
     203        /**
     204         * Show the prompt inside a field.
     205         *
     206         * @param {object} event The event triggering this show request.
     207         */
     208        showPrompt: function( event ) {
     209                this.togglePrompt( event.target, true );
     210        },
     211
     212        /**
     213         * Hide the prompt inside a field.
     214         *
     215         * @param {object} event The event triggering this hide request.
     216         */
     217        hidePrompt: function( event ) {
     218                this.togglePrompt( event.target, false );
     219        },
     220
     221        /**
     222         * Handle error conditions.
     223         *
     224         * {string} error The error condition, or false to reset.
     225         */
     226        setErrorState: function( error ) {
     227
     228                // Set or reset the app state error condition.
     229                quickDraft.state.set( 'errorState', error );
     230
     231                if ( false !== error ) {
     232
     233                        // Alert screen readers that an error occurred.
     234                        wp.a11y.speak( error, 'assertive' );
     235                }
     236
     237        },
     238
     239        /**
     240         * Handle the form submission event.
     241         *
     242         * @param {object} event The form submission event.
     243         */
     244        handleFormSubmission: function( event ) {
     245                var values,
     246                        hasValuesToSave = false;
     247
     248                // Prevent the browser's default form submission handling.
     249                event.preventDefault();
     250
     251                // Prevent double submissions by checking the submitting state.
     252                if ( quickDraft.state.get( 'submitting' ) ) {
     253                        return;
     254                }
     255
     256                // Reset the error state.
     257                this.setErrorState( false );
     258
     259                // Extract the form field values.
     260                values = _.reduce( this.$el.serializeArray(), function( memo, field ) {
     261                        memo[ field.name ] = field.value;
     262                        hasValuesToSave    = hasValuesToSave || ( '' !== field.value );
     263                        return memo;
     264                }, {} );
     265
     266                // If the values are all blank, show an error.
     267                if ( ! hasValuesToSave ) {
     268
     269                        // Set the error.
     270                        this.setErrorState( quickDraft.l10n.errorEmptyFields );
     271                        return;
     272                }
     273
     274                // Save the new values to the model and confirm they are valid.
     275                this.model.set( values );
     276                if ( ! this.model.isValid() ) {
     277                        return;
     278                }
     279
     280                // Show a spinner during the callback.
     281                this.$el.addClass( 'is-saving' );
     282
     283
     284                // Set the state sbmitting to avoid double saves
     285                quickDraft.state.set( 'submitting', true );
     286
     287                // Trigger the model save.
     288                this.model.save()
     289
     290                        // Always remove the spinner.
     291                        .always(
     292                                _.bind( function() {
     293                                        this.$el.removeClass( 'is-saving' );
     294
     295                                        // Refocus in the title field, hiding its prompt.
     296                                        _.delay( function() { jQuery( '#quick-press input#title' ).focus(); }, 250 );
     297
     298                                        // Submission complete
     299                                        quickDraft.state.set( 'submitting', false );
     300
     301                                }, this )
     302                        )
     303
     304                        // Handle save success.
     305                        .success(
     306                                _.bind( function() {
     307                                        // Success! Clear any previous error state.
     308                                         this.render();
     309
     310                                        // Add the post model to the head of our collection.
     311                                        this.collection.add( this.model, { at: 0 } );
     312
     313                                        // Create a new post model to contain the form data and reset the form.
     314                                        this.model = new wp.api.models.Post();
     315                                        this.model.on( 'change:errorState', _.bind( this.render, this ) );
     316
     317                                        this.el.reset();
     318                                }, this )
     319                        )
     320
     321                        // Handle save failure.
     322                        .error(
     323                                _.bind( function( model, error ) {
     324                                        var message = '';
     325
     326                                        // Try to parse and use the response message.
     327                                        try {
     328                                                message = JSON.parse( error.responseText ).message;
     329                                        } catch( e ) {
     330
     331                                                // Fall back to a default error string if the parse fails.
     332                                                message = quickDraft.l10n.error;
     333                                        }
     334
     335                                        // Set the app error condition.
     336                                        this.setErrorState( message );
     337                                }, this )
     338                        );
     339        },
     340
     341        // Render the form view.
     342        render: function() {
     343                var $error    = this.$el.find( '.notice-alt' ),
     344                        errorText = quickDraft.state.get( 'errorState' );
     345
     346                // Error notice is only visible if error text is set.
     347                $error.toggleClass( 'hidden', ! errorText );
     348                if ( errorText ) {
     349
     350                        // Note: The inner text transform prevents XSS via html().
     351                        $error.html( jQuery( '<p />', { text: errorText } ) );
     352                }
     353        }
     354} );
     355
     356/**
     357 * Set up a view object for the Quick Draft list of drafts.
     358 *
     359 * @since 4.8.0
     360 *
     361 * @augments wp.Backbone.View
     362 */
     363QuickDraft.Views.DraftList = wp.Backbone.View.extend( {
     364
     365        // Initialize the draft list view.
     366        initialize: function() {
     367
     368                // Render the view once the drafts have loaded.
     369                this.listenTo( this.collection, 'sync', this.onDraftsLoaded );
     370        },
     371
     372        // Once the drafts have loaded, complete the setup.
     373        onDraftsLoaded: function() {
     374
     375                // Add a listener for new items added to the underlying (draft) post collection.
     376                this.listenTo( this.collection, 'add', this.renderNew );
     377
     378                // Render the view!
     379                this.render();
     380        },
     381
     382        // Handle a new item being added to the collection.
     383        renderNew: function() {
     384
     385                // Display highlight effect to first (added) item for one second.
     386                var $newEl = this.render().$el.find( 'li:first' ).addClass( 'is-new' );
     387                setTimeout( function() {
     388                        $newEl.removeClass( 'is-new' );
     389                }, 1000 );
     390
     391                // Alert screen readers that a new draft has been added.
     392                wp.a11y.speak( quickDraft.l10n.newDraftCreated, 'assertive' );
     393        },
     394
     395        // Render the draft post list view.
     396        render: function() {
     397
     398                // Hide drafts list entirely if no drafts exist.
     399                this.$el.toggle( this.collection.length > 0 );
     400
     401                // Display a 'View All' link if there are more drafts available.
     402                this.$el.find( '.view-all' ).toggle( this.collection.hasMore() );
     403
     404                // Remove the placeholder class and render the models.
     405                this.$el.find( '.drafts-list' )
     406                        .removeClass( 'is-placeholder' )
     407                        .html(
     408                                _.map( this.collection.models, function( draft ) {
     409                                        return new QuickDraft.Views.DraftListItem( {
     410                                                model: draft
     411                                        } ).render().el;
     412                                } )
     413                        );
     414
     415                return this;
     416        }
    189417} );
     418
     419/**
     420 * Set up a view object an individual draft in the draft list.
     421 *
     422 * @since 4.8.0
     423 *
     424 * @augments wp.Backbone.View
     425 */
     426QuickDraft.Views.DraftListItem = wp.Backbone.View.extend( {
     427        tagName: 'li',
     428
     429        // Render beased on the passed template.
     430        template: wp.template( 'item-quick-press-draft' ),
     431
     432        // Render a single draft list item.
     433        render: function() {
     434
     435                // Clone the original model attributes, so we can leave the model untouched.
     436                var attributes = _.clone( this.model.attributes );
     437
     438                // Trim the content to 10 words.
     439                attributes.formattedContent = wp.formatting.trimWords( attributes.content.rendered, 10 );
     440
     441                // If the title is missing entirely, add a no title placeholder.
     442                attributes.formattedTitle = attributes.title.rendered.length > 0 ? attributes.title.rendered : quickDraft.l10n.noTitle;
     443
     444                // Format the data using Intl.DateTimeFormat with a fallback to date.toLocaleDateString.
     445                var date = new Date( wp.api.utils.parseISO8601( attributes.date + quickDraft.timezoneOffset ) );
     446                if ( 'undefined' !== typeof Intl && Intl.DateTimeFormat ) {
     447                        attributes.formattedDate = new Intl.DateTimeFormat( undefined, {
     448                                month: 'long',
     449                                day: 'numeric',
     450                                year: 'numeric'
     451                        } ).format( date );
     452                } else {
     453                        attributes.formattedDate = date.toLocaleDateString();
     454                }
     455
     456                // Output the rendered template.
     457                this.$el.html( this.template( attributes ) );
     458
     459                // Continue the rendering chain.
     460                return this;
     461        }
     462} );
     463
     464
     465/**
     466 * Initialize the Quick Draft feature.
     467 *
     468 * @since 4.8.0
     469 *
     470 */
     471QuickDraft.init = function() {
     472
     473        // Set up a state model to track the application state.
     474        quickDraft.state = new Backbone.Model({
     475                'errorState': false
     476        });
     477
     478        // Wait for the wp-api client to initialize.
     479        wp.api.loadPromise.done( function() {
     480
     481                // Fetch up to 4 of the current user's recent drafts by extending wp.api.collections.Posts.
     482                var draftsCollection = new wp.api.collections.Posts();
     483                draftsCollection.fetch( {
     484                        data: {
     485                                status: 'draft',
     486                                author: quickDraft.currentUserId,
     487                                per_page: 4,
     488                                order_by: 'date',
     489                                'quick-draft-post-list': true /* flag passed for back end filters */
     490                        }
     491                } );
     492
     493                // Drafts list is initialized but not rendered until drafts load.
     494                new QuickDraft.Views.DraftList( {
     495                        el: '#quick-press-drafts',
     496                        collection: draftsCollection
     497                } );
     498
     499                new QuickDraft.Views.Form( {
     500                        el: '#quick-press',
     501                        model: new wp.api.models.Post(),
     502                        collection: draftsCollection
     503                } ).render();
     504        });
     505};
  • src/wp-includes/js/wp-util.js

    diff --git src/wp-includes/js/wp-util.js src/wp-includes/js/wp-util.js
    index 527441d..bdc7531 100644
    window.wp = window.wp || {}; 
    121121                }
    122122        };
    123123
     124        // wp.formatting
     125        // ------
     126        //
     127        // Tools for formatting strings
     128        wp.formatting = {
     129                settings: settings.formatting || {},
     130
     131                /**
     132                 * Trims text to a certain number of words.
     133                 *
     134                 * @see wp_trim_words
     135                 *
     136                 * @param  {string} text     Text to trim.
     137                 * @param  {number} numWords Number of words. Optional, default is 55.
     138                 * @param  {string} more     What to append if text needs to be trimmed. Optional, default is '…'.
     139                 * @return {string}          Trimmed text.
     140                 */
     141                trimWords: function( text, numWords, more ) {
     142                        var words, separator;
     143
     144                        if ( 'undefined' === typeof numWords ) {
     145                                numWords = 55;
     146                        }
     147
     148                        if ( 'undefined' === typeof more ) {
     149                                more = wp.formatting.settings.trimWordsMore;
     150                        }
     151
     152                        text = text.replace( /[\n\r\t ]+/g, ' ' ).replace( /^ | $/g, '' );
     153
     154                        if ( wp.formatting.settings.trimWordsByCharacter ) {
     155                                separator = '';
     156                        } else {
     157                                separator = ' ';
     158                        }
     159
     160                        words = text.split( separator );
     161
     162                        if ( words.length <= numWords ) {
     163                                return words.join( separator );
     164                        }
     165
     166                        return words.slice( 0, numWords ).join( separator ) + more;
     167                }
     168        };
     169
    124170}(jQuery));
  • src/wp-includes/rest-api.php

    diff --git src/wp-includes/rest-api.php src/wp-includes/rest-api.php
    index 3d0b7ee..3711e32 100644
    function rest_api_default_filters() { 
    164164        add_filter( 'rest_post_dispatch', 'rest_send_allow_header', 10, 3 );
    165165
    166166        add_filter( 'rest_pre_dispatch', 'rest_handle_options_request', 10, 3 );
     167
     168        // Legacy filter for Quick Draft recent posts.
     169        add_filter( 'rest_post_query', 'rest_filter_quick_draft_query', 10, 2 );
     170}
     171
     172/**
     173 * Filter query args used by he Quick Draft recent posts list.
     174 *
     175 * @param array           $args    Key value array of query var to query value.
     176 * @param WP_REST_Request $request The request used.
     177 */
     178function rest_filter_quick_draft_query( $query_args, $request ) {
     179
     180        // Only modify Quick Draft queries.
     181        $params = $request->get_query_params();
     182
     183        if ( ! isset( $params['quick-draft-post-list'] ) ) {
     184                return $query_args;
     185        }
     186
     187        /**
     188         * Filters the post query arguments for the 'Recent Drafts' dashboard widget.
     189         *
     190         * @since 4.4.0
     191         *
     192         * @param array $query_args The query arguments for the 'Recent Drafts' dashboard widget.
     193         */
     194        $query_args = apply_filters( 'dashboard_recent_drafts_query_args', $query_args );
     195
     196        return $query_args;
     197
    167198}
    168199
    169200/**
  • src/wp-includes/script-loader.php

    diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
    index be32073..c10fa11 100644
    function wp_default_scripts( &$scripts ) { 
    336336                'ajax' => array(
    337337                        'url' => admin_url( 'admin-ajax.php', 'relative' ),
    338338                ),
     339                'formatting' => array(
     340                        'trimWordsMore'  => __( '&hellip;' ),
     341                        /*
     342                         * translators: If your word count is based on single characters (e.g. East Asian characters),
     343                         * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
     344                         * Do not translate into your own language.
     345                         */
     346                        'trimWordsByCharacter' => strpos( _x( 'words', 'Word count type. Do not translate!' ), 'characters' ) === 0 && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ),
     347                ),
    339348        ) );
    340349
    341350        $scripts->add( 'wp-backbone', "/wp-includes/js/wp-backbone$suffix.js", array('backbone', 'wp-util'), false, 1 );
    function wp_default_scripts( &$scripts ) { 
    721730                        'current' => __( 'Current Color' ),
    722731                ) );
    723732
    724                 $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox' ), false, 1 );
     733                $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-api', 'wp-backbone', 'wp-a11y', 'wp-util' ), false, 1 );
     734                did_action( 'init' ) && $scripts->localize( 'dashboard', 'quickDraft', array(
     735                        'currentUserId'  => get_current_user_id(),
     736                        'l10n' => array(
     737                                'error'            => __( 'An error has occurred. Please reload the page and try again.' ),
     738                                'newDraftCreated'  => __( 'Success. A new draft was created.' ),
     739                                'errorEmptyFields' => __( 'Error. All fields were empty.' ),
     740                                'noTitle'          => __( '(no title)' ),
     741                        ),
     742                        'timezoneOffset' => ( get_option( 'gmt_offset' ) >= 0 ? '+' : '-' ) . date( 'H:i', abs( get_option( 'gmt_offset' ) * 3600 ) ),
     743                ) );
    725744
    726745                $scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" );
    727746
  • tests/qunit/index.html

    diff --git tests/qunit/index.html tests/qunit/index.html
    index 9a17ec2..baf0f46 100644
     
    6161                <script src="wp-admin/js/customize-base.js"></script>
    6262                <script src="wp-admin/js/customize-header.js"></script>
    6363                <script src="wp-includes/js/shortcode.js"></script>
     64                <script src="wp-includes/js/wp-util.js"></script>
    6465                <script src="wp-admin/js/customize-controls.js"></script>
    6566                <script src="wp-admin/js/customize-controls-utils.js"></script>
    6667                <script src="wp-admin/js/customize-nav-menus.js"></script>
  • new file tests/qunit/wp-includes/js/wp-util.js

    diff --git tests/qunit/wp-includes/js/wp-util.js tests/qunit/wp-includes/js/wp-util.js
    new file mode 100644
    index 0000000..a627585
    - +  
     1/* global wp */
     2( function( QUnit ) {
     3        wp.formatting.settings.trimWordsMore = '&hellip;';
     4        QUnit.module( 'wp-util' );
     5        var longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce varius lacinia vehicula. Etiam sapien risus, ultricies ac posuere eu, convallis sit amet augue. Pellentesque urna massa, lacinia vel iaculis eget, bibendum in mauris. Aenean eleifend pulvinar ligula, a convallis eros gravida non. Suspendisse potenti. Pellentesque et odio tortor. In vulputate pellentesque libero, sed dapibus velit mollis viverra. Pellentesque id urna euismod dolor cursus sagittis.';
     6
     7        QUnit.test( 'wp.formatting.trimWords', function( assert ) {
     8                _.each( [
     9                        {
     10                                'trimmed': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce varius lacinia vehicula. Etiam sapien risus, ultricies ac posuere eu, convallis sit amet augue. Pellentesque urna massa, lacinia vel iaculis eget, bibendum in mauris. Aenean eleifend pulvinar ligula, a convallis eros gravida non. Suspendisse potenti. Pellentesque et odio tortor. In vulputate pellentesque libero, sed dapibus velit&hellip;',
     11                                'text': longText,
     12                                'description': 'Trims to 55 by default.'
     13                        },
     14                        {
     15                                'trimmed': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce varius&hellip;',
     16                                'text': longText,
     17                                'length': 10,
     18                                'description': 'Trims to 10.'
     19                        },
     20                        {
     21                                'trimmed': 'Lorem ipsum dolor sit amet,[...] Read on!',
     22                                'text': longText,
     23                                'description': 'Trims to 5 and uses custom more.',
     24                                'length': 5,
     25                                'more': '[...] Read on!'
     26                        },
     27                        {
     28                                'trimmed': 'This is some short text.',
     29                                'text': 'This is some short text.',
     30                                'description': 'Doesn\'t strip short text.'
     31                        }
     32
     33                ], function( test ) {
     34                        assert.equal(
     35                                wp.formatting.trimWords( test.text, test.length, test.more ),
     36                                test.trimmed,
     37                                test.description
     38                        );
     39                } );
     40        } );
     41} )( window.QUnit );
     42( function( QUnit ) {
     43        wp.formatting.settings.trimWordsMore = '&hellip;';
     44        QUnit.module( 'wp-util' );
     45        var longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce varius lacinia vehicula. Etiam sapien risus, ultricies ac posuere eu, convallis sit amet augue. Pellentesque urna massa, lacinia vel iaculis eget, bibendum in mauris. Aenean eleifend pulvinar ligula, a convallis eros gravida non. Suspendisse potenti. Pellentesque et odio tortor. In vulputate pellentesque libero, sed dapibus velit mollis viverra. Pellentesque id urna euismod dolor cursus sagittis.';
     46
     47        QUnit.test( 'wp.formatting.trimWords', function( assert ) {
     48                _.each( [
     49                        {
     50                                'trimmed': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce varius lacinia vehicula. Etiam sapien risus, ultricies ac posuere eu, convallis sit amet augue. Pellentesque urna massa, lacinia vel iaculis eget, bibendum in mauris. Aenean eleifend pulvinar ligula, a convallis eros gravida non. Suspendisse potenti. Pellentesque et odio tortor. In vulputate pellentesque libero, sed dapibus velit&hellip;',
     51                                'text': longText,
     52                                'description': 'Trims to 55 by default.'
     53                        },
     54                        {
     55                                'trimmed': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce varius&hellip;',
     56                                'text': longText,
     57                                'length': 10,
     58                                'description': 'Trims to 10.'
     59                        },
     60                        {
     61                                'trimmed': 'Lorem ipsum dolor sit amet,[...] Read on!',
     62                                'text': longText,
     63                                'description': 'Trims to 5 and uses custom more.',
     64                                'length': 5,
     65                                'more': '[...] Read on!'
     66                        },
     67                        {
     68                                'trimmed': 'This is some short text.',
     69                                'text': 'This is some short text.',
     70                                'description': 'Doesn\'t strip short text.'
     71                        }
     72
     73                ], function( test ) {
     74                        assert.equal(
     75                                wp.formatting.trimWords( test.text, test.length, test.more ),
     76                                test.trimmed,
     77                                test.description
     78                        );
     79                } );
     80        } );
     81} )( window.QUnit );