Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

confirm if leaving a modified form without saving #12241

Merged
merged 1 commit into from
Aug 21, 2020
Merged

confirm if leaving a modified form without saving #12241

merged 1 commit into from
Aug 21, 2020

Conversation

escapewindow
Copy link
Contributor

There may be a nicer way to track form modification; not sure.

@timvandermeij
Copy link
Contributor

Relates to #12202.

src/display/annotation_layer.js Outdated Show resolved Hide resolved
src/display/annotation_storage.js Outdated Show resolved Hide resolved
web/app.js Outdated Show resolved Hide resolved
@brendandahl
Copy link
Contributor

/botio-linux preview

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_preview from @brendandahl received. Current queue size: 0

Live output at: http://54.67.70.0:8877/a56a6e04f9e6b15/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/a56a6e04f9e6b15/output.txt

Total script time: 3.34 mins

Published

@Snuffleupagus
Copy link
Collaborator

Snuffleupagus commented Aug 19, 2020

According to https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event, beforeunload has really undesirable effects in general:

[...] Attaching an event handler/listener to window or document's beforeunload event prevents browsers from using in-memory page navigation caches, like Firefox's Back-Forward cache or WebKit's Page Cache.

Furthermore, years ago, we used to have a beforeunload event listener in another part of the code-base, but removed it because it caused problems. (Unfortunately I don't remember all the details right now, since it was well over five years ago now.)

All-in-all, it seems really unfortunate as far as I'm concerned to use a beforeunload event unconditionally like this. Can't we at least limit this to documents with forms, to lessen the impact of these changes (unless a solution without beforeunload can be had)?

Copy link
Collaborator

@Snuffleupagus Snuffleupagus left a comment

Choose a reason for hiding this comment

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

In addition to #12241 (comment), I've also got a couple of questions/suggestions based on a cursory look at the code.

src/display/annotation_storage.js Outdated Show resolved Hide resolved
src/display/annotation_layer.js Outdated Show resolved Hide resolved
src/display/api.js Outdated Show resolved Hide resolved
@escapewindow
Copy link
Contributor Author

According to https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event, beforeunload has really undesirable effects in general:

[...] Attaching an event handler/listener to window or document's beforeunload event prevents browsers from using in-memory page navigation caches, like Firefox's Back-Forward cache or WebKit's Page Cache.

Furthermore, years ago, we used to have a beforeunload event listener in another part of the code-base, but removed it because it caused problems. (Unfortunately I don't remember all the details right now, since it was well over five years ago now.)

All-in-all, it seems really unfortunate as far as I'm concerned to use a beforeunload event unconditionally like this. Can't we at least limit this to documents with forms, to lessen the impact of these changes (unless a solution without beforeunload can be had)?

I took a look at this. It looks like this.bindWindowEvents() happens before _initializeMetadata, and possibly even load, so I don't have a this.documentInfo.IsAcroFormPresent or a this.pdfDocument to refer to. Another solution could be to bind beforeunload elsewhere, outside of bindWindowEvents. Do you have any recommendations here? (Or am I mistaken about any of my assumptions?)

@escapewindow
Copy link
Contributor Author

bdahl
aki: what about binding/unbinding on modified?
aki
that makes sense. is there a destroy() or similar?
i'll try that and test
bdahl
may need to add an event that is dispatched from annotation storage on modification and reset?

@escapewindow
Copy link
Contributor Author

bdahl
aki: what about binding/unbinding on modified?
aki
that makes sense. is there a destroy() or similar?
i'll try that and test
bdahl
may need to add an event that is dispatched from annotation storage on modification and reset?

This patch doesn't appear to work. I git stashed that, then tried looking for how to send an event from annotation storage. dispatchEvent seems to only be in web/, and message handlers appear to only go between core and display?

@escapewindow
Copy link
Contributor Author

bdahl
aki: could add two properties to class AnnotationStorage e.g. onReset and onModified that the viewer could set as callbacks. then when those are called in the viewer you'd add/remove the unload listener

This worked! 488f674

@brendandahl
Copy link
Contributor

/botio-linux preview

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_preview from @brendandahl received. Current queue size: 0

Live output at: http://54.67.70.0:8877/a63abdef2cb89a4/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/a63abdef2cb89a4/output.txt

Total script time: 3.37 mins

Published

Copy link
Contributor

@timvandermeij timvandermeij left a comment

Choose a reason for hiding this comment

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

Looks good to me with these comments addressed.

src/display/annotation_storage.js Outdated Show resolved Hide resolved
src/display/annotation_storage.js Outdated Show resolved Hide resolved
@@ -49,6 +53,9 @@ class AnnotationStorage {
* @param {Object} value
*/
setValue(key, value) {
if (this._storage.get(key) !== value) {
Copy link
Contributor

@timvandermeij timvandermeij Aug 20, 2020

Choose a reason for hiding this comment

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

The only situation where this won't work is

storage.setValue(id, option.displayValue);
because that class is the only widget that doesn't use getOrCreateValue first. You can verify this by opening https://github.com/mozilla/pdf.js/blob/master/test/pdfs/annotation-choice-widget.pdf and without changing anything navigating away from the page, and you'll get the warning.

However, I'll most likely need to change that anyway for #12233, so this should be fine, but I'd like to fix that one first before landing this one just to make sure it's all fine.

Copy link
Contributor

Choose a reason for hiding this comment

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

We're getting down to the wire on Firefox's soft freeze coming up. Since the failing behavior isn't too bad, I'm going to merge this in so we have as small as possible updates in mozilla central.

src/display/annotation_storage.js Outdated Show resolved Hide resolved
web/base_viewer.js Outdated Show resolved Hide resolved
@brendandahl
Copy link
Contributor

/botio-linux unittest

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_unittest from @brendandahl received. Current queue size: 0

Live output at: http://54.67.70.0:8877/7d9eb4ffbc0de69/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/7d9eb4ffbc0de69/output.txt

Total script time: 3.77 mins

  • Unit Tests: Passed

@brendandahl brendandahl merged commit 10f61b8 into mozilla:master Aug 21, 2020
@Snuffleupagus
Copy link
Collaborator

Snuffleupagus commented Aug 21, 2020

Sorry, but I'm finding the decision to add a global event listener in web/base_viewer.js slightly strange and inconsistent (since there's no others anywhere in the file). Note that when the viewer was originally split into components, we purposely tried to move e.g. any direct DOM accesses out of them.

Hence it does seem, at least to me, that placing that code in PDFViewerApplication.load (in web/app.js) instead would have been slightly more expected overall.


Also, I understand that the following is more difficult to implement, but nonetheless: Note that this will not warn when switching documents, which means that if you call e.g. PDFViewerApplication.open with a new document (or directly call BaseViewer.setDocument when using the viewer components standalone) there won't be any warning about losing form data.

@escapewindow
Copy link
Contributor Author

Sorry, but I'm finding the decision to add a global event listener in web/base_viewer.js slightly strange and inconsistent (since there's no others anywhere in the file). Note that when the viewer was originally split into components, we purposely tried to move e.g. any direct DOM accesses out of them.

Hence it does seem, at least to me, that placing that code in PDFViewerApplication.load (in web/app.js) instead would have been slightly more expected overall.

I thought we might not have an annotationStorage yet, but it looks like that works! #12256

Also, I understand that the following is more difficult to implement, but nonetheless: Note that this will not warn when switching documents, which means that if you call e.g. PDFViewerApplication.open with a new document (or directly call BaseViewer.setDocument when using the viewer components standalone) there won't be any warning about losing form data.

We may want to file this as an issue to track and prioritize.

@timvandermeij
Copy link
Contributor

Thank you for your work! The first point is addressed in a follow-up PR and the second point is filed in issue #12257.

timvandermeij added a commit that referenced this pull request Aug 21, 2020
#12241 followup - move event listener to PDFViewerApplication.load
timvandermeij added a commit to timvandermeij/pdf.js that referenced this pull request Aug 22, 2020
…ion storage

This commit makes the following improvements:

- The code is similar to the other interactive form widgets now, with a
  clear note for the only difference.
- Calling `getOrCreateValue` unconditionally ensures that choice widgets
  always have a value in the annotation storage. Previously we only
  inserted a value in the annotation storage when an option matched or
  when a selection was changed. However, this causes breakage when
  saving/printing because comboboxes, which we don't fully support yet
  but are rendered, might not have a value in storage at all. Their
  field value might not match any option since it allows the user to
  enter a custom value.
- Calling `getOrCreateValue` unconditionally ensures that forms with
  choice widgets no longer always trigger a warning when the user
  navigates away from the page. This fixes
  mozilla#12241 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants