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
Implement support for Popup annotations #6792
Conversation
I suppose I can try, but I won't have time until after Christmas. However, it seems that this PR currently breaks most of the annotations in http://tug.ctan.org/tex-archive/macros/latex/contrib/pdfcomment/doc/pdfcomment.pdf, since nothing happens when they are hovered/clicked. |
It seems that it is also possible for Text annotations to not have an associated Popup annotation (which is the case in that PDF file), in which case the Text annotation needs to provide the popup and not the Popup annotation. This case can be discovered by checking if the Text annotation has a Issues to address:
|
3459427
to
97fc47d
Compare
warn('Popup annotation has an invalid parent annotation.'); | ||
return; | ||
} | ||
this.data.parentId = dict.map.Parent.num; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please note that you should not access members of a Dict
by directly using map
(it should be considered private), use e.g. Dict_get
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main problem with using Dict.get('Parent')
is that the ID (num
) is not in the returned object anymore (or at least I could not find it). Do you know of a better way of obtaining this (internal) annotation ID other than the method I used? I will happily use that then.
Edit: There is Dict.get('Parent').objId
, but its value is 29R
(string) instead of the correct 29
(integer). Something like parseInt(Dict.get('Parent').objId, 10);
should yield the same result as my method, but I'm not sure if it's better because objId
still seems like something private and it's more code. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably want Dict_getRaw
, since it looks like you want to access a Reference
. And I don't think that you should use objId
when you have access to a reference, since it's also somewhat private, and should probably not be relied on.
But the real question here is: if you have a Ref
, why do you directly access just one of its properties? In practice, the gen
is usually zero, but you cannot assume that that always holds, so I really think that you ought to use Ref_toString
instead!
This leads me to look at the current code in annotation.js
, and I thus think that https://github.com/mozilla/pdf.js/blob/master/src/core/annotation.js#L163 is actually wrong! That line really ought to read this.data.id = params.ref.toString();
, which means that changing the current line to this.data.parentId = dict.getRaw('Parent').toString();
should then work just fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the new commit. Really nice find!
97fc47d
to
5cbcf15
Compare
} | ||
|
||
var parentItem = dict.get('Parent'); | ||
if (!parentItem) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to have two different cases for when the Parent
entry isn't present, or is invalid?
Would it not suffice to just replace both of them with e.g.
...
var dict = parameters.dict;
var parentDict = dict.get('Parent');
if (!parentDict) {
warn(...);
return;
}
this.data.parentId = ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the new commit. Much easier indeed.
5cbcf15
to
00aa8e1
Compare
// Attach the event listeners and position the container. A parent | ||
// element is only available when its type is supported. | ||
var selector = '[data-annotation-id="' + this.data.parentId + '"]'; | ||
var parentItem = this.layer.querySelectorAll(selector)[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is querySelectorAll(...)[0]
really necessary, couldn't you simply use querySelector
instead, since those should be equivalent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the new commit.
7a681ed
to
9994138
Compare
} | ||
|
||
if (dict.has('C')) { | ||
data.hasBgColor = true; | ||
this.data.popup = !!dict.get('Popup'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this just contains a boolean, how about naming it data.hasPopup
instead?
Also, wouldn't dict.has('Popup)
work here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a linked test-case for this particular code-path (or if it's not too much trouble, create a reduced one)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dict.has('Popup')
is indeed working just fine. Not sure why I did not use that in the first place...
I'll try to create a reduced test case, but otherwise I will certainly add a linked test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably still need this.data.hasPopup
though, since you've got code in annotation_layer.js
that seem to depend on that flag being present :)
But I really like the general direction this PR is going!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. Fixed in the new commit. I have managed to create a reduced test case, which is now also in the commit.
9994138
to
51886ca
Compare
title: this.data.title, | ||
contents: this.data.contents | ||
}; | ||
var popupElement = new PopupElement(parameters); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I'm concerned, these kind of temporary variables doesn't really add much in terms of readability. You could just do:
var popupElement = new PopupElement({
parentContainer: this.container,
parentTrigger: image,
color: this.data.color,
title: this.data.title,
contents: this.data.contents
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the new commit, also for the other place where I did this for this commit. Looks better that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just trying to find small things to make the total diff smaller ;)
8897031
to
c3ee03e
Compare
this.data.color = null; | ||
} | ||
|
||
this.data.popup = dict.has('Popup'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry, but I'd still like this to be named this.data.hasPopup
, given that it's a boolean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the new commit. I had missed this before, so thanks for reminding me!
7a9282d
to
a231e26
Compare
Most code for Popup annotations is already present for Text annotations. This patch extracts the popup creation logic from the Text annotation code so it can be reused for Popup annotations. Not only does this add support for Popup annotations, the Text annotation code is also considerably easier. If a `Popup` entry is available for a Text annotation, it will not be more than an image. The popup will be handled by the Popup annotation. However, it is also possible for Text annotations to not have a separate Popup annotation, in which case the Text annotation handles the popup creation itself.
a231e26
to
7d43971
Compare
I forgot to mention how you can test the reference image rendering locally, though you might already know this. First make a backup of your current reference images, then simply remove the Thank you for the helpful comments so far and merry Christmas! :-) |
/botio-linux preview |
From: Bot.io (Linux)ReceivedCommand cmd_preview from @timvandermeij received. Current queue size: 0 Live output at: http://107.21.233.14:8877/8d36eb7e61e5580/output.txt |
From: Bot.io (Linux)SuccessFull output at http://107.21.233.14:8877/8d36eb7e61e5580/output.txt Total script time: 0.81 mins Published |
/botio test |
From: Bot.io (Linux)ReceivedCommand cmd_test from @timvandermeij received. Current queue size: 0 Live output at: http://107.21.233.14:8877/3edc7c48302c2c8/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_test from @timvandermeij received. Current queue size: 0 Live output at: http://107.22.172.223:8877/0bad30f904f75a8/output.txt |
From: Bot.io (Windows)SuccessFull output at http://107.22.172.223:8877/0bad30f904f75a8/output.txt Total script time: 20.52 mins
|
From: Bot.io (Linux)SuccessFull output at http://107.21.233.14:8877/3edc7c48302c2c8/output.txt Total script time: 20.61 mins
|
Thank you for the patch! /botio makeref |
From: Bot.io (Windows)ReceivedCommand cmd_makeref from @Snuffleupagus received. Current queue size: 0 Live output at: http://107.22.172.223:8877/fc4dfd01b429a35/output.txt |
From: Bot.io (Linux)ReceivedCommand cmd_makeref from @Snuffleupagus received. Current queue size: 0 Live output at: http://107.21.233.14:8877/1f892d746193e3e/output.txt |
Implement support for Popup annotations
From: Bot.io (Windows)SuccessFull output at http://107.22.172.223:8877/fc4dfd01b429a35/output.txt Total script time: 20.18 mins
|
From: Bot.io (Linux)SuccessFull output at http://107.21.233.14:8877/1f892d746193e3e/output.txt Total script time: 20.51 mins
|
Most code for Popup annotations is already present for Text annotations. This patch extracts the popup creation logic from the Text annotation code so it can be reused for Popup annotations.
Not only does this add support for Popup annotations, the Text annotation code is also considerably easier. If a
Popup
entry is available for a Text annotation, it will not be more than an image. The popup will be handled by the Popup annotation. However, it is also possible for Text annotations to not have a separate Popup annotation, in which case the Text annotation handles the popup creation itself.