Skip to content

Replacing unload events handlers to use pagehide#5056

Closed
spenserhale wants to merge 18 commits intoWordPress:trunkfrom
spenserhale:55491-replace-unload-events
Closed

Replacing unload events handlers to use pagehide#5056
spenserhale wants to merge 18 commits intoWordPress:trunkfrom
spenserhale:55491-replace-unload-events

Conversation

@spenserhale
Copy link
Copy Markdown

@spenserhale spenserhale commented Aug 24, 2023

Chrome has deprecated the 'unload' event (https://developer.chrome.com/blog/deprecating-unload/)

Replacing event handlers to use the 'pagehide' instead based on the suggestion from Chrome's documentation.

Trac ticket: https://core.trac.wordpress.org/ticket/55491

Commit Message

Administration: Remove deprecated unload event handlers and use pagehide (and pageshow) when appropriate.

Use pagehide event instead of unload in the following cases:

  • For classic editor to release the post lock.
  • In Text widget to rebuild editor after dragging widget to new location in classic widgets interface.
  • To clear out the window.name when navigating away from a post preview.
  • To suspend heartbeat, while also using pageshow event to resume as if it had been a focused tab in case page restored from bfcache.

Also:

  • Remove obsolete mobile cleanup code in js/_enqueues/lib/gallery.js (introduced in [9894]). Do same for src/js/_enqueues/wp/media/models.js (introduced in [22872]). See #22552.
  • Remove obsolete Firefox-specific workaround in js/_enqueues/wp/mce-view.js from [39282]. See #38511.

Fixes #55491.
Props spenserhale, westonruter, adamsilverstein, azaozz, shawfactor, peterwilsoncc, swissspidy.

});

jQuery(window).on( 'unload', function () { window.tinymce = window.tinyMCE = window.wpgallery = null; } ); // Cleanup.
jQuery(window).on( 'pagehide', function () { window.tinymce = window.tinyMCE = window.wpgallery = null; } ); // Cleanup.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should look into removing this instance entirely. Otherwise, if a tab is restored then it would be broken. And it wouldn't be possible to restore these variables with pageshow since they are gone.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was introduced in r9894

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a hard time finding where this file is even used in core.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is enqueued in two functions: wp_media_upload_handler() and media_upload_gallery(). This latter function refers to the screen as the "legacy media uploader form".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I found out how to get there:

  1. Activate the Classic Editor plugin
  2. Create a new post
  3. Upload new photos in the post and create a gallery from them
  4. Save the post
  5. With the post ID in hand, go to /wp-admin/media-upload.php?type=gallery&tab=type&post_id={POST_ID}

It looks like this:

image

I don't see any other way to get to that screen.

Given this, either we:

  1. Replace unload with pagehide and add a pageshow that does the reload behavior below, or
  2. We just remove the line of cleanup code altogether. It seems like it was put in place for an iOS Safari bug from over a decade ago, similar to https://github.com/WordPress/wordpress-develop/pull/5056/files#r1332289674, so it's probably obsolete.

@azaozz Since you introduced this line of code and are probably the most familiar with this codebase, what do you think we should do (also considering this is an inaccessible legacy screen)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also how @spenserhale removed similar code in src/js/_enqueues/wp/mce-view.js: https://github.com/WordPress/wordpress-develop/pull/5056/files#r1332287807

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just going to go ahead and remove this for consistency with src/js/_enqueues/wp/mce-view.js.


// When a widget is moved in the DOM the dynamically-created TinyMCE iframe will be destroyed and has to be re-built.
$( editor.getWin() ).on( 'unload', function() {
$( editor.getWin() ).on( 'pagehide', function() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of the unload event may not be a problem here for bfcache since it is added to the iframe and not the window as a whole. Still, if pagehide works the same we could still use it.

Copy link
Copy Markdown
Member

@westonruter westonruter Sep 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using unload is indeed a problem here. It disabled bfcache:

image

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the handler altogether results in a breakage:

Screen.recording.2023-09-20.17.09.09.webm

Nevertheless, using pagehide instead of unload does work:

Screen.recording.2023-09-20.17.09.40.webm

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevertheless, bfcache remains disabled since TinyMCE is using unload. However, this doesn't seem like something we should remove per https://core.trac.wordpress.org/ticket/55491#comment:27

@westonruter

This comment was marked as resolved.

@westonruter

This comment was marked as resolved.

}, 3000 );
}

function reload() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduced in r39282 to fix Core-38511 in 2016. It is to work-around a Firefox-specific bug. We should validate whether it is still an issue in Firefox. If not, we can remove this code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried reproducing the issue in Firefox according to the description of Core-38511 and I was unable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reported this to the 7-year old ticket: https://core.trac.wordpress.org/ticket/38511#comment:27

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@azaozz also please weigh in on whether we can remove this code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the age of this bug fix, it should be fine to remove. If we discover that this still creates an issue for Firefox users, we can always restore the fix.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, super old browser specific fix. LGTM to remove too.

Comment on lines -241 to -244
// Clean up. Prevents mobile browsers caching.
$(window).on('unload', function(){
window.wp = null;
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rationale for removal: https://core.trac.wordpress.org/ticket/55491#comment:17

However, if this depends on the server sending Cache-Control: no-store, then I'd like to further verify this.

@spenserhale What happens if no-store is not sent? Is there an issue then? I'd like to find a way to not have to send no-store in the admin so that we can benefit from bfcache, but if this depends on no-store then that would block enabling bfcache.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Origin is d2d01ad to fix Core-22552: "Empty wp on unload to work around caching in iOS Safari."

This commit is 11 years old. Most likely this is no longer an issue in Safari. If so, we can most likely delete this entire event handler.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 - fine to delete this super old bug fix/browser specific workaround. It is unlikely that the bug still exists, if it does we can always reintroduce a fix.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, same as above. Super old browser specific fix that seems okay to remove


if ( window.addEventListener ) {
window.addEventListener( 'unload', function() { window.name = ''; }, false );
window.addEventListener( 'pagehide', function() { window.name = ''; } );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was confused why the PageTransitionEvent being passed to this event handler has its persisted property set to false, both for the pagehide and the pageshow events. In looking at DevTools, I see:

image

So it is explained that the fact that window.open() was used to open the preview is another way that bfcache is disabled.

I think this is all good. I'm seeing that the window.name is being set to wp-preview-... when the tab is opened when clicking preview. When I navigate the preview window to another page, the window.name is set to an empty string. When I then re-preview a post I am opened in a new tab rather than the previous preview tab (which is now no longer a preview). If in that preview tab I go back to the previewed post, and then hit preview again, then it is that tab that gets updated with the latest preview content.

So I think we're good here.

Comment on lines +236 to +251
$(window).on(
'pageshow.wp-heartbeat',
/**
* Handles pageshow event.
*
* @param {jQuery.Event} event
* @param {PageTransitionEvent} event.originalEvent
*/
function ( event ) {
if ( event.originalEvent.persisted ) {

// Continue connecting.
resume();
}
}
);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not seeing this code firing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I am seeing it fire. Apparently I have a browser extension which is disabling bfcache, but if I try in an incognito window then event.originalEvent.persisted is true.

return __( 'The changes you made will be lost if you navigate away from this page.' );
}
}).on( 'unload.edit-post', function( event ) {
}).on( 'pagehide.edit-post', function( event ) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a single reference to the jQuery-namespaced unload.edit-post event name in WPdirectory, so I don't see any back-compat concerns here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that post lock is restored upon pageshow via heartbeat. See #5056 (comment)

}

$(window).on( 'unload.wp-heartbeat', function() {
$(window).on( 'pagehide.wp-heartbeat', function() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with pagehide.edit-post, I don't see a single reference to the jQuery-namespaced unload.wp-heartbeat event name in WPdirectory, so I don't see any back-compat concerns here.

*/
function ( event ) {
if ( event.originalEvent.persisted ) {
window.location.reload();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice this code will never fire because this code is loaded on the Classic Editor and TinyMCE disables bfcache due to an unload event handler.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevertheless, if that offending TinyMCE code is commented-out and Cache-Control: no-store is disabled (e.g. via plugin), then the experience is not great when you leave with a dirty editor state: you get the "Are you sure?" dialog when you leave and then when you go back, to get it again when it attempts to reload:

Screen.recording.2023-10-02.16.03.53.webm

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the end, this code is not needed because upon pageshow, heartbeat will resume and it will start sending its wp-refresh-post-lock requests.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this pageshow event is removed in 329ebfb, and then heartbeat then connects immediately upon pageshow if restoring from bfcache in 00772ee.

Much better experience:

Screen.recording.2023-10-02.16.19.16.webm

@westonruter westonruter requested a review from azaozz October 3, 2023 00:22
Comment on lines +245 to +251
if ( event.originalEvent.persisted ) {
/*
* When page navigation is stored via bfcache (Back/Forward Cache), consider this the same as
* if the user had just switched to the tab since the behavior is similar.
*/
focused();
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See outdated conversation: #5056 (comment)

Comment on lines -91 to -92
jQuery(window).on( 'unload', function () { window.tinymce = window.tinyMCE = window.wpgallery = null; } ); // Cleanup.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@azaozz
Copy link
Copy Markdown
Contributor

azaozz commented Oct 9, 2023

The changes from unload to pagehide seem pretty straightforward. Also the removal of super old browser specific bugfixes. On the other hand this touches an area where bugs may be harder to figure out, but thinking that if something goes wrong it would be detected and fixed during RC.

@westonruter
Copy link
Copy Markdown
Member

Committed in r56809.

@westonruter westonruter closed this Oct 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants