Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/js/media/models/attachments.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,6 @@ var Attachments = Backbone.Collection.extend(/** @lends wp.media.model.Attachmen
this.observers.push( attachments );

attachments.on( 'add change remove', this._validateHandler, this );
attachments.on( 'add', this._addToTotalAttachments, this );
attachments.on( 'remove', this._removeFromTotalAttachments, this );
attachments.on( 'reset', this._validateAllHandler, this );
this.validateAll( attachments );
return this;
Expand Down Expand Up @@ -310,6 +308,12 @@ var Attachments = Backbone.Collection.extend(/** @lends wp.media.model.Attachmen
this.reset( [], { silent: true } );
this.observe( attachments );

// Bind total attachment count tracking only to the mirrored query
// collection, not to additional observed collections (e.g. selection).
// See Trac #65053.
attachments.on( 'add', this._addToTotalAttachments, this );
attachments.on( 'remove', this._removeFromTotalAttachments, this );

// Used for the search results.
this.trigger( 'attachments:received', this );
return this;
Expand Down
1 change: 1 addition & 0 deletions tests/qunit/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
<script src="wp-admin/js/widgets/test-media-image-widget.js"></script>
<script src="wp-admin/js/widgets/test-media-gallery-widget.js"></script>
<script src="wp-admin/js/widgets/test-media-video-widget.js"></script>
<script src="wp-includes/js/media/test-models.js"></script>

<!-- Customizer templates for sections -->
<script type="text/html" id="tmpl-customize-section-default">
Expand Down
107 changes: 107 additions & 0 deletions tests/qunit/wp-includes/js/media/test-models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* globals wp */
/* jshint qunit: true */
/* eslint-env qunit */

( function () {
'use strict';

QUnit.module( 'wp.media.model.Attachments' );

/*
* Trac #65053: opening the media modal via "Set featured image" or
* an Image block reported an incorrect "Showing X of Y" total because
* Attachments#observe() bound the totalAttachments trackers to every
* observed collection, including the Selection. Selection mutations
* therefore mutated the mirrored Query's totalAttachments.
*
* The library mirrors a Query (which owns totalAttachments) AND
* additionally observes a Selection (so a pre-existing featured image
* stays visible in the grid). Only the Query should drive the count.
*/
QUnit.test(
'observing a selection does not corrupt totalAttachments (Trac #65053)',
function ( assert ) {
var Attachments = wp.media.model.Attachments,
Selection = wp.media.model.Selection,
Attachment = wp.media.model.Attachment,
query,
library,
selection;

// Stand-in for a Query collection: the source of truth for totalAttachments.
query = new Attachments();
query.totalAttachments = 8;

// The library is what AttachmentsBrowser renders. It mirrors the query.
library = new Attachments();
library.mirror( query );

assert.strictEqual(
library.getTotalAttachments(),
8,
'precondition: getTotalAttachments() reflects the mirrored query total'
);

// FeaturedImage / ReplaceImage controllers additionally observe the selection.
selection = new Selection( [], { multiple: false } );
library.observe( selection );

// Adding to the selection must not mutate the mirrored query's total.
selection.add( new Attachment( { id: 42 } ) );
assert.strictEqual(
library.getTotalAttachments(),
8,
'add to observed selection leaves totalAttachments untouched'
);

// Single-select swap: Selection#add internally remove()s prior models
// before adding the new one. Both events must be ignored by the count.
selection.add( new Attachment( { id: 99 } ) );
assert.strictEqual(
library.getTotalAttachments(),
8,
'single-select swap on observed selection leaves totalAttachments untouched'
);

// Removing from the selection must also leave the total alone.
selection.remove( selection.models );
assert.strictEqual(
library.getTotalAttachments(),
8,
'remove from observed selection leaves totalAttachments untouched'
);
}
);

QUnit.test(
'mirrored query add/remove still drives totalAttachments',
function ( assert ) {
var Attachments = wp.media.model.Attachments,
Attachment = wp.media.model.Attachment,
query,
library,
attachment;

query = new Attachments();
query.totalAttachments = 5;

library = new Attachments();
library.mirror( query );

attachment = new Attachment( { id: 1 } );
query.add( attachment );
assert.strictEqual(
library.getTotalAttachments(),
6,
'adding to the mirrored query increments totalAttachments'
);

query.remove( attachment );
assert.strictEqual(
library.getTotalAttachments(),
5,
'removing from the mirrored query decrements totalAttachments'
);
}
);
} )();
Loading