Ticket #38342: 38342.23.diff
File 38342.23.diff, 28.8 KB (added by , 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 { 518 518 resize: none; 519 519 } 520 520 521 #quick-press.is-saving .spinner { 522 visibility: inherit; 523 } 524 521 525 /* Dashboard Quick Draft - Drafts list */ 522 526 523 527 .js #dashboard_quick_press .drafts { … … form.initial-form.quickpress-open input#title { 541 545 margin: 0 12px; 542 546 } 543 547 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 544 602 #dashboard_quick_press .drafts li { 545 603 margin-bottom: 1em; 546 604 } 605 606 #dashboard_quick_press .drafts li.is-new { 607 background-color: #fffbe5; 608 } 609 547 610 #dashboard_quick_press .drafts li time { 548 611 color: #72777c; 549 612 } -
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 ) { 494 494 $post_ID = (int) $post->ID; 495 495 ?> 496 496 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> 503 499 <div class="input-text-wrap" id="title-wrap"> 504 <label class=" screen-reader-textprompt" for="title" id="title-prompt-text">500 <label class="prompt" for="title" id="title-prompt-text"> 505 501 506 502 <?php 507 503 /** This filter is documented in wp-admin/edit-form-advanced.php */ 508 504 echo apply_filters( 'enter_title_here', __( 'Title' ), $post ); 509 505 ?> 510 506 </label> 511 <input type="text" name=" post_title" id="title" autocomplete="off" />507 <input type="text" name="title" id="title" autocomplete="off" /> 512 508 </div> 513 509 514 510 <div class="textarea-wrap" id="description-wrap"> 515 <label class=" screen-reader-textprompt" for="content" id="content-prompt-text"><?php _e( 'What’s on your mind?' ); ?></label>511 <label class="prompt" for="content" id="content-prompt-text"><?php _e( 'What’s on your mind?' ); ?></label> 516 512 <textarea name="content" id="content" class="mceEditor" rows="3" cols="15" autocomplete="off"></textarea> 517 513 </div> 518 519 514 <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> 524 516 <?php submit_button( __( 'Save Draft' ), 'primary', 'save', false, array( 'id' => 'save-post' ) ); ?> 525 517 <br class="clear" /> 526 518 </p> 527 519 528 520 </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…' ) ?></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> 529 537 <?php 530 wp_dashboard_recent_drafts();531 538 } 532 539 533 540 /** 534 541 * Show recent drafts of the user on the dashboard. 535 542 * 536 543 * @since 2.7.0 544 * @deprecated 4.8.0 537 545 * 538 546 * @param array $drafts 539 547 */ … … function wp_dashboard_recent_drafts( $drafts = false ) { 548 556 'order' => 'DESC' 549 557 ); 550 558 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 */ 558 560 $query_args = apply_filters( 'dashboard_recent_drafts_query_args', $query_args ); 559 561 560 562 $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..53a2a94 100644
1 /* global pagenow, ajaxurl, postboxes, wpActiveEditor:true */2 var ajaxWidgets, ajaxPopulateWidgets, quickPressLoad;1 /* global _, wp, quickDraft, pagenow, ajaxurl, postboxes, wpActiveEditor:true */ 2 var ajaxWidgets, ajaxPopulateWidgets, QuickDraft = {}; 3 3 4 4 jQuery(document).ready( function($) { 5 5 var welcomePanel = $( '#welcome-panel' ), … … jQuery(document).ready( function($) { 59 59 }; 60 60 ajaxPopulateWidgets(); 61 61 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(); 117 64 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 } } ); 125 69 126 70 $( '.meta-box-sortables' ).sortable( 'option', 'containment', '#wpwrap' ); 127 71 … … jQuery(document).ready( function($) { 186 130 }); 187 131 } 188 132 133 autoResizeTextarea(); 134 135 if ( jQuery( '#dashboard_quick_press' ).is( ':visible' ) ) { 136 QuickDraft.init(); 137 } 138 }); 139 140 // Set up the QuickDraft views. 141 QuickDraft.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 */ 150 QuickDraft.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 jQuery( element ).siblings( '.prompt' ).toggleClass( 'screen-reader-text', ! visible || hasContent ); 191 }, 192 193 // Show all of the field promts. 194 showAllPrompts: function() { 195 this.$el.find( ':input' ).each( _.bind( function( i, input ) { 196 197 // Prompt toggling must be deferred because the reset event is 198 // fired before the input values have been cleared 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 */ 363 QuickDraft.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 } 189 417 } ); 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 */ 426 QuickDraft.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 var attributes, date; 435 436 // Clone the original model attributes, so we can leave the model untouched. 437 attributes = _.clone( this.model.attributes ); 438 439 // Trim the content to 10 words. 440 attributes.formattedContent = wp.formatting.trimWords( attributes.content.rendered, 10 ); 441 442 // If the title is missing entirely, add a no title placeholder. 443 attributes.formattedTitle = attributes.title.rendered.length > 0 ? attributes.title.rendered : quickDraft.l10n.noTitle; 444 445 // Format the date 446 attributes.formattedDate = wp.formatting.date( wp.api.utils.parseISO8601( attributes.date ) ); 447 448 // Output the rendered template. 449 this.$el.html( this.template( attributes ) ); 450 451 // Continue the rendering chain. 452 return this; 453 } 454 } ); 455 456 457 /** 458 * Initialize the Quick Draft feature. 459 * 460 * @since 4.8.0 461 * 462 */ 463 QuickDraft.init = function() { 464 465 // Set up a state model to track the application state. 466 quickDraft.state = new Backbone.Model({ 467 'errorState': false 468 }); 469 470 // Wait for the wp-api client to initialize. 471 wp.api.loadPromise.done( function() { 472 473 // Fetch up to 4 of the current user's recent drafts by extending wp.api.collections.Posts. 474 var draftsCollection = new wp.api.collections.Posts(); 475 draftsCollection.fetch( { 476 data: { 477 status: 'draft', 478 author: quickDraft.currentUserId, 479 per_page: 4, 480 order_by: 'date', 481 'quick-draft-post-list': true /* flag passed for back end filters */ 482 } 483 } ); 484 485 // Drafts list is initialized but not rendered until drafts load. 486 new QuickDraft.Views.DraftList( { 487 el: '#quick-press-drafts', 488 collection: draftsCollection 489 } ); 490 491 new QuickDraft.Views.Form( { 492 el: '#quick-press', 493 model: new wp.api.models.Post(), 494 collection: draftsCollection 495 } ).render(); 496 }); 497 }; -
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..abf796f 100644
window.wp = window.wp || {}; 121 121 } 122 122 }; 123 123 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 /** 170 * Given optional date and format string, returns a localized date 171 * string approximating specified format. Uses browser i18n features 172 * when available, with fallback. Undefined arguments default to now 173 * and site configured date format respectively. 174 * 175 * @see http://php.net/manual/en/function.date.php 176 * 177 * @param {?*} date Optional date object or timestamp, defaults 178 * to now 179 * @param {?String} format Optional PHP date format string, defaults 180 * to site date format option 181 * @return {String} Localized formatted date string 182 */ 183 date: function( date, format ) { 184 var options, matches, m, ml, character, locales; 185 186 // Cast date parameter to date object. This accommodates timestamp, 187 // Date object, ISO8601 string, and undefined (defaulting to now). 188 date = new Date( date ); 189 190 // Adjust JavaScript date from local browser timezone to GMT+0 191 date.setTime( date.getTime() + ( date.getTimezoneOffset() * 60000 ) ); 192 193 // If no browser support for Intl, return fallback 194 if ( 'undefined' === typeof Intl || ! Intl.DateTimeFormat ) { 195 return date.toLocaleDateString(); 196 } 197 198 // Default format to site date option 199 if ( 'undefined' === typeof format ) { 200 format = wp.formatting.settings.dateFormat; 201 } 202 203 matches = format.match( /\\?[a-zA-Z]/g ); 204 if ( ! matches ) { 205 return format; 206 } 207 208 options = {}; 209 for ( m = 0, ml = matches.length; m < ml; m++ ) { 210 character = matches[ m ]; 211 212 // Ignore characters prefixed with backslash 213 if ( 0 === character.indexOf( '\\' ) ) { 214 continue; 215 } 216 217 switch ( character ) { 218 // Supported: 219 case 'd': options.day = '2-digit'; break; 220 case 'D': options.weekday = 'short'; break; 221 case 'j': options.day = 'numeric'; break; 222 case 'l': options.weekday = 'long'; break; 223 case 'F': options.month = 'long'; break; 224 case 'm': options.month = '2-digit'; break; 225 case 'M': options.month = 'short'; break; 226 case 'n': options.month = 'numeric'; break; 227 case 'Y': options.year = 'numeric'; break; 228 case 'y': options.year = '2-digit'; break; 229 case 'g': options.hour = 'numeric'; options.hour12 = true; break; 230 case 'G': options.hour = 'numeric'; options.hour12 = false; break; 231 case 'h': options.hour = '2-digit'; options.hour12 = true; break; 232 case 'H': options.hour = '2-digit'; options.hour12 = false; break; 233 case 'i': options.minute = '2-digit'; break; 234 case 's': options.second = '2-digit'; break; 235 case 'e': options.timeZoneName = 'long'; break; 236 case 'T': options.timeZoneName = 'short'; break; 237 case 'c': return date.toISOString(); 238 case 'U': return Number( date ); 239 240 // Unsupported with fallback: 241 case 'N': options.weekday = 'narrow'; break; 242 case 'w': options.weekday = 'narrow'; break; 243 case 'o': options.year = 'numeric'; break; 244 case 'O': options.timeZoneName = 'short'; break; 245 case 'P': options.timeZoneName = 'short'; break; 246 case 'Z': options.timeZoneName = 'short'; break; 247 case 'r': return String( time ); 248 249 // Unsupported: 'S', 'z', 'W', 't', 'L', 'a', 'A', 'B', 'u', 'v', 'I' 250 } 251 } 252 253 locales = wp.formatting.settings.userLocale.replace( '_', '-' ); 254 return new Intl.DateTimeFormat( locales, options ).format( date ); 255 } 256 }; 257 124 258 }(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() { 164 164 add_filter( 'rest_post_dispatch', 'rest_send_allow_header', 10, 3 ); 165 165 166 166 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 */ 178 function 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 167 198 } 168 199 169 200 /** -
src/wp-includes/script-loader.php
diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php index be32073..02f665b 100644
function wp_default_scripts( &$scripts ) { 336 336 'ajax' => array( 337 337 'url' => admin_url( 'admin-ajax.php', 'relative' ), 338 338 ), 339 'formatting' => array( 340 'trimWordsMore' => __( '…' ), 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 'userLocale' => get_user_locale(), 348 'dateFormat' => get_option( 'date_format' ), 349 ), 339 350 ) ); 340 351 341 352 $scripts->add( 'wp-backbone', "/wp-includes/js/wp-backbone$suffix.js", array('backbone', 'wp-util'), false, 1 ); … … function wp_default_scripts( &$scripts ) { 721 732 'current' => __( 'Current Color' ), 722 733 ) ); 723 734 724 $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox' ), false, 1 ); 735 $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-api', 'wp-backbone', 'wp-a11y', 'wp-util' ), false, 1 ); 736 did_action( 'init' ) && $scripts->localize( 'dashboard', 'quickDraft', array( 737 'currentUserId' => get_current_user_id(), 738 'l10n' => array( 739 'error' => __( 'An error has occurred. Please reload the page and try again.' ), 740 'newDraftCreated' => __( 'Success. A new draft was created.' ), 741 'errorEmptyFields' => __( 'Error. All fields were empty.' ), 742 'noTitle' => __( '(no title)' ), 743 ) 744 ) ); 725 745 726 746 $scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" ); 727 747 -
tests/qunit/index.html
diff --git tests/qunit/index.html tests/qunit/index.html index 9a17ec2..baf0f46 100644
61 61 <script src="wp-admin/js/customize-base.js"></script> 62 62 <script src="wp-admin/js/customize-header.js"></script> 63 63 <script src="wp-includes/js/shortcode.js"></script> 64 <script src="wp-includes/js/wp-util.js"></script> 64 65 <script src="wp-admin/js/customize-controls.js"></script> 65 66 <script src="wp-admin/js/customize-controls-utils.js"></script> 66 67 <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..b24ec49
- + 1 /* global wp, jQuery, _ */ 2 jQuery(function() { 3 var originalSettings, sampleText; 4 5 module( 'wp.formatting', { 6 beforeEach: function() { 7 originalSettings = _.clone( wp.formatting.settings ); 8 wp.formatting.settings.trimWordsMore = '…'; 9 }, 10 afterEach: function() { 11 wp.formatting.settings = originalSettings; 12 } 13 }); 14 15 sampleText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec velit' + 16 ' tellus, porta ac nisl vitae, gravida rutrum risus. Integer porttitor rhoncus' + 17 ' convallis. Vestibulum et rutrum nulla. Aliquam efficitur vehicula tempor. Aliquam' + 18 ' sodales ligula vitae lorem vulputate, vitae sagittis turpis volutpat. Donec sapien' + 19 ' justo, facilisis eget dignissim vel, ultrices nec est. Vestibulum tempor purus dolor,' + 20 ' tincidunt suscipit diam consectetur eu.'; 21 22 test( 'trimWords() should default numWords to 55', function() { 23 var expected, result; 24 25 result = wp.formatting.trimWords( sampleText ); 26 expected = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec velit tellus,' + 27 ' porta ac nisl vitae, gravida rutrum risus. Integer porttitor rhoncus convallis.' + 28 ' Vestibulum et rutrum nulla. Aliquam efficitur vehicula tempor. Aliquam sodales' + 29 ' ligula vitae lorem vulputate, vitae sagittis turpis volutpat. Donec sapien justo,' + 30 ' facilisis eget dignissim vel, ultrices nec est. Vestibulum tempor purus dolor,' + 31 ' tincidunt…'; 32 33 equal( result, expected ); 34 }); 35 36 test( 'trimWords() accepts custom numWords', function() { 37 var expected, result; 38 39 result = wp.formatting.trimWords( sampleText, 4 ); 40 expected = 'Lorem ipsum dolor sit…'; 41 42 equal( result, expected ); 43 }); 44 45 test( 'trimWords() accepts custom truncation', function() { 46 var expected, result; 47 48 result = wp.formatting.trimWords( sampleText, 4, '...' ); 49 expected = 'Lorem ipsum dolor sit...'; 50 51 equal( result, expected ); 52 }); 53 54 test( 'trimWords() separated by character if defined by settings', function() { 55 var expected, result; 56 57 wp.formatting.settings.trimWordsByCharacter = true; 58 59 result = wp.formatting.trimWords( sampleText, 4 ); 60 expected = 'Lore…'; 61 62 equal( result, expected ); 63 }); 64 65 test( 'trimWords() separates by any whitespace', function() { 66 var modifiedSampleText, expected, result; 67 68 modifiedSampleText = "Lorem\nipsum\tdolor sit\n\ramet"; 69 result = wp.formatting.trimWords( modifiedSampleText, 4 ); 70 expected = 'Lorem ipsum dolor sit…'; 71 72 equal( result, expected ); 73 }); 74 75 test( 'trimWords() does not truncate if fewer words than numWords', function() { 76 var expected, result; 77 78 result = wp.formatting.trimWords( sampleText, Infinity ); 79 80 equal( result, sampleText ); 81 }); 82 });