From 7c992243fd62c4e74e331f7f3672022125a403d8 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Tue, 21 Jul 2015 19:52:49 +0200 Subject: [PATCH] Allow outline to be collapsed / shown via icon. - This commit adds a '>' before every outline item that has subitems. - Click on the '>' to collapse all subitems under that item (which turns the '>' in a 'v'). - Shift + click expands/collapses all descendant items under that tree. - Double-clicking on the "Show Document Outline" button in the toolbar expands/collapses all outline items. --- web/images/treeitem-collapsed.png | Bin 0 -> 125 bytes web/images/treeitem-collapsed@2x.png | Bin 0 -> 172 bytes web/images/treeitem-expanded.png | Bin 0 -> 128 bytes web/images/treeitem-expanded@2x.png | Bin 0 -> 149 bytes web/pdf_outline_view.js | 59 ++++++++++++++++++++++++++- web/viewer.css | 39 +++++++++++++++++- web/viewer.js | 5 +++ 7 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 web/images/treeitem-collapsed.png create mode 100644 web/images/treeitem-collapsed@2x.png create mode 100644 web/images/treeitem-expanded.png create mode 100644 web/images/treeitem-expanded@2x.png diff --git a/web/images/treeitem-collapsed.png b/web/images/treeitem-collapsed.png new file mode 100644 index 0000000000000000000000000000000000000000..c8d557351cd2fc80c3abd4b19e52924cd74780d5 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>0wld=oSO}#Ts&PILn;`P75MhNs4Zk;-DbE) zpt_L5GvPZo^g4)z4*}Q$iB}$ABb+ literal 0 HcmV?d00001 diff --git a/web/images/treeitem-collapsed@2x.png b/web/images/treeitem-collapsed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3b3b6103b356200d05caf7fa692cadf2c1e89043 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+0wn(&ce?|mialK%Ln;`P7Z_I0wld=oSO}#+&x_!LpZJ{CnQuDzHAj@)~YCc zcJ!pUslH1WIk z$<$8#)-<<4$>7e1Lt^WdBv>MS0tC+_?dkdu(KF##vY``K|4|Ok95LarEgxHDk6!z_ xe}ZGN#WGb9Hnl@SJ`EdME-hi&#=_6Qka7RV*Qd`VTY>g4c)I$ztaD0e0sz~DGV1^U literal 0 HcmV?d00001 diff --git a/web/pdf_outline_view.js b/web/pdf_outline_view.js index 311a27011..94b545f2b 100644 --- a/web/pdf_outline_view.js +++ b/web/pdf_outline_view.js @@ -36,6 +36,7 @@ var PDFOutlineView = (function PDFOutlineViewClosure() { this.container = options.container; this.outline = options.outline; this.linkService = options.linkService; + this.lastToggleIsShow = true; } PDFOutlineView.prototype = { @@ -44,6 +45,7 @@ var PDFOutlineView = (function PDFOutlineViewClosure() { while (container.firstChild) { container.removeChild(container.firstChild); } + this.lastToggleIsShow = true; }, /** @@ -69,6 +71,51 @@ var PDFOutlineView = (function PDFOutlineViewClosure() { }; }, + /** + * Prepend a button before an outline item which allows the user to toggle + * the visibility of all outline items at that level. + * + * @private + */ + _addToggleButton: function PDFOutlineView_addToggleButton(div) { + var toggler = document.createElement('div'); + toggler.className = 'outlineItemToggler'; + toggler.onclick = function(event) { + event.stopPropagation(); + toggler.classList.toggle('outlineItemsHidden'); + + if (event.shiftKey) { + var shouldShowAll = !toggler.classList.contains('outlineItemsHidden'); + this._toggleOutlineItem(div, shouldShowAll); + } + }.bind(this); + div.insertBefore(toggler, div.firstChild); + }, + + /** + * Toggle the visibility of the subtree of an outline item. + * + * @param {Element} root - the root of the outline (sub)tree. + * @param {boolean} state - whether to show the outline (sub)tree. If false, + * the outline subtree rooted at |root| will be collapsed. + * + * @private + */ + _toggleOutlineItem: function PDFOutlineView_toggleOutlineItem(root, show) { + this.lastToggleIsShow = show; + var togglers = root.querySelectorAll('.outlineItemToggler'); + for (var i = 0, ii = togglers.length; i < ii; ++i) { + togglers[i].classList[show ? 'remove' : 'add']('outlineItemsHidden'); + } + }, + + /** + * Collapse or expand all subtrees of the outline. + */ + toggleOutlineTree: function PDFOutlineView_toggleOutlineTree() { + this._toggleOutlineItem(this.container, !this.lastToggleIsShow); + }, + render: function PDFOutlineView_render() { var outline = this.outline; var outlineCount = 0; @@ -80,7 +127,9 @@ var PDFOutlineView = (function PDFOutlineViewClosure() { return; } - var queue = [{ parent: this.container, items: this.outline }]; + var fragment = document.createDocumentFragment(); + var queue = [{ parent: fragment, items: this.outline }]; + var hasAnyNesting = false; while (queue.length > 0) { var levelData = queue.shift(); for (var i = 0, len = levelData.items.length; i < len; i++) { @@ -93,6 +142,9 @@ var PDFOutlineView = (function PDFOutlineViewClosure() { div.appendChild(element); if (item.items.length > 0) { + hasAnyNesting = true; + this._addToggleButton(div); + var itemsDiv = document.createElement('div'); itemsDiv.className = 'outlineItems'; div.appendChild(itemsDiv); @@ -103,6 +155,11 @@ var PDFOutlineView = (function PDFOutlineViewClosure() { outlineCount++; } } + if (hasAnyNesting) { + this.container.classList.add('outlineWithDeepNesting'); + } + + this.container.appendChild(fragment); this._dispatchEvent(outlineCount); } diff --git a/web/viewer.css b/web/viewer.css index 4602351a4..3da1ff021 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -1190,10 +1190,12 @@ a:focus > .thumbnail > .thumbnailSelectionRing, padding: 3px 4px 0; } +html[dir='ltr'] .outlineWithDeepNesting > .outlineItem, html[dir='ltr'] .outlineItem > .outlineItems { margin-left: 20px; } +html[dir='rtl'] .outlineWithDeepNesting > .outlineItem, html[dir='rtl'] .outlineItem > .outlineItems { margin-right: 20px; } @@ -1221,7 +1223,7 @@ html[dir='rtl'] .outlineItem > .outlineItems { } html[dir='ltr'] .outlineItem > a { - padding: 2px 0 5px 10px; + padding: 2px 0 5px 4px; } html[dir='ltr'] .attachmentsItem > button { padding: 2px 0 3px 7px; @@ -1229,13 +1231,46 @@ html[dir='ltr'] .attachmentsItem > button { } html[dir='rtl'] .outlineItem > a { - padding: 2px 10px 5px 0; + padding: 2px 4px 5px 0; } html[dir='rtl'] .attachmentsItem > button { padding: 2px 7px 3px 0; text-align: right; } +.outlineItemToggler { + position: relative; + height: 0; + width: 0; + color: hsla(0,0%,100%,.5); +} +.outlineItemToggler::before { + content: url(images/treeitem-collapsed.png); + display: inline-block; + position: absolute; +} +.outlineItemToggler.outlineItemsHidden::before { + content: url(images/treeitem-expanded.png); +} +.outlineItemToggler.outlineItemsHidden ~ .outlineItems { + display: none; +} +html[dir='ltr'] .outlineItemToggler { + float: left; +} +html[dir='rtl'] .outlineItemToggler { + float: right; +} +html[dir='ltr'] .outlineItemToggler::before { + right: 4px; +} +html[dir='rtl'] .outlineItemToggler::before { + left: 4px; +} + +.outlineItemToggler:hover, +.outlineItemToggler:hover + a, +.outlineItemToggler:hover ~ .outlineItems, .outlineItem > a:hover, .attachmentsItem > button:hover { background-color: hsla(0,0%,100%,.02); diff --git a/web/viewer.js b/web/viewer.js index fc6e8f3ba..3819f5231 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -1401,6 +1401,11 @@ function webViewerInitialized() { PDFViewerApplication.switchSidebarView('outline'); }); + document.getElementById('viewOutline').addEventListener('dblclick', + function() { + PDFViewerApplication.outline.toggleOutlineTree(); + }); + document.getElementById('viewAttachments').addEventListener('click', function() { PDFViewerApplication.switchSidebarView('attachments');