Commit Graph

34 Commits

Author SHA1 Message Date
Jonas Jenwald
5729c0b32f Add support for finding/highlighting the outlineItem, corresponding to the currently visible page, in the sidebar (issue 7557, bug 1253820, bug 1499050)
This implementation is inspired by the behaviour in (recent versions of) Adobe Reader, since it leads to reasonably simple and straightforward code as far as I'm concerned.
*Specifically:* We'll only consider *one* destination per page when finding/highlighting the current outline item, which is similar to e.g. Adobe Reader, and we choose the *first* outline item at the *lowest* level of the outline tree.

Given that this functionality requires not only parsing of the `outline`, but looking up *all* of the destinations in the document, this feature can when initialized have a non-trivial performance overhead for larger PDF documents.
In an attempt to reduce the performance impact, the following steps are taken here:

 - The "find current outline item"-functionality will only be enabled once *one* page has rendered and *all* the pages have been loaded[1], to prevent it interfering with data regular fetching/parsing early on during document loading and viewer initialization.

 - With the exception of a couple of small and simple `eventBus`-listeners, in `PDFOutlineViewer`, this new functionality is initialized *lazily* the first time that the user clicks on the `currentOutlineItem`-button.

 - The entire "find current outline item"-functionality is disabled when `disableAutoFetch = true` is set, since it can easily lead to the setting becoming essentially pointless[2] by triggering *a lot* of data fetching from a relatively minor viewer-feature.

 - Fetch the destinations *individually*, since that's generally more efficient than using `PDFDocumentProxy.getDestinations` to fetch them all at once. Despite making the overall parsing code *more* asynchronous, and leading to a lot more main/worker-thread message passing, in practice this seems faster for larger documents.

Finally, we'll now always highlight an outline item that the user manually clicked on, since only highlighting when the new "find current outline item"-functionality is used seemed inconsistent.

---
[1] Keep in mind that the `outline` itself already isn't fetched/parsed until at least *one* page has been rendered in the viewer.

[2] And also quite slow, since it can take a fair amount of time to fetch all of the necessary `destinations` data when `disableAutoFetch = true` is set.
2021-01-09 16:09:44 +01:00
Jonas Jenwald
c185061757 Include the state in the "presentationmodechanged" event, and remove the separate active/switchInProgress properties
Given that we already have a `PresentationModeState`-enumeration, we should use that with the "presentationmodechanged" event rather than including separate properties. Note that this new behaviour, of including an enumeration-value in the event, is consistent with lots of other existing viewer-events.

To hopefully avoid issues in custom implementations of the default viewer, any attempt to access the removed properties will now throw.
2020-12-28 20:31:17 +01:00
Jonas Jenwald
66aabe3ec7 [api-minor] Add support for toggling of Optional Content in the viewer (issue 12096)
*Besides, obviously, adding viewer support:* This patch attempts to improve the general API for Optional Content Groups slightly, by adding a couple of new methods for interacting with the (more complex) data structures of `OptionalContentConfig`-instances. (Thus allowing us to mark some of the data as "private", given that it probably shouldn't be manipulated directly.)

By utilizing not just the "raw" Optional Content Groups, but the data from the `/Order` array when available, we can thus display the Layers in a proper tree-structure with collapsible headings for PDF documents that utilizes that feature.

Note that it's possible to reset all Optional Content Groups to their default visibility state, simply by double-clicking on the Layers-button in the sidebar.
(Currently that's indicated in the Layers-button tooltip, which is obviously easy to overlook, however it's probably the best we can do for now without adding more buttons, or even a dropdown-toolbar, to the sidebar.)

Also, the current Layers-button icons are a little rough around the edges, quite literally, but given that the viewer will soon have its UI modernized anyway they hopefully suffice in the meantime.

To give users *full* control of the visibility of the various Optional Content Groups, even those which according to the `/Order` array should not (by default) be toggleable in the UI, this patch will place those under a *custom* heading which:
 - Is collapsed by default, and placed at the bottom of the Layers-tree, to be a bit less obtrusive.
 - Uses a slightly different formatting, compared to the "regular" headings.
 - Is localizable.

Finally, note that the thumbnails are *purposely* always rendered with all Optional Content Groups at their default visibility state, since that seems the most useful and it's also consistent with other viewers.
To ensure that this works as intended, we'll thus disable the `PDFThumbnailView.setImage` functionality when the Optional Content Groups have been changed in the viewer. (This obviously means that we'll re-render thumbnails instead of using the rendered pages. However, this situation ought to be rare enough for this to not really be a problem.)
2020-08-30 16:28:40 +02:00
Jonas Jenwald
54fc7058e4 Re-factor the "outlineloaded"/"attachmentsloaded" event handlers in PDFSidebar
With recent changes, these event handlers are now essentially identical. Hence a new helper function is added, to reduce unnecessary duplication (will also be helpful with upcoming changes).
2020-08-05 23:08:06 +02:00
Jonas Jenwald
0b65d4cacd Re-factor the dispatching of "attachmentsloaded" events, when the PDF document contains no "regular" attachments
Since the attachment fetching/parsing is already asynchronous, possibly delaying the dispatching of an "attachmentsloaded" event should thus not be a problem in general.
Note that in some cases, i.e. PDF documents with no "regular" attachments and only FileAttachment annotations, we'll thus no longer dispatch an "attachmentsloaded" event when `attachmentsCount === 0` and instead wait for the FileAttachment parsing to finish. (The use of a timeout still guarantees that an "attachmentsloaded" event is *eventually* dispatched though.)

This patch *considerably* simplifies the "attachmentsloaded" event handler, in `PDFSidebar`, since the details are now abstracted away from the consumer.

Finally, add a check in `_appendAttachment` to ensure (indirectly) that the FileAttachment annotation is actually relevant for the active document.
2020-08-03 14:23:44 +02:00
Jonas Jenwald
886b256ada Remove variable shadowing from the JavaScript files in the web/ folder
*This is part of a series of patches that will try to split PR 11566 into smaller chunks, to make reviewing more feasible.*

Once all the code has been fixed, we'll be able to eventually enable the ESLint `no-shadow` rule; see https://eslint.org/docs/rules/no-shadow
2020-03-13 12:59:58 +01:00
Jonas Jenwald
4a1b056c82 Re-factor the EventBus to allow servicing of "external" event listeners *after* the viewer components have updated
Since the goal has always been, essentially since the `EventBus` abstraction was added, to remove all dispatching of DOM events[1] from the viewer components this patch tries to address one thing that came up when updating the examples:
The DOM events are always dispatched last, and it's thus guaranteed that all internal event listeners have been invoked first.
However, there's no such guarantees with the general `EventBus` functionality and the order in which event listeners are invoked is *not* specified. With the promotion of the `EventBus` in the examples, over DOM events, it seems like a good idea to at least *try* to keep this ordering invariant[2] intact.

Obviously this won't prevent anyone from manually calling the new *internal* viewer component methods on the `EventBus`, but hopefully that won't be too common since any existing third-party code would obviously use the `on`/`off` methods and that all of the examples shows the *correct* usage (which should be similarily documented on the "Third party viewer usage" Wiki-page).

---
[1] Looking at the various Firefox-tests, I'm not sure that it'll be possible to (easily) re-write all of them to not rely on DOM events (since getting access to `PDFViewerApplication` might be generally difficult/messy depending on scopes).
In any case, even if technically feasible, it would most likely add *a lot* of complication that may not be desireable in the various Firefox-tests. All-in-all, I'd be fine with keeping the DOM events only for the `MOZCENTRAL` target and gated on `Cu.isInAutomation` (or similar) rather than a preference.

[2] I wouldn't expect any *real* bugs in a custom implementation, simply based on event ordering, but it nonetheless seem like a good idea if any "external" events are still handled last.
2020-02-27 19:38:13 +01:00
Jonas Jenwald
36881e3770 Ensure that all import and require statements, in the entire code-base, have a .js file extension
In order to eventually get rid of SystemJS and start using native `import`s instead, we'll need to provide "complete" file identifiers since otherwise there'll be MIME type errors when attempting to use `import`.
2020-01-04 13:01:43 +01:00
Jonas Jenwald
5d14e68bec Enable the ESLint prefer-const rule in the web/ directory
Please find additional details about the ESLint rule at https://eslint.org/docs/rules/prefer-const

Note that this patch is generated automatically, by using the ESLint `--fix` argument, and will thus require some additional clean-up (which is done separately).
2019-12-27 01:03:58 +01:00
Jonas Jenwald
a63f7ad486 Fix the linting errors, from the Prettier auto-formatting, that ESLint --fix couldn't handle
This patch makes the follow changes:
 - Remove no longer necessary inline `// eslint-disable-...` comments.
 - Fix `// eslint-disable-...` comments that Prettier moved down, thus causing new linting errors.
 - Concatenate strings which now fit on just one line.
 - Fix comments that are now too long.
 - Finally, and most importantly, adjust comments that Prettier moved down, since the new positions often is confusing or outright wrong.
2019-12-26 12:35:12 +01:00
Jonas Jenwald
de36b2aaba Enable auto-formatting of the entire code-base using Prettier (issue 11444)
Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes).

Prettier is being used for a couple of reasons:

 - To be consistent with `mozilla-central`, where Prettier is already in use across the tree.

 - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters.

Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some).
Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long.

*Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit.

(On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-26 12:34:24 +01:00
Tim van der Meij
8b4ae6f3eb
Consistently use @type for getter data types in JSDoc comments
Sometimes we also used `@return` or `@returns`, but `@type` is what
the JSDoc documentation recommends. This also improves the documentation
because before this commit the types were not shown and now they are.
2019-10-13 13:58:17 +02:00
Tim van der Meij
f4daafc077
Consistently use square brackets for optional parameters in JSDoc comments
Square brackets are recommended to indicate optional parameters. Using
them helps for automatically generating correct documentation.
2019-10-13 13:58:17 +02:00
Jonas Jenwald
04a3dc65e4 Move the sidebar toggleButton event listener into PDFSidebar
This is consistent with other functionality, such as e.g. `SecondaryToolbar` and `PDFFindBar`.
2019-08-10 15:38:33 +02:00
Jonas Jenwald
1753f91c6b Re-factor the PDFSidebar constructor to simplify its call-site (PR 10123 follow-up) 2019-02-24 13:15:24 +01:00
Jonas Jenwald
19795597a2 Convert more code to use classList.toggle with the force parameter
There's a bunch of code, in the viewer, which for historical reasons use `switch` statements to add and remove CSS classes.
This code can be simplified, and unnecessary duplication avoided, by using `classList.toggle` instead.
2019-02-06 17:18:45 +01:00
Jonas Jenwald
6806248030 Modify a number of the viewer preferences, whose current default value is 0, such that they behave as expected with the view history
The intention with preferences such as `sidebarViewOnLoad`/`scrollModeOnLoad`/`spreadModeOnLoad` were always that they should be able to *unconditionally* override their view history counterparts.
Due to the way that these preferences were initially implemented[1], trying to e.g. force the sidebar to remain hidden on load cannot be guaranteed[2]. The reason for this is the use of "enumeration values" containing zero, which in hindsight was an unfortunate choice on my part.
At this point it's also not as simple as just re-numbering the affected structures, since that would wreak havoc on existing (modified) preferences. The only reasonable solution that I was able to come up with was to change the *default* values of the preferences themselves, but not their actual values or the meaning thereof.

As part of the refactoring, the `disablePageMode` preference was combined with the *adjusted* `sidebarViewOnLoad` one, to hopefully reduce confusion by not tracking related state separately.

Additionally, the `showPreviousViewOnLoad` and `disableOpenActionDestination` preferences were combined into a *new* `viewOnLoad` enumeration preference, to further avoid tracking related state separately.
2019-02-02 10:21:18 +01:00
Jonas Jenwald
dd4620530d Change PDFSidebar.switchView to act as a wrapper for a "private" PDFSidebar._switchView method
The new "private" method will return a boolean, indicating if the `sidebarviewchanged` event was dispatched, thus allowing some simplification of the `PDFSidebar.setInitialView` method.
2019-02-02 10:21:16 +01:00
Jonas Jenwald
8eda8c27f8 Attempt to simplify the signature of the PDFSidebar constructor, by moving the eventBus parameter from the options object and removing the PDFOutlineViewer dependency
This is similar to the format used by a number of other viewer components, and should simplify the `PDFSidebar` initialization slightly.
Furthermore, by using the `eventBus` it's no longer necessary for `PDFSidebar` to have a direct dependency on `PDFOutlineViewer`.

There's still room for improvement here, but this patch is at least a start (since it's not clear to me how best to handle the viewers).
2018-10-02 13:14:11 +02:00
Jonas Jenwald
7a0db8960d Layout the sidebar in the same vertical position regardless of the viewer width (issue 4052, bug 850591)
If we want to (eventually) make it possible to resize the sidebar, then having its width indirectly affect the toolbar is going to wreck havoc on the media queries used to show/hide buttons in the main toolbar (since many of them depend on the toolbar state, and thus its width).
Updating all of the media queries dynamically with JavaScript seems like a non-starter, given that it'd cause *very* messy code. It thus seem to me that we'd need to fix the position of the sidebar, to have any hope of (in the short term) addressing issue 2072.

Hence, I'm suggesting that the we always layout the sidebar in a consistent vertical position, and only animate the `viewerContainer` rather than the entire `mainContainer`.

Fixes 4052.
Fixes bug 850591.
2017-10-11 18:17:28 +02:00
Jonas Jenwald
870a8f6c35 Remove the ability to pass a scale parameter in the (optional) args object parameter of PDFViewerApplication.open(file, args)
Since the very early days of the viewer, it's been possible to pass in a `scale` when opening a PDF file. However, most of the time it was/is actually being ignored, which limits its usefulness considerably.

In older versions of the viewer, if a document hash was present (i.e. `PDFViewerApplication.initialBookmark` being set) or if the document existed in the `ViewHistory`, the `scale` passed to `PDFViewerApplication.open` would thus always be ignored.
In addition to the above, in the current viewer there's even more cases where the `scale` parameter will be ignored: if a (valid) browser history entry exists on document load, or if the `defaultZoomValue` preference is set to a non-default value.
Hence the result is that in most situation, a `scale` passed to `PDFViewerApplication.open` will be completely ignored.

A much better, not to mention supported, way of setting the initial scale is by using the `defaultZoomLevel` preference. In comparision, this also has the advantage of being used in situations where the `scale` would be ignored.

All in all this leads to the current situation where we have code which is essentially dead, since no part of the viewer (by default) relies on it.
To clean up this code, and to avoid having to pass (basically) unused parameters around, I'd thus like to remove the ability to pass a `scale` to `PDFViewerApplication.open`.
2017-08-24 13:14:00 +02:00
Jonas Jenwald
9273350c6b Attempt to delay disabling of the attachment view until FileAttachment annotations of the *initial* page has been parsed
As discussed in PR 8673, we cannot solve the general issue (since that would require parsing every single page). However, we can mitigate the effect somewhat, by waiting for the FileAttachment annotations of the initially rendered page.
2017-08-17 14:30:03 +02:00
Jonas Jenwald
614e8cf295 Change var to let, and use object destructuring, in a couple of previously class converted web/*.js files
Note that these files were among the first to be converted to ES6 classes, so it probably makes sense to do another pass to bring them inline with the most recent ES6 conversions.
2017-07-03 11:22:49 +02:00
Jonas Jenwald
223c429357 Fix inconsistent spacing and trailing commas in objects in web/ files, so we can enable the comma-dangle and object-curly-spacing ESLint rules later on
http://eslint.org/docs/rules/comma-dangle
http://eslint.org/docs/rules/object-curly-spacing

Given that we currently have quite inconsistent object formatting, fixing this in in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead.

*Please note:* This patch was created automatically, using the ESLint `--fix` command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch.

```diff
diff --git a/web/pdf_thumbnail_view.js b/web/pdf_thumbnail_view.js
index 002dbf29..1de4e530 100644
--- a/web/pdf_thumbnail_view.js
+++ b/web/pdf_thumbnail_view.js
@@ -420,8 +420,8 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
     setPageLabel: function PDFThumbnailView_setPageLabel(label) {
       this.pageLabel = (typeof label === 'string' ? label : null);

-      this.l10n.get('thumb_page_title', { page: this.pageId, }, 'Page {{page}}').
-          then((msg) => {
+      this.l10n.get('thumb_page_title', { page: this.pageId, },
+                    'Page {{page}}').then((msg) => {
         this.anchor.title = msg;
       });

diff --git a/web/secondary_toolbar.js b/web/secondary_toolbar.js
index 160e0410..6495fc5e 100644
--- a/web/secondary_toolbar.js
+++ b/web/secondary_toolbar.js
@@ -65,7 +65,8 @@ class SecondaryToolbar {
       { element: options.printButton, eventName: 'print', close: true, },
       { element: options.downloadButton, eventName: 'download', close: true, },
       { element: options.viewBookmarkButton, eventName: null, close: true, },
-      { element: options.firstPageButton, eventName: 'firstpage', close: true, },
+      { element: options.firstPageButton, eventName: 'firstpage',
+        close: true, },
       { element: options.lastPageButton, eventName: 'lastpage', close: true, },
       { element: options.pageRotateCwButton, eventName: 'rotatecw',
         close: false, },
@@ -76,7 +77,7 @@ class SecondaryToolbar {
       { element: options.cursorHandToolButton, eventName: 'switchcursortool',
         eventDetails: { tool: CursorTool.HAND, }, close: true, },
       { element: options.documentPropertiesButton,
-        eventName: 'documentproperties', close: true, }
+        eventName: 'documentproperties', close: true, },
     ];
     this.items = {
       firstPage: options.firstPageButton,
```
2017-06-01 12:47:47 +02:00
Yury Delendik
5438ce9b98 Wraps mozL10n to async calls; splits firefox and generic l10n libs. 2017-05-31 09:22:25 -05:00
Tim van der Meij
26ad82f5c2
Convert the sidebar to ES6 syntax 2017-04-23 17:13:51 +02:00
Yury Delendik
8e681ce3e2 Change amd to cjs path in ES6 modules 2017-04-14 10:32:36 -05:00
Jonas Jenwald
3b35c15d42 Convert the files in the /web folder to ES6 modules
Note that as discussed on IRC, this makes the viewer slightly slower to load *only* in `gulp server` mode, however the difference seem slight enough that I think it will be fine.
2017-04-09 11:55:48 +02:00
Jonas Jenwald
616e5fadff Display a notification on the sidebarToggle button for PDF documents with outline/attachments
A longstanding issue with the viewer is that you cannot tell if a PDF document includes an outline and/or attachments without actually opening the sidebar.
This patch contains a suggested solution for that, by displaying an hide-on-interaction notification on the `sidebarToggle` button (and the relevant sidebar view buttons). Note that this was inspired by e.g. the update notification that is displayed on the menu button in Firefox.

For an initial implementation, I've tried to do this in such a way that the notification isn't too distracting. Without being an UX expert, I don't think that we'd want something too in-your-face, in order to keep the viewer toolbars reasonable clean. (We probably do *not* want e.g. an entire notification bar in these situations, since that would take up unnecessary screen space and require actions from the user to close.)

However it's certainly possible that the current notification might simply be *too* inconspicuous to be truly helpful to users, but we could probably iterate on that if the feature itself is deemed useful.
2017-01-30 15:39:04 +01:00
Yury Delendik
7fd3db9977 Adds EventBus. 2016-04-28 06:57:24 -05:00
Jonas Jenwald
5657d082c7 Dispatch a sidebarviewchanged event in PDFSidebar when the view changes
We cannot piggy-back on the `updateviewarea` event in order to update the stored sidebar state, since there're a number of cases where opening/switching the sidebar view won't fire a `updateviewarea` event.
Note that `updateviewarea` only fires when the position changes in the *viewer*, which means that it won't fire if e.g. the viewer is narrow, such that the sidebar overlays the document transparently; or when switching views, without the document position also changing.

This patch also moves the handling of `forceOpen` parameter in `PDFSidebar_switchView`, to prevent triggering back-to-back rendering and dispatching of events.
2016-04-16 10:10:28 +02:00
Yury Delendik
006e8fb59d Introduces UMD headers to the web/ folder. 2016-04-13 10:09:48 -05:00
Jonas Jenwald
39cba5d25d Remove PDFThumbnailViewer_ensureThumbnailVisible
Functionality wise, `ensureThumbnailVisible` is essentially just a shorthand for `scrollThumbnailIntoView`. (And note that `PDFViewer` doesn't implement a `ensurePageVisible` method.)

The only remaining usage of `PDFThumbnailViewer_ensureThumbnailVisible` is inside `PDFPresentationMode`, which introduces an otherwise unnecessary `PDFThumbnailViewer` dependency there.

We're already relying on the `presentationmodechanged` event, in various files, to track the state of Presentation Mode. Thus we can simply listen for that event in `PDFSidebar` too, and update the thumbnails if necessary.
2016-02-28 18:21:59 +01:00
Jonas Jenwald
67a1dfcfb5 Move the sidebar related code from viewer.js into PDFSidebar
The sidebar code has, except for minor fixes/additions (such as attachments), been largely untouch for years.
To avoid having a bunch of sidebar code sprinkled throughout viewer.js, this patch moves the sidebar code into a separate file (pdf_sidebar.js), similar to how most other functionality has been moved in the last few years.

Besides simply moving code around, this patch also has the added benefit that we now keep track of the sidebar state (not just opened/closed).
This now makes it possible to handle both `Preferences` *and* `ViewHistory` settings for the sidebar state in a cleaner way, preventing strange and confusing interactions between the two.
2016-02-27 14:13:09 +01:00