Skip to content

[Editor] Dispatch an event when some global states are changing (bug 1777695) #15130

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

Merged
merged 1 commit into from
Jul 5, 2022

Conversation

calixteman
Copy link
Contributor

  • this way the context menu in Firefox can take into account what we
    have in the clipboard, if an editor is selected, ...
  • when the user will click on a context menu item, an action will be
    triggered, hence this patch adds what is required to handle it;
  • some tests will be added in the Firefox' patch.

Comment on lines 226 to 237
if (event.button === 2) {
// Avoid to focus this editor because of a right click.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we actually want to focus it for a middle-click, i.e. (usually) the scroll-wheel on a mouse, or do we perhaps want to avoid it receiving focus for event.button !== 0 instead?

Comment on lines 368 to 460
switch (details.name) {
case "undo":
this.undo();
break;
case "redo":
this.redo();
break;
case "cut":
this.cut();
break;
case "copy":
this.copy();
break;
case "paste":
this.paste();
break;
case "delete":
this.delete();
break;
case "selectAll":
this.selectAll();
break;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Given that the action-names seem to perfectly mimic the method-names, could we perhaps avoid a bit of duplication here?

Suggested change
switch (details.name) {
case "undo":
this.undo();
break;
case "redo":
this.redo();
break;
case "cut":
this.cut();
break;
case "copy":
this.copy();
break;
case "paste":
this.paste();
break;
case "delete":
this.delete();
break;
case "selectAll":
this.selectAll();
break;
}
this[details.name]?.();

* @param {Object} details
*/
#dispatchUpdateStates(details) {
const hasChange = Object.entries(details).some(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit:

Suggested change
const hasChange = Object.entries(details).some(
const hasChanged = Object.entries(details).some(

@@ -325,6 +416,29 @@ class AnnotationEditorUIManager {
});
}

/**
* Set the editing state.
* It can be useful to temporarly disable it when the user is editing a
Copy link
Collaborator

Choose a reason for hiding this comment

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

Spelling-nit:

Suggested change
* It can be useful to temporarly disable it when the user is editing a
* It can be useful to temporarily disable it when the user is editing a

Comment on lines 673 to 675
return Array.from(this.#allEditors.values()).every(editor =>
editor.isEmpty()
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: While it probably doesn't matter much, performance wise, it seems that this code will lead to essentially two loops and one (strictly speaking) unnecessary Array allocation.
Would it make sense to do something like the following instead?

Suggested change
return Array.from(this.#allEditors.values()).every(editor =>
editor.isEmpty()
);
for (const editor of this.#allEditors.values()) {
if (!editor.isEmpty()) {
return false;
}
}
return true;

web/app.js Outdated
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
eventBus._on(
"annotationeditorstateschanged",
annotationEditorStatesChanged
Copy link
Collaborator

Choose a reason for hiding this comment

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

For consistency with all of the code above, please make this:

Suggested change
annotationEditorStatesChanged
webViewerAnnotationEditorStatesChanged

web/app.js Outdated
@@ -3074,6 +3080,10 @@ function beforeUnload(evt) {
return false;
}

function annotationEditorStatesChanged(data) {
PDFViewerApplication.externalServices.setEditorStates(data);
Copy link
Collaborator

Choose a reason for hiding this comment

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

For documentation purposes, please add the following dummy-method to the DefaultExternalServices-class at the top of the file:

  static updateEditorStates(data) {
    throw new Error("Not implemented: updateEditorStates");
  }

constructor(eventBus) {
this.#eventBus = eventBus;
this.#eventBus.on("editingaction", this.#boundOnEditingAction);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use the ._on-method for every "internal" use-case, since that helps ensure that the PDF.js code always receive events before any externally registered event listeners.

Suggested change
this.#eventBus.on("editingaction", this.#boundOnEditingAction);
eventBus._on("editingaction", this.#boundOnEditingAction);

Comment on lines 404 to 408
this.#eventBus.dispatch("annotationeditorstateschanged", {
source: this,
details,
});
Object.assign(this.#previousStates, details);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems, as far as I can tell, that the "shape" of the details-Object will differ quite a lot between call-sites. Is that an issue, and if so do we perhaps want to ensure that we always send consistent data here?

You could possibly avoid that by doing something like this:

Suggested change
this.#eventBus.dispatch("annotationeditorstateschanged", {
source: this,
details,
});
Object.assign(this.#previousStates, details);
this.#eventBus.dispatch("annotationeditorstateschanged", {
source: this,
details: Object.assign(this.#previousStates, details),
});

Comment on lines 401 to 402
static setEditorStates(data) {
FirefoxCom.request("setEditorStates", data);
Copy link
Collaborator

Choose a reason for hiding this comment

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

For consistency with existing methods, in the FirefoxExternalServices-class, maybe use:

Suggested change
static setEditorStates(data) {
FirefoxCom.request("setEditorStates", data);
static updateEditorStates(data) {
FirefoxCom.request("updateEditorStates", data);

*/
mousedown(event) {
if (event.button !== 0) {
// Avoid to focus this editor because of a right click.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe tweak the comment slightly, now that the condition was updated above?

Suggested change
// Avoid to focus this editor because of a right click.
// Avoid to focus this editor because of a non-left click.

constructor(eventBus) {
this.#eventBus = eventBus;
this.#eventBus._on("editingaction", this.#boundOnEditingAction);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It doesn't seem that anything is ever removing this listener, as far as I can tell?
That means that when multiple documents have been opened in the GENERIC viewer, there'll be a number of old (and stale) listeners still around. While "editingaction"-support will currently only be implemented in Firefox, this is nonetheless something that we should fix here to prevent any future issues.

Basically, I think that the simplest solution would be to add e.g. a destroy-method to this class and having it run:

this.#eventBus._off("editingaction", this.#boundOnEditingAction);

Then, in the viewer, remove line

this.#annotationEditorUIManager = null;

and instead add

if (this.#annotationEditorUIManager) {
  this.#annotationEditorUIManager.destroy();
  this.#annotationEditorUIManager = null;
}

just after line

@calixteman calixteman requested a review from Snuffleupagus July 5, 2022 20:12
- this way the context menu in Firefox can take into account what we
  have in the clipboard, if an editor is selected, ...
- when the user will click on a context menu item, an action will be
  triggered, hence this patch adds what is required to handle it;
- some tests will be added in the Firefox' patch.
@Snuffleupagus
Copy link
Collaborator

/botio integrationtest

@pdfjsbot
Copy link

pdfjsbot commented Jul 5, 2022

From: Bot.io (Linux m4)


Received

Command cmd_integrationtest from @Snuffleupagus received. Current queue size: 1

Live output at: http://54.241.84.105:8877/5e859836d7f1c5a/output.txt

@pdfjsbot
Copy link

pdfjsbot commented Jul 5, 2022

From: Bot.io (Windows)


Received

Command cmd_integrationtest from @Snuffleupagus received. Current queue size: 1

Live output at: http://54.193.163.58:8877/6684513ded1c454/output.txt

@pdfjsbot
Copy link

pdfjsbot commented Jul 5, 2022

From: Bot.io (Linux m4)


Success

Full output at http://54.241.84.105:8877/5e859836d7f1c5a/output.txt

Total script time: 4.74 mins

  • Integration Tests: Passed

@pdfjsbot
Copy link

pdfjsbot commented Jul 5, 2022

From: Bot.io (Windows)


Failed

Full output at http://54.193.163.58:8877/6684513ded1c454/output.txt

Total script time: 8.30 mins

  • Integration Tests: FAILED

@Snuffleupagus Snuffleupagus merged commit bde4663 into mozilla:master Jul 5, 2022
@marco-c marco-c linked an issue Jul 13, 2022 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support copying and pasting by right click context menu
3 participants