summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown.js')
-rw-r--r--chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown.js219
1 files changed, 219 insertions, 0 deletions
diff --git a/chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown.js b/chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown.js
new file mode 100644
index 00000000000..191f4cfcfbf
--- /dev/null
+++ b/chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown.js
@@ -0,0 +1,219 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function() {
+/**
+ * Size of additional padding in the inner scrollable section of the dropdown.
+ */
+const DROPDOWN_INNER_PADDING = 12;
+
+/** Size of vertical padding on the outer #dropdown element. */
+const DROPDOWN_OUTER_PADDING = 2;
+
+/** Minimum height of toolbar dropdowns (px). */
+const MIN_DROPDOWN_HEIGHT = 200;
+
+Polymer({
+ is: 'viewer-toolbar-dropdown',
+
+ properties: {
+ /** Icon to display when the dropdown is closed. */
+ closedIcon: String,
+
+ /** Whether the dropdown should be centered or right aligned. */
+ dropdownCentered: {
+ type: Boolean,
+ reflectToAttribute: true,
+ value: false,
+ },
+
+ /** True if the dropdown is currently open. */
+ dropdownOpen: {
+ type: Boolean,
+ reflectToAttribute: true,
+ value: false,
+ },
+
+ /**
+ * String to be displayed at the top of the dropdown and for the tooltip
+ * of the button.
+ */
+ header: String,
+
+ /** Whether to hide the header at the top of the dropdown. */
+ hideHeader: {
+ type: Boolean,
+ value: false,
+ },
+
+ /** Lowest vertical point that the dropdown should occupy (px). */
+ lowerBound: {
+ type: Number,
+ observer: 'lowerBoundChanged_',
+ },
+
+ /** Unique id to identify this dropdown for metrics purposes. */
+ metricsId: String,
+
+ /** Whether the dropdown must be selected before opening. */
+ openAfterSelect: {
+ type: Boolean,
+ value: false,
+ },
+
+ /** Icon to display when the dropdown is open. */
+ openIcon: String,
+
+ /** Whether the dropdown is marked as selected. */
+ selected: {
+ type: Boolean,
+ reflectToAttribute: true,
+ value: false,
+ },
+
+ /**
+ * Toolbar icon currently being displayed.
+ * @private
+ */
+ dropdownIcon_: {
+ type: String,
+ computed: 'computeIcon_(dropdownOpen, closedIcon, openIcon)',
+ },
+ },
+
+ /**
+ * Current animation being played, or null if there is none.
+ * @private {?Object}
+ */
+ animation_: null,
+
+ /**
+ * True if the max-height CSS property for the dropdown scroll container
+ * is valid. If false, the height will be updated the next time the
+ * dropdown is visible.
+ * @private {boolean}
+ */
+ maxHeightValid_: false,
+
+ /**
+ * @return {string} Current icon for the dropdown.
+ * @private
+ */
+ computeIcon_: function(dropdownOpen, closedIcon, openIcon) {
+ return dropdownOpen ? openIcon : closedIcon;
+ },
+
+ /** @private */
+ lowerBoundChanged_: function() {
+ this.maxHeightValid_ = false;
+ if (this.dropdownOpen) {
+ this.updateMaxHeight();
+ }
+ },
+
+ toggleDropdown: function() {
+ if (!this.dropdownOpen && this.openAfterSelect && !this.selected) {
+ // The dropdown has `openAfterSelect` set, but is not yet selected.
+ return;
+ }
+ this.dropdownOpen = !this.dropdownOpen;
+ if (this.dropdownOpen) {
+ this.$.dropdown.style.display = 'block';
+ if (!this.maxHeightValid_) {
+ this.updateMaxHeight();
+ }
+ this.fire('dropdown-opened', this.metricsId);
+ }
+
+ if (this.dropdownOpen) {
+ const listener = (e) => {
+ if (e.path.includes(this)) {
+ return;
+ }
+ if (this.dropdownOpen) {
+ this.toggleDropdown();
+ this.blur();
+ }
+ // Clean up the handler. The dropdown may already be closed.
+ window.removeEventListener('pointerdown', listener);
+ };
+ window.addEventListener('pointerdown', listener);
+ }
+
+ this.playAnimation_(this.dropdownOpen);
+ },
+
+ updateMaxHeight: function() {
+ const scrollContainer = this.$['scroll-container'];
+ let height = this.lowerBound - scrollContainer.getBoundingClientRect().top -
+ DROPDOWN_INNER_PADDING;
+ height = Math.max(height, MIN_DROPDOWN_HEIGHT);
+ scrollContainer.style.maxHeight = height + 'px';
+ this.maxHeightValid_ = true;
+ },
+
+ /**
+ * Start an animation on the dropdown.
+ * @param {boolean} isEntry True to play entry animation, false to play
+ * exit.
+ * @private
+ */
+ playAnimation_: function(isEntry) {
+ this.animation_ = isEntry ? this.animateEntry_() : this.animateExit_();
+ this.animation_.onfinish = () => {
+ this.animation_ = null;
+ if (!this.dropdownOpen) {
+ this.$.dropdown.style.display = 'none';
+ }
+ };
+ },
+
+ /**
+ * @return {!Object} Animation
+ * @private
+ */
+ animateEntry_: function() {
+ let maxHeight =
+ this.$.dropdown.getBoundingClientRect().height - DROPDOWN_OUTER_PADDING;
+
+ if (maxHeight < 0) {
+ maxHeight = 0;
+ }
+
+ this.$.dropdown.animate(
+ {
+ opacity: [0, 1],
+ },
+ {
+ duration: 150,
+ easing: 'cubic-bezier(0, 0, 0.2, 1)',
+ });
+ return this.$.dropdown.animate(
+ [
+ {height: '20px', transform: 'translateY(-10px)'},
+ {height: maxHeight + 'px', transform: 'translateY(0)'},
+ ],
+ {
+ duration: 250,
+ easing: 'cubic-bezier(0, 0, 0.2, 1)',
+ });
+ },
+
+ /**
+ * @return {!Object} Animation
+ * @private
+ */
+ animateExit_: function() {
+ return this.$.dropdown.animate(
+ [
+ {transform: 'translateY(0)', opacity: 1},
+ {transform: 'translateY(-5px)', opacity: 0},
+ ],
+ {
+ duration: 100,
+ easing: 'cubic-bezier(0.4, 0, 1, 1)',
+ });
+ }
+});
+})();