11

To reproduce:

  • Open up the VTC as duplicate interface
  • Click on an original question (this can also be done after the edit notice appears in the next step)
  • Wait for the question to be edited, so that "An edit has been made to this post" appears. (You cannot make the edit yourself in a different tab, because edits that your own account makes do not result in the notice appearing). The page should look like this:

enter image description here

  • Click anywhere inside the question (possibly on the duplicate interface)

Everything inside the question will disappear:

enter image description here


Technical details:

The problem is that the question's .postcell receives an opacity of 0 which never goes away:

<div class="postcell post-layout--right" style="opacity: 0;">

The bug can be understood by looking at the following lines in realtime-se.js's replaceIndividualPostContents:

// When a post with an edit notice is clicked,
// the following runs to replace the post with the new contents:
// $oldPost is a .question or .answer

var $oldBodyCell = $oldPost.find('.postcell, .answercell'),
    $newBodyCell = $newPost.find('.postcell, .answercell').css({ opacity: 0 });
// ...
$.when(
  fadeOut($oldBodyCell)
).then(function() {
  // ...
  $oldBodyCell.replaceWith($newBodyCell);
  // ...
  return $.when(
      fadeIn($newBodyCell)
  );

The .find('.postcell, .answercell') is meant to navigate from a parent .question or a .answer to a container on the right containing the post content, so that that container can be replaced. But what makes the duplicate interface in particular produce this bug is that, when viewing a question preview, there are many .postcell, .answercell elements inside the $oldPost - not only one for the question you're currently closing, but also one for the original question and one for every one of the original question's answers.

So $oldBodyCell contains multiple elements. [0] is the question cell we want, [1] is the question cell in the original preview, [2] is an answer cell in the original preview, etc. This is a problem because the $oldBodyCell.replaceWith($newBodyCell); will clone the $newBodyCell when there's more than one element to be replaced. After replacing, the actual DOM element that the $newBodyCell contains will be the last element replaced:

const $oldBodyCell = $('.cell');
const $newBodyCell = $('<div>replaced cell</div>');

$oldBodyCell.replaceWith($newBodyCell);
$newBodyCell.css({ backgroundColor: 'yellow' });
console.log($newBodyCell.length);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cell">cell 1</div>
<div class="cell">cell 2</div>
<div class="cell">cell 3</div>
<div class="cell">cell 4</div>

But the element which $newBodyCell contains will be the last answer in the original preview, so:

fadeIn($newBodyCell)

fades in the wrong element; the question cell for the question the user is currently on has been replaced with a clone of $newBodyCell containing the updated post contents, but the $newBodyCell does not contain that cloned element. So, the clone doesn't get faded in, and the main question cell remains at opacity: 0 forever.


To fix it, the $oldBodyCell should only select the main question cell, and not any of its descendants. Maybe change

var $oldBodyCell = $oldPost.find('.postcell, .answercell')

to

var $oldBodyCell = $oldPost.find('.postcell, .answercell').first()

That fixes the problem for me, at least.

You must log in to answer this question.

Browse other questions tagged .