aboutsummaryrefslogtreecommitdiff
path: root/catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html
diff options
context:
space:
mode:
Diffstat (limited to 'catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html')
-rw-r--r--catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html407
1 files changed, 407 insertions, 0 deletions
diff --git a/catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html b/catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html
new file mode 100644
index 00000000..670280b1
--- /dev/null
+++ b/catapult/third_party/polymer/components/paper-tooltip/paper-tooltip.html
@@ -0,0 +1,407 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../neon-animation/neon-animation-runner-behavior.html">
+<link rel="import" href="../neon-animation/animations/fade-in-animation.html">
+<link rel="import" href="../neon-animation/animations/fade-out-animation.html">
+
+<!--
+Material design: [Tooltips](https://www.google.com/design/spec/components/tooltips.html)
+
+`<paper-tooltip>` is a label that appears on hover and focus when the user
+hovers over an element with the cursor or with the keyboard. It will be centered
+to an anchor element specified in the `for` attribute, or, if that doesn't exist,
+centered to the parent node containing it.
+
+Example:
+
+ <div style="display:inline-block">
+ <button>Click me!</button>
+ <paper-tooltip>Tooltip text</paper-tooltip>
+ </div>
+
+ <div>
+ <button id="btn">Click me!</button>
+ <paper-tooltip for="btn">Tooltip text</paper-tooltip>
+ </div>
+
+The tooltip can be positioned on the top|bottom|left|right of the anchor using
+the `position` attribute. The default position is bottom.
+
+ <paper-tooltip for="btn" position="left">Tooltip text</paper-tooltip>
+ <paper-tooltip for="btn" position="top">Tooltip text</paper-tooltip>
+
+### Styling
+
+The following custom properties and mixins are available for styling:
+
+Custom property | Description | Default
+----------------|-------------|----------
+`--paper-tooltip-background` | The background color of the tooltip | `#616161`
+`--paper-tooltip-opacity` | The opacity of the tooltip | `0.9`
+`--paper-tooltip-text-color` | The text color of the tooltip | `white`
+`--paper-tooltip` | Mixin applied to the tooltip | `{}`
+
+@group Paper Elements
+@element paper-tooltip
+@demo demo/index.html
+-->
+
+<dom-module id="paper-tooltip">
+ <template>
+ <style>
+ :host {
+ display: block;
+ position: absolute;
+ outline: none;
+ z-index: 1002;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+ cursor: default;
+ }
+
+ #tooltip {
+ display: block;
+ outline: none;
+ @apply(--paper-font-common-base);
+ font-size: 10px;
+ line-height: 1;
+
+ background-color: var(--paper-tooltip-background, #616161);
+ opacity: var(--paper-tooltip-opacity, 0.9);
+ color: var(--paper-tooltip-text-color, white);
+
+ padding: 8px;
+ border-radius: 2px;
+
+ @apply(--paper-tooltip);
+ }
+
+ /* Thanks IE 10. */
+ .hidden {
+ display: none !important;
+ }
+ </style>
+
+ <div id="tooltip" class="hidden">
+ <content></content>
+ </div>
+ </template>
+
+ <script>
+ Polymer({
+ is: 'paper-tooltip',
+
+ hostAttributes: {
+ role: 'tooltip',
+ tabindex: -1
+ },
+
+ behaviors: [
+ Polymer.NeonAnimationRunnerBehavior
+ ],
+
+ properties: {
+ /**
+ * The id of the element that the tooltip is anchored to. This element
+ * must be a sibling of the tooltip.
+ */
+ for: {
+ type: String,
+ observer: '_findTarget'
+ },
+
+ /**
+ * Set this to true if you want to manually control when the tooltip
+ * is shown or hidden.
+ */
+ manualMode: {
+ type: Boolean,
+ value: false,
+ observer: '_manualModeChanged'
+ },
+
+ /**
+ * Positions the tooltip to the top, right, bottom, left of its content.
+ */
+ position: {
+ type: String,
+ value: 'bottom'
+ },
+
+ /**
+ * If true, no parts of the tooltip will ever be shown offscreen.
+ */
+ fitToVisibleBounds: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The spacing between the top of the tooltip and the element it is
+ * anchored to.
+ */
+ offset: {
+ type: Number,
+ value: 14
+ },
+
+ /**
+ * This property is deprecated, but left over so that it doesn't
+ * break exiting code. Please use `offset` instead. If both `offset` and
+ * `marginTop` are provided, `marginTop` will be ignored.
+ * @deprecated since version 1.0.3
+ */
+ marginTop: {
+ type: Number,
+ value: 14
+ },
+
+ /**
+ * The delay that will be applied before the `entry` animation is
+ * played when showing the tooltip.
+ */
+ animationDelay: {
+ type: Number,
+ value: 500
+ },
+
+ /**
+ * The entry and exit animations that will be played when showing and
+ * hiding the tooltip. If you want to override this, you must ensure
+ * that your animationConfig has the exact format below.
+ */
+ animationConfig: {
+ type: Object,
+ value: function() {
+ return {
+ 'entry': [{
+ name: 'fade-in-animation',
+ node: this,
+ timing: {delay: 0}
+ }],
+ 'exit': [{
+ name: 'fade-out-animation',
+ node: this
+ }]
+ }
+ }
+ },
+
+ _showing: {
+ type: Boolean,
+ value: false
+ }
+ },
+
+ listeners: {
+ 'neon-animation-finish': '_onAnimationFinish',
+ },
+
+ /**
+ * Returns the target element that this tooltip is anchored to. It is
+ * either the element given by the `for` attribute, or the immediate parent
+ * of the tooltip.
+ */
+ get target () {
+ var parentNode = Polymer.dom(this).parentNode;
+ // If the parentNode is a document fragment, then we need to use the host.
+ var ownerRoot = Polymer.dom(this).getOwnerRoot();
+
+ var target;
+ if (this.for) {
+ target = Polymer.dom(ownerRoot).querySelector('#' + this.for);
+ } else {
+ target = parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE ?
+ ownerRoot.host : parentNode;
+ }
+
+ return target;
+ },
+
+ attached: function() {
+ this._findTarget();
+ },
+
+ detached: function() {
+ if (!this.manualMode)
+ this._removeListeners();
+ },
+
+ show: function() {
+ // If the tooltip is already showing, there's nothing to do.
+ if (this._showing)
+ return;
+
+ if (Polymer.dom(this).textContent.trim() === ''){
+ // Check if effective children are also empty
+ var allChildrenEmpty = true;
+ var effectiveChildren = Polymer.dom(this).getEffectiveChildNodes();
+ for (var i = 0; i < effectiveChildren.length; i++) {
+ if (effectiveChildren[i].textContent.trim() !== '') {
+ allChildrenEmpty = false;
+ break;
+ }
+ }
+ if (allChildrenEmpty) {
+ return;
+ }
+ }
+
+
+ this.cancelAnimation();
+ this._showing = true;
+ this.toggleClass('hidden', false, this.$.tooltip);
+ this.updatePosition();
+
+ this.animationConfig.entry[0].timing = this.animationConfig.entry[0].timing || {};
+ this.animationConfig.entry[0].timing.delay = this.animationDelay;
+ this._animationPlaying = true;
+ this.playAnimation('entry');
+ },
+
+ hide: function() {
+ // If the tooltip is already hidden, there's nothing to do.
+ if (!this._showing) {
+ return;
+ }
+
+ // If the entry animation is still playing, don't try to play the exit
+ // animation since this will reset the opacity to 1. Just end the animation.
+ if (this._animationPlaying) {
+ this.cancelAnimation();
+ this._showing = false;
+ this._onAnimationFinish();
+ return;
+ }
+
+ this._showing = false;
+ this._animationPlaying = true;
+ this.playAnimation('exit');
+ },
+
+ updatePosition: function() {
+ if (!this._target || !this.offsetParent)
+ return;
+
+ var offset = this.offset;
+ // If a marginTop has been provided by the user (pre 1.0.3), use it.
+ if (this.marginTop != 14 && this.offset == 14)
+ offset = this.marginTop;
+
+ var parentRect = this.offsetParent.getBoundingClientRect();
+ var targetRect = this._target.getBoundingClientRect();
+ var thisRect = this.getBoundingClientRect();
+
+ var horizontalCenterOffset = (targetRect.width - thisRect.width) / 2;
+ var verticalCenterOffset = (targetRect.height - thisRect.height) / 2;
+
+ var targetLeft = targetRect.left - parentRect.left;
+ var targetTop = targetRect.top - parentRect.top;
+
+ var tooltipLeft, tooltipTop;
+
+ switch (this.position) {
+ case 'top':
+ tooltipLeft = targetLeft + horizontalCenterOffset;
+ tooltipTop = targetTop - thisRect.height - offset;
+ break;
+ case 'bottom':
+ tooltipLeft = targetLeft + horizontalCenterOffset;
+ tooltipTop = targetTop + targetRect.height + offset;
+ break;
+ case 'left':
+ tooltipLeft = targetLeft - thisRect.width - offset;
+ tooltipTop = targetTop + verticalCenterOffset;
+ break;
+ case 'right':
+ tooltipLeft = targetLeft + targetRect.width + offset;
+ tooltipTop = targetTop + verticalCenterOffset;
+ break;
+ }
+
+ // TODO(noms): This should use IronFitBehavior if possible.
+ if (this.fitToVisibleBounds) {
+ // Clip the left/right side
+ if (parentRect.left + tooltipLeft + thisRect.width > window.innerWidth) {
+ this.style.right = '0px';
+ this.style.left = 'auto';
+ } else {
+ this.style.left = Math.max(0, tooltipLeft) + 'px';
+ this.style.right = 'auto';
+ }
+
+ // Clip the top/bottom side.
+ if (parentRect.top + tooltipTop + thisRect.height > window.innerHeight) {
+ this.style.bottom = parentRect.height + 'px';
+ this.style.top = 'auto';
+ } else {
+ this.style.top = Math.max(-parentRect.top, tooltipTop) + 'px';
+ this.style.bottom = 'auto';
+ }
+ } else {
+ this.style.left = tooltipLeft + 'px';
+ this.style.top = tooltipTop + 'px';
+ }
+
+ },
+
+ _addListeners: function() {
+ if (this._target) {
+ this.listen(this._target, 'mouseenter', 'show');
+ this.listen(this._target, 'focus', 'show');
+ this.listen(this._target, 'mouseleave', 'hide');
+ this.listen(this._target, 'blur', 'hide');
+ this.listen(this._target, 'tap', 'hide');
+ }
+ this.listen(this, 'mouseenter', 'hide');
+ },
+
+ _findTarget: function() {
+ if (!this.manualMode)
+ this._removeListeners();
+
+ this._target = this.target;
+
+ if (!this.manualMode)
+ this._addListeners();
+ },
+
+ _manualModeChanged: function() {
+ if (this.manualMode)
+ this._removeListeners();
+ else
+ this._addListeners();
+ },
+
+ _onAnimationFinish: function() {
+ this._animationPlaying = false;
+ if (!this._showing) {
+ this.toggleClass('hidden', true, this.$.tooltip);
+ }
+ },
+
+ _removeListeners: function() {
+ if (this._target) {
+ this.unlisten(this._target, 'mouseenter', 'show');
+ this.unlisten(this._target, 'focus', 'show');
+ this.unlisten(this._target, 'mouseleave', 'hide');
+ this.unlisten(this._target, 'blur', 'hide');
+ this.unlisten(this._target, 'tap', 'hide');
+ }
+ this.unlisten(this, 'mouseenter', 'hide');
+ }
+ });
+ </script>
+</dom-module>