| Index: chrome/browser/resources/md_history/lazy_load.crisper.js
|
| diff --git a/chrome/browser/resources/md_history/lazy_load.crisper.js b/chrome/browser/resources/md_history/lazy_load.crisper.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..29502b017090db42b4004999cd9ec846036c4f53
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/md_history/lazy_load.crisper.js
|
| @@ -0,0 +1,3291 @@
|
| +Polymer({
|
| + is: 'iron-collapse',
|
| + behaviors: [ Polymer.IronResizableBehavior ],
|
| + properties: {
|
| + horizontal: {
|
| + type: Boolean,
|
| + value: false,
|
| + observer: '_horizontalChanged'
|
| + },
|
| + opened: {
|
| + type: Boolean,
|
| + value: false,
|
| + notify: true,
|
| + observer: '_openedChanged'
|
| + },
|
| + noAnimation: {
|
| + type: Boolean
|
| + },
|
| + _desiredSize: {
|
| + type: String,
|
| + value: ''
|
| + }
|
| + },
|
| + get dimension() {
|
| + return this.horizontal ? 'width' : 'height';
|
| + },
|
| + get _dimensionMax() {
|
| + return this.horizontal ? 'maxWidth' : 'maxHeight';
|
| + },
|
| + get _dimensionMaxCss() {
|
| + return this.horizontal ? 'max-width' : 'max-height';
|
| + },
|
| + hostAttributes: {
|
| + role: 'group',
|
| + 'aria-hidden': 'true',
|
| + 'aria-expanded': 'false'
|
| + },
|
| + listeners: {
|
| + transitionend: '_transitionEnd'
|
| + },
|
| + attached: function() {
|
| + this._transitionEnd();
|
| + },
|
| + toggle: function() {
|
| + this.opened = !this.opened;
|
| + },
|
| + show: function() {
|
| + this.opened = true;
|
| + },
|
| + hide: function() {
|
| + this.opened = false;
|
| + },
|
| + updateSize: function(size, animated) {
|
| + size = size === 'auto' ? '' : size;
|
| + if (this._desiredSize === size) {
|
| + return;
|
| + }
|
| + this._desiredSize = size;
|
| + this._updateTransition(false);
|
| + var willAnimate = animated && !this.noAnimation && this._isDisplayed;
|
| + if (willAnimate) {
|
| + var startSize = this._calcSize();
|
| + if (size === '') {
|
| + this.style[this._dimensionMax] = '';
|
| + size = this._calcSize();
|
| + }
|
| + this.style[this._dimensionMax] = startSize;
|
| + this.scrollTop = this.scrollTop;
|
| + this._updateTransition(true);
|
| + willAnimate = size !== startSize;
|
| + }
|
| + this.style[this._dimensionMax] = size;
|
| + if (!willAnimate) {
|
| + this._transitionEnd();
|
| + }
|
| + },
|
| + enableTransition: function(enabled) {
|
| + Polymer.Base._warn('`enableTransition()` is deprecated, use `noAnimation` instead.');
|
| + this.noAnimation = !enabled;
|
| + },
|
| + _updateTransition: function(enabled) {
|
| + this.style.transitionDuration = enabled && !this.noAnimation ? '' : '0s';
|
| + },
|
| + _horizontalChanged: function() {
|
| + this.style.transitionProperty = this._dimensionMaxCss;
|
| + var otherDimension = this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxWidth';
|
| + this.style[otherDimension] = '';
|
| + this.updateSize(this.opened ? 'auto' : '0px', false);
|
| + },
|
| + _openedChanged: function() {
|
| + this.setAttribute('aria-expanded', this.opened);
|
| + this.setAttribute('aria-hidden', !this.opened);
|
| + this.toggleClass('iron-collapse-closed', false);
|
| + this.toggleClass('iron-collapse-opened', false);
|
| + this.updateSize(this.opened ? 'auto' : '0px', true);
|
| + if (this.opened) {
|
| + this.focus();
|
| + }
|
| + },
|
| + _transitionEnd: function() {
|
| + this.style[this._dimensionMax] = this._desiredSize;
|
| + this.toggleClass('iron-collapse-closed', !this.opened);
|
| + this.toggleClass('iron-collapse-opened', this.opened);
|
| + this._updateTransition(false);
|
| + this.notifyResize();
|
| + },
|
| + get _isDisplayed() {
|
| + var rect = this.getBoundingClientRect();
|
| + for (var prop in rect) {
|
| + if (rect[prop] !== 0) return true;
|
| + }
|
| + return false;
|
| + },
|
| + _calcSize: function() {
|
| + return this.getBoundingClientRect()[this.dimension] + 'px';
|
| + }
|
| +});
|
| +
|
| +// Copyright 2016 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.
|
| +var HistoryDomain;
|
| +
|
| +var HistoryGroup;
|
| +
|
| +Polymer({
|
| + is: 'history-grouped-list',
|
| + behaviors: [ HistoryListBehavior ],
|
| + properties: {
|
| + historyData: {
|
| + type: Array
|
| + },
|
| + groupedHistoryData_: {
|
| + type: Array
|
| + },
|
| + searchedTerm: {
|
| + type: String,
|
| + value: ''
|
| + },
|
| + range: {
|
| + type: Number
|
| + },
|
| + queryStartTime: String,
|
| + queryEndTime: String
|
| + },
|
| + observers: [ 'updateGroupedHistoryData_(range, historyData)' ],
|
| + createHistoryDomains_: function(visits) {
|
| + var domainIndexes = {};
|
| + var domains = [];
|
| + for (var i = 0, visit; visit = visits[i]; i++) {
|
| + var domain = visit.domain;
|
| + if (domainIndexes[domain] == undefined) {
|
| + domainIndexes[domain] = domains.length;
|
| + domains.push({
|
| + domain: domain,
|
| + visits: [],
|
| + expanded: false,
|
| + rendered: false
|
| + });
|
| + }
|
| + domains[domainIndexes[domain]].visits.push(visit);
|
| + }
|
| + var sortByVisits = function(a, b) {
|
| + return b.visits.length - a.visits.length;
|
| + };
|
| + domains.sort(sortByVisits);
|
| + return domains;
|
| + },
|
| + updateGroupedHistoryData_: function() {
|
| + if (this.historyData.length == 0) {
|
| + this.groupedHistoryData_ = [];
|
| + return;
|
| + }
|
| + if (this.range == HistoryRange.WEEK) {
|
| + var days = [];
|
| + var currentDayVisits = [ this.historyData[0] ];
|
| + var pushCurrentDay = function() {
|
| + days.push({
|
| + title: this.searchedTerm ? currentDayVisits[0].dateShort : currentDayVisits[0].dateRelativeDay,
|
| + domains: this.createHistoryDomains_(currentDayVisits)
|
| + });
|
| + }.bind(this);
|
| + var visitsSameDay = function(a, b) {
|
| + if (this.searchedTerm) return a.dateShort == b.dateShort;
|
| + return a.dateRelativeDay == b.dateRelativeDay;
|
| + }.bind(this);
|
| + for (var i = 1; i < this.historyData.length; i++) {
|
| + var visit = this.historyData[i];
|
| + if (!visitsSameDay(visit, currentDayVisits[0])) {
|
| + pushCurrentDay();
|
| + currentDayVisits = [];
|
| + }
|
| + currentDayVisits.push(visit);
|
| + }
|
| + pushCurrentDay();
|
| + this.groupedHistoryData_ = days;
|
| + } else if (this.range == HistoryRange.MONTH) {
|
| + this.groupedHistoryData_ = [ {
|
| + title: this.queryStartTime + ' – ' + this.queryEndTime,
|
| + domains: this.createHistoryDomains_(this.historyData)
|
| + } ];
|
| + }
|
| + },
|
| + toggleDomainExpanded_: function(e) {
|
| + var collapse = e.currentTarget.parentNode.querySelector('iron-collapse');
|
| + e.model.set('domain.rendered', true);
|
| + setTimeout(function() {
|
| + collapse.toggle();
|
| + }, 0);
|
| + },
|
| + needsTimeGap_: function(groupIndex, domainIndex, itemIndex) {
|
| + var visits = this.groupedHistoryData_[groupIndex].domains[domainIndex].visits;
|
| + return md_history.HistoryItem.needsTimeGap(visits, itemIndex, this.searchedTerm);
|
| + },
|
| + pathForItem_: function(groupIndex, domainIndex, itemIndex) {
|
| + return [ 'groupedHistoryData_', groupIndex, 'domains', domainIndex, 'visits', itemIndex ].join('.');
|
| + },
|
| + getWebsiteIconStyle_: function(domain) {
|
| + return 'background-image: ' + cr.icon.getFavicon(domain.visits[0].url);
|
| + },
|
| + getDropdownIcon_: function(expanded) {
|
| + return expanded ? 'cr:expand-less' : 'cr:expand-more';
|
| + }
|
| +});
|
| +
|
| +Polymer.PaperButtonBehaviorImpl = {
|
| + properties: {
|
| + elevation: {
|
| + type: Number,
|
| + reflectToAttribute: true,
|
| + readOnly: true
|
| + }
|
| + },
|
| + observers: [ '_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)', '_computeKeyboardClass(receivedFocusFromKeyboard)' ],
|
| + hostAttributes: {
|
| + role: 'button',
|
| + tabindex: '0',
|
| + animated: true
|
| + },
|
| + _calculateElevation: function() {
|
| + var e = 1;
|
| + if (this.disabled) {
|
| + e = 0;
|
| + } else if (this.active || this.pressed) {
|
| + e = 4;
|
| + } else if (this.receivedFocusFromKeyboard) {
|
| + e = 3;
|
| + }
|
| + this._setElevation(e);
|
| + },
|
| + _computeKeyboardClass: function(receivedFocusFromKeyboard) {
|
| + this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
|
| + },
|
| + _spaceKeyDownHandler: function(event) {
|
| + Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
|
| + if (this.hasRipple() && this.getRipple().ripples.length < 1) {
|
| + this._ripple.uiDownAction();
|
| + }
|
| + },
|
| + _spaceKeyUpHandler: function(event) {
|
| + Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event);
|
| + if (this.hasRipple()) {
|
| + this._ripple.uiUpAction();
|
| + }
|
| + }
|
| +};
|
| +
|
| +Polymer.PaperButtonBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperButtonBehaviorImpl ];
|
| +
|
| +Polymer({
|
| + is: 'paper-button',
|
| + behaviors: [ Polymer.PaperButtonBehavior ],
|
| + properties: {
|
| + raised: {
|
| + type: Boolean,
|
| + reflectToAttribute: true,
|
| + value: false,
|
| + observer: '_calculateElevation'
|
| + }
|
| + },
|
| + _calculateElevation: function() {
|
| + if (!this.raised) {
|
| + this._setElevation(0);
|
| + } else {
|
| + Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this);
|
| + }
|
| + }
|
| +});
|
| +
|
| +Polymer.PaperItemBehaviorImpl = {
|
| + hostAttributes: {
|
| + role: 'option',
|
| + tabindex: '0'
|
| + }
|
| +};
|
| +
|
| +Polymer.PaperItemBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperItemBehaviorImpl ];
|
| +
|
| +Polymer({
|
| + is: 'paper-item',
|
| + behaviors: [ Polymer.PaperItemBehavior ]
|
| +});
|
| +
|
| +Polymer.IronFitBehavior = {
|
| + properties: {
|
| + sizingTarget: {
|
| + type: Object,
|
| + value: function() {
|
| + return this;
|
| + }
|
| + },
|
| + fitInto: {
|
| + type: Object,
|
| + value: window
|
| + },
|
| + noOverlap: {
|
| + type: Boolean
|
| + },
|
| + positionTarget: {
|
| + type: Element
|
| + },
|
| + horizontalAlign: {
|
| + type: String
|
| + },
|
| + verticalAlign: {
|
| + type: String
|
| + },
|
| + dynamicAlign: {
|
| + type: Boolean
|
| + },
|
| + horizontalOffset: {
|
| + type: Number,
|
| + value: 0,
|
| + notify: true
|
| + },
|
| + verticalOffset: {
|
| + type: Number,
|
| + value: 0,
|
| + notify: true
|
| + },
|
| + autoFitOnAttach: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + _fitInfo: {
|
| + type: Object
|
| + }
|
| + },
|
| + get _fitWidth() {
|
| + var fitWidth;
|
| + if (this.fitInto === window) {
|
| + fitWidth = this.fitInto.innerWidth;
|
| + } else {
|
| + fitWidth = this.fitInto.getBoundingClientRect().width;
|
| + }
|
| + return fitWidth;
|
| + },
|
| + get _fitHeight() {
|
| + var fitHeight;
|
| + if (this.fitInto === window) {
|
| + fitHeight = this.fitInto.innerHeight;
|
| + } else {
|
| + fitHeight = this.fitInto.getBoundingClientRect().height;
|
| + }
|
| + return fitHeight;
|
| + },
|
| + get _fitLeft() {
|
| + var fitLeft;
|
| + if (this.fitInto === window) {
|
| + fitLeft = 0;
|
| + } else {
|
| + fitLeft = this.fitInto.getBoundingClientRect().left;
|
| + }
|
| + return fitLeft;
|
| + },
|
| + get _fitTop() {
|
| + var fitTop;
|
| + if (this.fitInto === window) {
|
| + fitTop = 0;
|
| + } else {
|
| + fitTop = this.fitInto.getBoundingClientRect().top;
|
| + }
|
| + return fitTop;
|
| + },
|
| + get _defaultPositionTarget() {
|
| + var parent = Polymer.dom(this).parentNode;
|
| + if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
| + parent = parent.host;
|
| + }
|
| + return parent;
|
| + },
|
| + get _localeHorizontalAlign() {
|
| + if (this._isRTL) {
|
| + if (this.horizontalAlign === 'right') {
|
| + return 'left';
|
| + }
|
| + if (this.horizontalAlign === 'left') {
|
| + return 'right';
|
| + }
|
| + }
|
| + return this.horizontalAlign;
|
| + },
|
| + attached: function() {
|
| + this._isRTL = window.getComputedStyle(this).direction == 'rtl';
|
| + this.positionTarget = this.positionTarget || this._defaultPositionTarget;
|
| + if (this.autoFitOnAttach) {
|
| + if (window.getComputedStyle(this).display === 'none') {
|
| + setTimeout(function() {
|
| + this.fit();
|
| + }.bind(this));
|
| + } else {
|
| + this.fit();
|
| + }
|
| + }
|
| + },
|
| + fit: function() {
|
| + this.position();
|
| + this.constrain();
|
| + this.center();
|
| + },
|
| + _discoverInfo: function() {
|
| + if (this._fitInfo) {
|
| + return;
|
| + }
|
| + var target = window.getComputedStyle(this);
|
| + var sizer = window.getComputedStyle(this.sizingTarget);
|
| + this._fitInfo = {
|
| + inlineStyle: {
|
| + top: this.style.top || '',
|
| + left: this.style.left || '',
|
| + position: this.style.position || ''
|
| + },
|
| + sizerInlineStyle: {
|
| + maxWidth: this.sizingTarget.style.maxWidth || '',
|
| + maxHeight: this.sizingTarget.style.maxHeight || '',
|
| + boxSizing: this.sizingTarget.style.boxSizing || ''
|
| + },
|
| + positionedBy: {
|
| + vertically: target.top !== 'auto' ? 'top' : target.bottom !== 'auto' ? 'bottom' : null,
|
| + horizontally: target.left !== 'auto' ? 'left' : target.right !== 'auto' ? 'right' : null
|
| + },
|
| + sizedBy: {
|
| + height: sizer.maxHeight !== 'none',
|
| + width: sizer.maxWidth !== 'none',
|
| + minWidth: parseInt(sizer.minWidth, 10) || 0,
|
| + minHeight: parseInt(sizer.minHeight, 10) || 0
|
| + },
|
| + margin: {
|
| + top: parseInt(target.marginTop, 10) || 0,
|
| + right: parseInt(target.marginRight, 10) || 0,
|
| + bottom: parseInt(target.marginBottom, 10) || 0,
|
| + left: parseInt(target.marginLeft, 10) || 0
|
| + }
|
| + };
|
| + if (this.verticalOffset) {
|
| + this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffset;
|
| + this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
|
| + this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || '';
|
| + this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px';
|
| + }
|
| + if (this.horizontalOffset) {
|
| + this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOffset;
|
| + this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || '';
|
| + this._fitInfo.inlineStyle.marginRight = this.style.marginRight || '';
|
| + this.style.marginLeft = this.style.marginRight = this.horizontalOffset + 'px';
|
| + }
|
| + },
|
| + resetFit: function() {
|
| + var info = this._fitInfo || {};
|
| + for (var property in info.sizerInlineStyle) {
|
| + this.sizingTarget.style[property] = info.sizerInlineStyle[property];
|
| + }
|
| + for (var property in info.inlineStyle) {
|
| + this.style[property] = info.inlineStyle[property];
|
| + }
|
| + this._fitInfo = null;
|
| + },
|
| + refit: function() {
|
| + var scrollLeft = this.sizingTarget.scrollLeft;
|
| + var scrollTop = this.sizingTarget.scrollTop;
|
| + this.resetFit();
|
| + this.fit();
|
| + this.sizingTarget.scrollLeft = scrollLeft;
|
| + this.sizingTarget.scrollTop = scrollTop;
|
| + },
|
| + position: function() {
|
| + if (!this.horizontalAlign && !this.verticalAlign) {
|
| + return;
|
| + }
|
| + this._discoverInfo();
|
| + this.style.position = 'fixed';
|
| + this.sizingTarget.style.boxSizing = 'border-box';
|
| + this.style.left = '0px';
|
| + this.style.top = '0px';
|
| + var rect = this.getBoundingClientRect();
|
| + var positionRect = this.__getNormalizedRect(this.positionTarget);
|
| + var fitRect = this.__getNormalizedRect(this.fitInto);
|
| + var margin = this._fitInfo.margin;
|
| + var size = {
|
| + width: rect.width + margin.left + margin.right,
|
| + height: rect.height + margin.top + margin.bottom
|
| + };
|
| + var position = this.__getPosition(this._localeHorizontalAlign, this.verticalAlign, size, positionRect, fitRect);
|
| + var left = position.left + margin.left;
|
| + var top = position.top + margin.top;
|
| + var right = Math.min(fitRect.right - margin.right, left + rect.width);
|
| + var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
|
| + var minWidth = this._fitInfo.sizedBy.minWidth;
|
| + var minHeight = this._fitInfo.sizedBy.minHeight;
|
| + if (left < margin.left) {
|
| + left = margin.left;
|
| + if (right - left < minWidth) {
|
| + left = right - minWidth;
|
| + }
|
| + }
|
| + if (top < margin.top) {
|
| + top = margin.top;
|
| + if (bottom - top < minHeight) {
|
| + top = bottom - minHeight;
|
| + }
|
| + }
|
| + this.sizingTarget.style.maxWidth = right - left + 'px';
|
| + this.sizingTarget.style.maxHeight = bottom - top + 'px';
|
| + this.style.left = left - rect.left + 'px';
|
| + this.style.top = top - rect.top + 'px';
|
| + },
|
| + constrain: function() {
|
| + if (this.horizontalAlign || this.verticalAlign) {
|
| + return;
|
| + }
|
| + this._discoverInfo();
|
| + var info = this._fitInfo;
|
| + if (!info.positionedBy.vertically) {
|
| + this.style.position = 'fixed';
|
| + this.style.top = '0px';
|
| + }
|
| + if (!info.positionedBy.horizontally) {
|
| + this.style.position = 'fixed';
|
| + this.style.left = '0px';
|
| + }
|
| + this.sizingTarget.style.boxSizing = 'border-box';
|
| + var rect = this.getBoundingClientRect();
|
| + if (!info.sizedBy.height) {
|
| + this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
|
| + }
|
| + if (!info.sizedBy.width) {
|
| + this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right', 'Width');
|
| + }
|
| + },
|
| + _sizeDimension: function(rect, positionedBy, start, end, extent) {
|
| + this.__sizeDimension(rect, positionedBy, start, end, extent);
|
| + },
|
| + __sizeDimension: function(rect, positionedBy, start, end, extent) {
|
| + var info = this._fitInfo;
|
| + var fitRect = this.__getNormalizedRect(this.fitInto);
|
| + var max = extent === 'Width' ? fitRect.width : fitRect.height;
|
| + var flip = positionedBy === end;
|
| + var offset = flip ? max - rect[end] : rect[start];
|
| + var margin = info.margin[flip ? start : end];
|
| + var offsetExtent = 'offset' + extent;
|
| + var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent];
|
| + this.sizingTarget.style['max' + extent] = max - margin - offset - sizingOffset + 'px';
|
| + },
|
| + center: function() {
|
| + if (this.horizontalAlign || this.verticalAlign) {
|
| + return;
|
| + }
|
| + this._discoverInfo();
|
| + var positionedBy = this._fitInfo.positionedBy;
|
| + if (positionedBy.vertically && positionedBy.horizontally) {
|
| + return;
|
| + }
|
| + this.style.position = 'fixed';
|
| + if (!positionedBy.vertically) {
|
| + this.style.top = '0px';
|
| + }
|
| + if (!positionedBy.horizontally) {
|
| + this.style.left = '0px';
|
| + }
|
| + var rect = this.getBoundingClientRect();
|
| + var fitRect = this.__getNormalizedRect(this.fitInto);
|
| + if (!positionedBy.vertically) {
|
| + var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2;
|
| + this.style.top = top + 'px';
|
| + }
|
| + if (!positionedBy.horizontally) {
|
| + var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2;
|
| + this.style.left = left + 'px';
|
| + }
|
| + },
|
| + __getNormalizedRect: function(target) {
|
| + if (target === document.documentElement || target === window) {
|
| + return {
|
| + top: 0,
|
| + left: 0,
|
| + width: window.innerWidth,
|
| + height: window.innerHeight,
|
| + right: window.innerWidth,
|
| + bottom: window.innerHeight
|
| + };
|
| + }
|
| + return target.getBoundingClientRect();
|
| + },
|
| + __getCroppedArea: function(position, size, fitRect) {
|
| + var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom - (position.top + size.height));
|
| + var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right - (position.left + size.width));
|
| + return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size.height;
|
| + },
|
| + __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
|
| + var positions = [ {
|
| + verticalAlign: 'top',
|
| + horizontalAlign: 'left',
|
| + top: positionRect.top,
|
| + left: positionRect.left
|
| + }, {
|
| + verticalAlign: 'top',
|
| + horizontalAlign: 'right',
|
| + top: positionRect.top,
|
| + left: positionRect.right - size.width
|
| + }, {
|
| + verticalAlign: 'bottom',
|
| + horizontalAlign: 'left',
|
| + top: positionRect.bottom - size.height,
|
| + left: positionRect.left
|
| + }, {
|
| + verticalAlign: 'bottom',
|
| + horizontalAlign: 'right',
|
| + top: positionRect.bottom - size.height,
|
| + left: positionRect.right - size.width
|
| + } ];
|
| + if (this.noOverlap) {
|
| + for (var i = 0, l = positions.length; i < l; i++) {
|
| + var copy = {};
|
| + for (var key in positions[i]) {
|
| + copy[key] = positions[i][key];
|
| + }
|
| + positions.push(copy);
|
| + }
|
| + positions[0].top = positions[1].top += positionRect.height;
|
| + positions[2].top = positions[3].top -= positionRect.height;
|
| + positions[4].left = positions[6].left += positionRect.width;
|
| + positions[5].left = positions[7].left -= positionRect.width;
|
| + }
|
| + vAlign = vAlign === 'auto' ? null : vAlign;
|
| + hAlign = hAlign === 'auto' ? null : hAlign;
|
| + var position;
|
| + for (var i = 0; i < positions.length; i++) {
|
| + var pos = positions[i];
|
| + if (!this.dynamicAlign && !this.noOverlap && pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
|
| + position = pos;
|
| + break;
|
| + }
|
| + var alignOk = (!vAlign || pos.verticalAlign === vAlign) && (!hAlign || pos.horizontalAlign === hAlign);
|
| + if (!this.dynamicAlign && !alignOk) {
|
| + continue;
|
| + }
|
| + position = position || pos;
|
| + pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
|
| + var diff = pos.croppedArea - position.croppedArea;
|
| + if (diff < 0 || diff === 0 && alignOk) {
|
| + position = pos;
|
| + }
|
| + if (position.croppedArea === 0 && alignOk) {
|
| + break;
|
| + }
|
| + }
|
| + return position;
|
| + }
|
| +};
|
| +
|
| +(function() {
|
| + 'use strict';
|
| + Polymer({
|
| + is: 'iron-overlay-backdrop',
|
| + properties: {
|
| + opened: {
|
| + reflectToAttribute: true,
|
| + type: Boolean,
|
| + value: false,
|
| + observer: '_openedChanged'
|
| + }
|
| + },
|
| + listeners: {
|
| + transitionend: '_onTransitionend'
|
| + },
|
| + created: function() {
|
| + this.__openedRaf = null;
|
| + },
|
| + attached: function() {
|
| + this.opened && this._openedChanged(this.opened);
|
| + },
|
| + prepare: function() {
|
| + if (this.opened && !this.parentNode) {
|
| + Polymer.dom(document.body).appendChild(this);
|
| + }
|
| + },
|
| + open: function() {
|
| + this.opened = true;
|
| + },
|
| + close: function() {
|
| + this.opened = false;
|
| + },
|
| + complete: function() {
|
| + if (!this.opened && this.parentNode === document.body) {
|
| + Polymer.dom(this.parentNode).removeChild(this);
|
| + }
|
| + },
|
| + _onTransitionend: function(event) {
|
| + if (event && event.target === this) {
|
| + this.complete();
|
| + }
|
| + },
|
| + _openedChanged: function(opened) {
|
| + if (opened) {
|
| + this.prepare();
|
| + } else {
|
| + var cs = window.getComputedStyle(this);
|
| + if (cs.transitionDuration === '0s' || cs.opacity == 0) {
|
| + this.complete();
|
| + }
|
| + }
|
| + if (!this.isAttached) {
|
| + return;
|
| + }
|
| + if (this.__openedRaf) {
|
| + window.cancelAnimationFrame(this.__openedRaf);
|
| + this.__openedRaf = null;
|
| + }
|
| + this.scrollTop = this.scrollTop;
|
| + this.__openedRaf = window.requestAnimationFrame(function() {
|
| + this.__openedRaf = null;
|
| + this.toggleClass('opened', this.opened);
|
| + }.bind(this));
|
| + }
|
| + });
|
| +})();
|
| +
|
| +Polymer.IronOverlayManagerClass = function() {
|
| + this._overlays = [];
|
| + this._minimumZ = 101;
|
| + this._backdropElement = null;
|
| + Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this));
|
| + document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
|
| + document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
|
| +};
|
| +
|
| +Polymer.IronOverlayManagerClass.prototype = {
|
| + constructor: Polymer.IronOverlayManagerClass,
|
| + get backdropElement() {
|
| + if (!this._backdropElement) {
|
| + this._backdropElement = document.createElement('iron-overlay-backdrop');
|
| + }
|
| + return this._backdropElement;
|
| + },
|
| + get deepActiveElement() {
|
| + var active = document.activeElement || document.body;
|
| + while (active.root && Polymer.dom(active.root).activeElement) {
|
| + active = Polymer.dom(active.root).activeElement;
|
| + }
|
| + return active;
|
| + },
|
| + _bringOverlayAtIndexToFront: function(i) {
|
| + var overlay = this._overlays[i];
|
| + if (!overlay) {
|
| + return;
|
| + }
|
| + var lastI = this._overlays.length - 1;
|
| + var currentOverlay = this._overlays[lastI];
|
| + if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
|
| + lastI--;
|
| + }
|
| + if (i >= lastI) {
|
| + return;
|
| + }
|
| + var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
|
| + if (this._getZ(overlay) <= minimumZ) {
|
| + this._applyOverlayZ(overlay, minimumZ);
|
| + }
|
| + while (i < lastI) {
|
| + this._overlays[i] = this._overlays[i + 1];
|
| + i++;
|
| + }
|
| + this._overlays[lastI] = overlay;
|
| + },
|
| + addOrRemoveOverlay: function(overlay) {
|
| + if (overlay.opened) {
|
| + this.addOverlay(overlay);
|
| + } else {
|
| + this.removeOverlay(overlay);
|
| + }
|
| + },
|
| + addOverlay: function(overlay) {
|
| + var i = this._overlays.indexOf(overlay);
|
| + if (i >= 0) {
|
| + this._bringOverlayAtIndexToFront(i);
|
| + this.trackBackdrop();
|
| + return;
|
| + }
|
| + var insertionIndex = this._overlays.length;
|
| + var currentOverlay = this._overlays[insertionIndex - 1];
|
| + var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
|
| + var newZ = this._getZ(overlay);
|
| + if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
|
| + this._applyOverlayZ(currentOverlay, minimumZ);
|
| + insertionIndex--;
|
| + var previousOverlay = this._overlays[insertionIndex - 1];
|
| + minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
|
| + }
|
| + if (newZ <= minimumZ) {
|
| + this._applyOverlayZ(overlay, minimumZ);
|
| + }
|
| + this._overlays.splice(insertionIndex, 0, overlay);
|
| + this.trackBackdrop();
|
| + },
|
| + removeOverlay: function(overlay) {
|
| + var i = this._overlays.indexOf(overlay);
|
| + if (i === -1) {
|
| + return;
|
| + }
|
| + this._overlays.splice(i, 1);
|
| + this.trackBackdrop();
|
| + },
|
| + currentOverlay: function() {
|
| + var i = this._overlays.length - 1;
|
| + return this._overlays[i];
|
| + },
|
| + currentOverlayZ: function() {
|
| + return this._getZ(this.currentOverlay());
|
| + },
|
| + ensureMinimumZ: function(minimumZ) {
|
| + this._minimumZ = Math.max(this._minimumZ, minimumZ);
|
| + },
|
| + focusOverlay: function() {
|
| + var current = this.currentOverlay();
|
| + if (current) {
|
| + current._applyFocus();
|
| + }
|
| + },
|
| + trackBackdrop: function() {
|
| + var overlay = this._overlayWithBackdrop();
|
| + if (!overlay && !this._backdropElement) {
|
| + return;
|
| + }
|
| + this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
|
| + this.backdropElement.opened = !!overlay;
|
| + },
|
| + getBackdrops: function() {
|
| + var backdrops = [];
|
| + for (var i = 0; i < this._overlays.length; i++) {
|
| + if (this._overlays[i].withBackdrop) {
|
| + backdrops.push(this._overlays[i]);
|
| + }
|
| + }
|
| + return backdrops;
|
| + },
|
| + backdropZ: function() {
|
| + return this._getZ(this._overlayWithBackdrop()) - 1;
|
| + },
|
| + _overlayWithBackdrop: function() {
|
| + for (var i = 0; i < this._overlays.length; i++) {
|
| + if (this._overlays[i].withBackdrop) {
|
| + return this._overlays[i];
|
| + }
|
| + }
|
| + },
|
| + _getZ: function(overlay) {
|
| + var z = this._minimumZ;
|
| + if (overlay) {
|
| + var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex);
|
| + if (z1 === z1) {
|
| + z = z1;
|
| + }
|
| + }
|
| + return z;
|
| + },
|
| + _setZ: function(element, z) {
|
| + element.style.zIndex = z;
|
| + },
|
| + _applyOverlayZ: function(overlay, aboveZ) {
|
| + this._setZ(overlay, aboveZ + 2);
|
| + },
|
| + _overlayInPath: function(path) {
|
| + path = path || [];
|
| + for (var i = 0; i < path.length; i++) {
|
| + if (path[i]._manager === this) {
|
| + return path[i];
|
| + }
|
| + }
|
| + },
|
| + _onCaptureClick: function(event) {
|
| + var overlay = this.currentOverlay();
|
| + if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
|
| + overlay._onCaptureClick(event);
|
| + }
|
| + },
|
| + _onCaptureFocus: function(event) {
|
| + var overlay = this.currentOverlay();
|
| + if (overlay) {
|
| + overlay._onCaptureFocus(event);
|
| + }
|
| + },
|
| + _onCaptureKeyDown: function(event) {
|
| + var overlay = this.currentOverlay();
|
| + if (overlay) {
|
| + if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
|
| + overlay._onCaptureEsc(event);
|
| + } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
|
| + overlay._onCaptureTab(event);
|
| + }
|
| + }
|
| + },
|
| + _shouldBeBehindOverlay: function(overlay1, overlay2) {
|
| + return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
|
| + }
|
| +};
|
| +
|
| +Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
|
| +
|
| +(function() {
|
| + 'use strict';
|
| + Polymer.IronOverlayBehaviorImpl = {
|
| + properties: {
|
| + opened: {
|
| + observer: '_openedChanged',
|
| + type: Boolean,
|
| + value: false,
|
| + notify: true
|
| + },
|
| + canceled: {
|
| + observer: '_canceledChanged',
|
| + readOnly: true,
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + withBackdrop: {
|
| + observer: '_withBackdropChanged',
|
| + type: Boolean
|
| + },
|
| + noAutoFocus: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + noCancelOnEscKey: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + noCancelOnOutsideClick: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + closingReason: {
|
| + type: Object
|
| + },
|
| + restoreFocusOnClose: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + alwaysOnTop: {
|
| + type: Boolean
|
| + },
|
| + _manager: {
|
| + type: Object,
|
| + value: Polymer.IronOverlayManager
|
| + },
|
| + _focusedChild: {
|
| + type: Object
|
| + }
|
| + },
|
| + listeners: {
|
| + 'iron-resize': '_onIronResize'
|
| + },
|
| + get backdropElement() {
|
| + return this._manager.backdropElement;
|
| + },
|
| + get _focusNode() {
|
| + return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
|
| + },
|
| + get _focusableNodes() {
|
| + var FOCUSABLE_WITH_DISABLED = [ 'a[href]', 'area[href]', 'iframe', '[tabindex]', '[contentEditable=true]' ];
|
| + var FOCUSABLE_WITHOUT_DISABLED = [ 'input', 'select', 'textarea', 'button' ];
|
| + var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') + ':not([tabindex="-1"]),' + FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),') + ':not([disabled]):not([tabindex="-1"])';
|
| + var focusables = Polymer.dom(this).querySelectorAll(selector);
|
| + if (this.tabIndex >= 0) {
|
| + focusables.splice(0, 0, this);
|
| + }
|
| + return focusables.sort(function(a, b) {
|
| + if (a.tabIndex === b.tabIndex) {
|
| + return 0;
|
| + }
|
| + if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
|
| + return 1;
|
| + }
|
| + return -1;
|
| + });
|
| + },
|
| + ready: function() {
|
| + this.__isAnimating = false;
|
| + this.__shouldRemoveTabIndex = false;
|
| + this.__firstFocusableNode = this.__lastFocusableNode = null;
|
| + this.__raf = null;
|
| + this.__restoreFocusNode = null;
|
| + this._ensureSetup();
|
| + },
|
| + attached: function() {
|
| + if (this.opened) {
|
| + this._openedChanged(this.opened);
|
| + }
|
| + this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
|
| + },
|
| + detached: function() {
|
| + Polymer.dom(this).unobserveNodes(this._observer);
|
| + this._observer = null;
|
| + if (this.__raf) {
|
| + window.cancelAnimationFrame(this.__raf);
|
| + this.__raf = null;
|
| + }
|
| + this._manager.removeOverlay(this);
|
| + },
|
| + toggle: function() {
|
| + this._setCanceled(false);
|
| + this.opened = !this.opened;
|
| + },
|
| + open: function() {
|
| + this._setCanceled(false);
|
| + this.opened = true;
|
| + },
|
| + close: function() {
|
| + this._setCanceled(false);
|
| + this.opened = false;
|
| + },
|
| + cancel: function(event) {
|
| + var cancelEvent = this.fire('iron-overlay-canceled', event, {
|
| + cancelable: true
|
| + });
|
| + if (cancelEvent.defaultPrevented) {
|
| + return;
|
| + }
|
| + this._setCanceled(true);
|
| + this.opened = false;
|
| + },
|
| + _ensureSetup: function() {
|
| + if (this._overlaySetup) {
|
| + return;
|
| + }
|
| + this._overlaySetup = true;
|
| + this.style.outline = 'none';
|
| + this.style.display = 'none';
|
| + },
|
| + _openedChanged: function(opened) {
|
| + if (opened) {
|
| + this.removeAttribute('aria-hidden');
|
| + } else {
|
| + this.setAttribute('aria-hidden', 'true');
|
| + }
|
| + if (!this.isAttached) {
|
| + return;
|
| + }
|
| + this.__isAnimating = true;
|
| + this.__onNextAnimationFrame(this.__openedChanged);
|
| + },
|
| + _canceledChanged: function() {
|
| + this.closingReason = this.closingReason || {};
|
| + this.closingReason.canceled = this.canceled;
|
| + },
|
| + _withBackdropChanged: function() {
|
| + if (this.withBackdrop && !this.hasAttribute('tabindex')) {
|
| + this.setAttribute('tabindex', '-1');
|
| + this.__shouldRemoveTabIndex = true;
|
| + } else if (this.__shouldRemoveTabIndex) {
|
| + this.removeAttribute('tabindex');
|
| + this.__shouldRemoveTabIndex = false;
|
| + }
|
| + if (this.opened && this.isAttached) {
|
| + this._manager.trackBackdrop();
|
| + }
|
| + },
|
| + _prepareRenderOpened: function() {
|
| + this.__restoreFocusNode = this._manager.deepActiveElement;
|
| + this._preparePositioning();
|
| + this.refit();
|
| + this._finishPositioning();
|
| + if (this.noAutoFocus && document.activeElement === this._focusNode) {
|
| + this._focusNode.blur();
|
| + this.__restoreFocusNode.focus();
|
| + }
|
| + },
|
| + _renderOpened: function() {
|
| + this._finishRenderOpened();
|
| + },
|
| + _renderClosed: function() {
|
| + this._finishRenderClosed();
|
| + },
|
| + _finishRenderOpened: function() {
|
| + this.notifyResize();
|
| + this.__isAnimating = false;
|
| + var focusableNodes = this._focusableNodes;
|
| + this.__firstFocusableNode = focusableNodes[0];
|
| + this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
|
| + this.fire('iron-overlay-opened');
|
| + },
|
| + _finishRenderClosed: function() {
|
| + this.style.display = 'none';
|
| + this.style.zIndex = '';
|
| + this.notifyResize();
|
| + this.__isAnimating = false;
|
| + this.fire('iron-overlay-closed', this.closingReason);
|
| + },
|
| + _preparePositioning: function() {
|
| + this.style.transition = this.style.webkitTransition = 'none';
|
| + this.style.transform = this.style.webkitTransform = 'none';
|
| + this.style.display = '';
|
| + },
|
| + _finishPositioning: function() {
|
| + this.style.display = 'none';
|
| + this.scrollTop = this.scrollTop;
|
| + this.style.transition = this.style.webkitTransition = '';
|
| + this.style.transform = this.style.webkitTransform = '';
|
| + this.style.display = '';
|
| + this.scrollTop = this.scrollTop;
|
| + },
|
| + _applyFocus: function() {
|
| + if (this.opened) {
|
| + if (!this.noAutoFocus) {
|
| + this._focusNode.focus();
|
| + }
|
| + } else {
|
| + this._focusNode.blur();
|
| + this._focusedChild = null;
|
| + if (this.restoreFocusOnClose && this.__restoreFocusNode) {
|
| + this.__restoreFocusNode.focus();
|
| + }
|
| + this.__restoreFocusNode = null;
|
| + var currentOverlay = this._manager.currentOverlay();
|
| + if (currentOverlay && this !== currentOverlay) {
|
| + currentOverlay._applyFocus();
|
| + }
|
| + }
|
| + },
|
| + _onCaptureClick: function(event) {
|
| + if (!this.noCancelOnOutsideClick) {
|
| + this.cancel(event);
|
| + }
|
| + },
|
| + _onCaptureFocus: function(event) {
|
| + if (!this.withBackdrop) {
|
| + return;
|
| + }
|
| + var path = Polymer.dom(event).path;
|
| + if (path.indexOf(this) === -1) {
|
| + event.stopPropagation();
|
| + this._applyFocus();
|
| + } else {
|
| + this._focusedChild = path[0];
|
| + }
|
| + },
|
| + _onCaptureEsc: function(event) {
|
| + if (!this.noCancelOnEscKey) {
|
| + this.cancel(event);
|
| + }
|
| + },
|
| + _onCaptureTab: function(event) {
|
| + if (!this.withBackdrop) {
|
| + return;
|
| + }
|
| + var shift = event.shiftKey;
|
| + var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
|
| + var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
|
| + var shouldWrap = false;
|
| + if (nodeToCheck === nodeToSet) {
|
| + shouldWrap = true;
|
| + } else {
|
| + var focusedNode = this._manager.deepActiveElement;
|
| + shouldWrap = focusedNode === nodeToCheck || focusedNode === this;
|
| + }
|
| + if (shouldWrap) {
|
| + event.preventDefault();
|
| + this._focusedChild = nodeToSet;
|
| + this._applyFocus();
|
| + }
|
| + },
|
| + _onIronResize: function() {
|
| + if (this.opened && !this.__isAnimating) {
|
| + this.__onNextAnimationFrame(this.refit);
|
| + }
|
| + },
|
| + _onNodesChange: function() {
|
| + if (this.opened && !this.__isAnimating) {
|
| + this.notifyResize();
|
| + }
|
| + },
|
| + __openedChanged: function() {
|
| + if (this.opened) {
|
| + this._prepareRenderOpened();
|
| + this._manager.addOverlay(this);
|
| + this._applyFocus();
|
| + this._renderOpened();
|
| + } else {
|
| + this._manager.removeOverlay(this);
|
| + this._applyFocus();
|
| + this._renderClosed();
|
| + }
|
| + },
|
| + __onNextAnimationFrame: function(callback) {
|
| + if (this.__raf) {
|
| + window.cancelAnimationFrame(this.__raf);
|
| + }
|
| + var self = this;
|
| + this.__raf = window.requestAnimationFrame(function nextAnimationFrame() {
|
| + self.__raf = null;
|
| + callback.call(self);
|
| + });
|
| + }
|
| + };
|
| + Polymer.IronOverlayBehavior = [ Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl ];
|
| +})();
|
| +
|
| +Polymer.NeonAnimatableBehavior = {
|
| + properties: {
|
| + animationConfig: {
|
| + type: Object
|
| + },
|
| + entryAnimation: {
|
| + observer: '_entryAnimationChanged',
|
| + type: String
|
| + },
|
| + exitAnimation: {
|
| + observer: '_exitAnimationChanged',
|
| + type: String
|
| + }
|
| + },
|
| + _entryAnimationChanged: function() {
|
| + this.animationConfig = this.animationConfig || {};
|
| + this.animationConfig['entry'] = [ {
|
| + name: this.entryAnimation,
|
| + node: this
|
| + } ];
|
| + },
|
| + _exitAnimationChanged: function() {
|
| + this.animationConfig = this.animationConfig || {};
|
| + this.animationConfig['exit'] = [ {
|
| + name: this.exitAnimation,
|
| + node: this
|
| + } ];
|
| + },
|
| + _copyProperties: function(config1, config2) {
|
| + for (var property in config2) {
|
| + config1[property] = config2[property];
|
| + }
|
| + },
|
| + _cloneConfig: function(config) {
|
| + var clone = {
|
| + isClone: true
|
| + };
|
| + this._copyProperties(clone, config);
|
| + return clone;
|
| + },
|
| + _getAnimationConfigRecursive: function(type, map, allConfigs) {
|
| + if (!this.animationConfig) {
|
| + return;
|
| + }
|
| + if (this.animationConfig.value && typeof this.animationConfig.value === 'function') {
|
| + this._warn(this._logf('playAnimation', "Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));
|
| + return;
|
| + }
|
| + var thisConfig;
|
| + if (type) {
|
| + thisConfig = this.animationConfig[type];
|
| + } else {
|
| + thisConfig = this.animationConfig;
|
| + }
|
| + if (!Array.isArray(thisConfig)) {
|
| + thisConfig = [ thisConfig ];
|
| + }
|
| + if (thisConfig) {
|
| + for (var config, index = 0; config = thisConfig[index]; index++) {
|
| + if (config.animatable) {
|
| + config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs);
|
| + } else {
|
| + if (config.id) {
|
| + var cachedConfig = map[config.id];
|
| + if (cachedConfig) {
|
| + if (!cachedConfig.isClone) {
|
| + map[config.id] = this._cloneConfig(cachedConfig);
|
| + cachedConfig = map[config.id];
|
| + }
|
| + this._copyProperties(cachedConfig, config);
|
| + } else {
|
| + map[config.id] = config;
|
| + }
|
| + } else {
|
| + allConfigs.push(config);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + },
|
| + getAnimationConfig: function(type) {
|
| + var map = {};
|
| + var allConfigs = [];
|
| + this._getAnimationConfigRecursive(type, map, allConfigs);
|
| + for (var key in map) {
|
| + allConfigs.push(map[key]);
|
| + }
|
| + return allConfigs;
|
| + }
|
| +};
|
| +
|
| +Polymer.NeonAnimationRunnerBehaviorImpl = {
|
| + _configureAnimations: function(configs) {
|
| + var results = [];
|
| + if (configs.length > 0) {
|
| + for (var config, index = 0; config = configs[index]; index++) {
|
| + var neonAnimation = document.createElement(config.name);
|
| + if (neonAnimation.isNeonAnimation) {
|
| + var result = null;
|
| + try {
|
| + result = neonAnimation.configure(config);
|
| + if (typeof result.cancel != 'function') {
|
| + result = document.timeline.play(result);
|
| + }
|
| + } catch (e) {
|
| + result = null;
|
| + console.warn('Couldnt play', '(', config.name, ').', e);
|
| + }
|
| + if (result) {
|
| + results.push({
|
| + neonAnimation: neonAnimation,
|
| + config: config,
|
| + animation: result
|
| + });
|
| + }
|
| + } else {
|
| + console.warn(this.is + ':', config.name, 'not found!');
|
| + }
|
| + }
|
| + }
|
| + return results;
|
| + },
|
| + _shouldComplete: function(activeEntries) {
|
| + var finished = true;
|
| + for (var i = 0; i < activeEntries.length; i++) {
|
| + if (activeEntries[i].animation.playState != 'finished') {
|
| + finished = false;
|
| + break;
|
| + }
|
| + }
|
| + return finished;
|
| + },
|
| + _complete: function(activeEntries) {
|
| + for (var i = 0; i < activeEntries.length; i++) {
|
| + activeEntries[i].neonAnimation.complete(activeEntries[i].config);
|
| + }
|
| + for (var i = 0; i < activeEntries.length; i++) {
|
| + activeEntries[i].animation.cancel();
|
| + }
|
| + },
|
| + playAnimation: function(type, cookie) {
|
| + var configs = this.getAnimationConfig(type);
|
| + if (!configs) {
|
| + return;
|
| + }
|
| + this._active = this._active || {};
|
| + if (this._active[type]) {
|
| + this._complete(this._active[type]);
|
| + delete this._active[type];
|
| + }
|
| + var activeEntries = this._configureAnimations(configs);
|
| + if (activeEntries.length == 0) {
|
| + this.fire('neon-animation-finish', cookie, {
|
| + bubbles: false
|
| + });
|
| + return;
|
| + }
|
| + this._active[type] = activeEntries;
|
| + for (var i = 0; i < activeEntries.length; i++) {
|
| + activeEntries[i].animation.onfinish = function() {
|
| + if (this._shouldComplete(activeEntries)) {
|
| + this._complete(activeEntries);
|
| + delete this._active[type];
|
| + this.fire('neon-animation-finish', cookie, {
|
| + bubbles: false
|
| + });
|
| + }
|
| + }.bind(this);
|
| + }
|
| + },
|
| + cancelAnimation: function() {
|
| + for (var k in this._animations) {
|
| + this._animations[k].cancel();
|
| + }
|
| + this._animations = {};
|
| + }
|
| +};
|
| +
|
| +Polymer.NeonAnimationRunnerBehavior = [ Polymer.NeonAnimatableBehavior, Polymer.NeonAnimationRunnerBehaviorImpl ];
|
| +
|
| +Polymer.NeonAnimationBehavior = {
|
| + properties: {
|
| + animationTiming: {
|
| + type: Object,
|
| + value: function() {
|
| + return {
|
| + duration: 500,
|
| + easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
| + fill: 'both'
|
| + };
|
| + }
|
| + }
|
| + },
|
| + isNeonAnimation: true,
|
| + timingFromConfig: function(config) {
|
| + if (config.timing) {
|
| + for (var property in config.timing) {
|
| + this.animationTiming[property] = config.timing[property];
|
| + }
|
| + }
|
| + return this.animationTiming;
|
| + },
|
| + setPrefixedProperty: function(node, property, value) {
|
| + var map = {
|
| + transform: [ 'webkitTransform' ],
|
| + transformOrigin: [ 'mozTransformOrigin', 'webkitTransformOrigin' ]
|
| + };
|
| + var prefixes = map[property];
|
| + for (var prefix, index = 0; prefix = prefixes[index]; index++) {
|
| + node.style[prefix] = value;
|
| + }
|
| + node.style[property] = value;
|
| + },
|
| + complete: function() {}
|
| +};
|
| +
|
| +Polymer({
|
| + is: 'opaque-animation',
|
| + behaviors: [ Polymer.NeonAnimationBehavior ],
|
| + configure: function(config) {
|
| + var node = config.node;
|
| + this._effect = new KeyframeEffect(node, [ {
|
| + opacity: '1'
|
| + }, {
|
| + opacity: '1'
|
| + } ], this.timingFromConfig(config));
|
| + node.style.opacity = '0';
|
| + return this._effect;
|
| + },
|
| + complete: function(config) {
|
| + config.node.style.opacity = '';
|
| + }
|
| +});
|
| +
|
| +(function() {
|
| + 'use strict';
|
| + var LAST_TOUCH_POSITION = {
|
| + pageX: 0,
|
| + pageY: 0
|
| + };
|
| + var ROOT_TARGET = null;
|
| + var SCROLLABLE_NODES = [];
|
| + Polymer.IronDropdownScrollManager = {
|
| + get currentLockingElement() {
|
| + return this._lockingElements[this._lockingElements.length - 1];
|
| + },
|
| + elementIsScrollLocked: function(element) {
|
| + var currentLockingElement = this.currentLockingElement;
|
| + if (currentLockingElement === undefined) return false;
|
| + var scrollLocked;
|
| + if (this._hasCachedLockedElement(element)) {
|
| + return true;
|
| + }
|
| + if (this._hasCachedUnlockedElement(element)) {
|
| + return false;
|
| + }
|
| + scrollLocked = !!currentLockingElement && currentLockingElement !== element && !this._composedTreeContains(currentLockingElement, element);
|
| + if (scrollLocked) {
|
| + this._lockedElementCache.push(element);
|
| + } else {
|
| + this._unlockedElementCache.push(element);
|
| + }
|
| + return scrollLocked;
|
| + },
|
| + pushScrollLock: function(element) {
|
| + if (this._lockingElements.indexOf(element) >= 0) {
|
| + return;
|
| + }
|
| + if (this._lockingElements.length === 0) {
|
| + this._lockScrollInteractions();
|
| + }
|
| + this._lockingElements.push(element);
|
| + this._lockedElementCache = [];
|
| + this._unlockedElementCache = [];
|
| + },
|
| + removeScrollLock: function(element) {
|
| + var index = this._lockingElements.indexOf(element);
|
| + if (index === -1) {
|
| + return;
|
| + }
|
| + this._lockingElements.splice(index, 1);
|
| + this._lockedElementCache = [];
|
| + this._unlockedElementCache = [];
|
| + if (this._lockingElements.length === 0) {
|
| + this._unlockScrollInteractions();
|
| + }
|
| + },
|
| + _lockingElements: [],
|
| + _lockedElementCache: null,
|
| + _unlockedElementCache: null,
|
| + _hasCachedLockedElement: function(element) {
|
| + return this._lockedElementCache.indexOf(element) > -1;
|
| + },
|
| + _hasCachedUnlockedElement: function(element) {
|
| + return this._unlockedElementCache.indexOf(element) > -1;
|
| + },
|
| + _composedTreeContains: function(element, child) {
|
| + var contentElements;
|
| + var distributedNodes;
|
| + var contentIndex;
|
| + var nodeIndex;
|
| + if (element.contains(child)) {
|
| + return true;
|
| + }
|
| + contentElements = Polymer.dom(element).querySelectorAll('content');
|
| + for (contentIndex = 0; contentIndex < contentElements.length; ++contentIndex) {
|
| + distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistributedNodes();
|
| + for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
|
| + if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| + return false;
|
| + },
|
| + _scrollInteractionHandler: function(event) {
|
| + if (event.cancelable && this._shouldPreventScrolling(event)) {
|
| + event.preventDefault();
|
| + }
|
| + if (event.targetTouches) {
|
| + var touch = event.targetTouches[0];
|
| + LAST_TOUCH_POSITION.pageX = touch.pageX;
|
| + LAST_TOUCH_POSITION.pageY = touch.pageY;
|
| + }
|
| + },
|
| + _lockScrollInteractions: function() {
|
| + this._boundScrollHandler = this._boundScrollHandler || this._scrollInteractionHandler.bind(this);
|
| + document.addEventListener('wheel', this._boundScrollHandler, true);
|
| + document.addEventListener('mousewheel', this._boundScrollHandler, true);
|
| + document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true);
|
| + document.addEventListener('touchstart', this._boundScrollHandler, true);
|
| + document.addEventListener('touchmove', this._boundScrollHandler, true);
|
| + },
|
| + _unlockScrollInteractions: function() {
|
| + document.removeEventListener('wheel', this._boundScrollHandler, true);
|
| + document.removeEventListener('mousewheel', this._boundScrollHandler, true);
|
| + document.removeEventListener('DOMMouseScroll', this._boundScrollHandler, true);
|
| + document.removeEventListener('touchstart', this._boundScrollHandler, true);
|
| + document.removeEventListener('touchmove', this._boundScrollHandler, true);
|
| + },
|
| + _shouldPreventScrolling: function(event) {
|
| + var target = Polymer.dom(event).rootTarget;
|
| + if (event.type !== 'touchmove' && ROOT_TARGET !== target) {
|
| + ROOT_TARGET = target;
|
| + SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path);
|
| + }
|
| + if (!SCROLLABLE_NODES.length) {
|
| + return true;
|
| + }
|
| + if (event.type === 'touchstart') {
|
| + return false;
|
| + }
|
| + var info = this._getScrollInfo(event);
|
| + return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY);
|
| + },
|
| + _getScrollableNodes: function(nodes) {
|
| + var scrollables = [];
|
| + var lockingIndex = nodes.indexOf(this.currentLockingElement);
|
| + for (var i = 0; i <= lockingIndex; i++) {
|
| + var node = nodes[i];
|
| + if (node.nodeType === 11) {
|
| + continue;
|
| + }
|
| + var style = node.style;
|
| + if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
|
| + style = window.getComputedStyle(node);
|
| + }
|
| + if (style.overflow === 'scroll' || style.overflow === 'auto') {
|
| + scrollables.push(node);
|
| + }
|
| + }
|
| + return scrollables;
|
| + },
|
| + _getScrollingNode: function(nodes, deltaX, deltaY) {
|
| + if (!deltaX && !deltaY) {
|
| + return;
|
| + }
|
| + var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
|
| + for (var i = 0; i < nodes.length; i++) {
|
| + var node = nodes[i];
|
| + var canScroll = false;
|
| + if (verticalScroll) {
|
| + canScroll = deltaY < 0 ? node.scrollTop > 0 : node.scrollTop < node.scrollHeight - node.clientHeight;
|
| + } else {
|
| + canScroll = deltaX < 0 ? node.scrollLeft > 0 : node.scrollLeft < node.scrollWidth - node.clientWidth;
|
| + }
|
| + if (canScroll) {
|
| + return node;
|
| + }
|
| + }
|
| + },
|
| + _getScrollInfo: function(event) {
|
| + var info = {
|
| + deltaX: event.deltaX,
|
| + deltaY: event.deltaY
|
| + };
|
| + if ('deltaX' in event) {} else if ('wheelDeltaX' in event) {
|
| + info.deltaX = -event.wheelDeltaX;
|
| + info.deltaY = -event.wheelDeltaY;
|
| + } else if ('axis' in event) {
|
| + info.deltaX = event.axis === 1 ? event.detail : 0;
|
| + info.deltaY = event.axis === 2 ? event.detail : 0;
|
| + } else if (event.targetTouches) {
|
| + var touch = event.targetTouches[0];
|
| + info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX;
|
| + info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY;
|
| + }
|
| + return info;
|
| + }
|
| + };
|
| +})();
|
| +
|
| +(function() {
|
| + 'use strict';
|
| + Polymer({
|
| + is: 'iron-dropdown',
|
| + behaviors: [ Polymer.IronControlState, Polymer.IronA11yKeysBehavior, Polymer.IronOverlayBehavior, Polymer.NeonAnimationRunnerBehavior ],
|
| + properties: {
|
| + horizontalAlign: {
|
| + type: String,
|
| + value: 'left',
|
| + reflectToAttribute: true
|
| + },
|
| + verticalAlign: {
|
| + type: String,
|
| + value: 'top',
|
| + reflectToAttribute: true
|
| + },
|
| + openAnimationConfig: {
|
| + type: Object
|
| + },
|
| + closeAnimationConfig: {
|
| + type: Object
|
| + },
|
| + focusTarget: {
|
| + type: Object
|
| + },
|
| + noAnimations: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + allowOutsideScroll: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + _boundOnCaptureScroll: {
|
| + type: Function,
|
| + value: function() {
|
| + return this._onCaptureScroll.bind(this);
|
| + }
|
| + }
|
| + },
|
| + listeners: {
|
| + 'neon-animation-finish': '_onNeonAnimationFinish'
|
| + },
|
| + observers: [ '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)' ],
|
| + get containedElement() {
|
| + return Polymer.dom(this.$.content).getDistributedNodes()[0];
|
| + },
|
| + get _focusTarget() {
|
| + return this.focusTarget || this.containedElement;
|
| + },
|
| + ready: function() {
|
| + this._scrollTop = 0;
|
| + this._scrollLeft = 0;
|
| + this._refitOnScrollRAF = null;
|
| + },
|
| + attached: function() {
|
| + if (!this.sizingTarget || this.sizingTarget === this) {
|
| + this.sizingTarget = this.containedElement;
|
| + }
|
| + },
|
| + detached: function() {
|
| + this.cancelAnimation();
|
| + document.removeEventListener('scroll', this._boundOnCaptureScroll);
|
| + Polymer.IronDropdownScrollManager.removeScrollLock(this);
|
| + },
|
| + _openedChanged: function() {
|
| + if (this.opened && this.disabled) {
|
| + this.cancel();
|
| + } else {
|
| + this.cancelAnimation();
|
| + this._updateAnimationConfig();
|
| + this._saveScrollPosition();
|
| + if (this.opened) {
|
| + document.addEventListener('scroll', this._boundOnCaptureScroll);
|
| + !this.allowOutsideScroll && Polymer.IronDropdownScrollManager.pushScrollLock(this);
|
| + } else {
|
| + document.removeEventListener('scroll', this._boundOnCaptureScroll);
|
| + Polymer.IronDropdownScrollManager.removeScrollLock(this);
|
| + }
|
| + Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
|
| + }
|
| + },
|
| + _renderOpened: function() {
|
| + if (!this.noAnimations && this.animationConfig.open) {
|
| + this.$.contentWrapper.classList.add('animating');
|
| + this.playAnimation('open');
|
| + } else {
|
| + Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments);
|
| + }
|
| + },
|
| + _renderClosed: function() {
|
| + if (!this.noAnimations && this.animationConfig.close) {
|
| + this.$.contentWrapper.classList.add('animating');
|
| + this.playAnimation('close');
|
| + } else {
|
| + Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments);
|
| + }
|
| + },
|
| + _onNeonAnimationFinish: function() {
|
| + this.$.contentWrapper.classList.remove('animating');
|
| + if (this.opened) {
|
| + this._finishRenderOpened();
|
| + } else {
|
| + this._finishRenderClosed();
|
| + }
|
| + },
|
| + _onCaptureScroll: function() {
|
| + if (!this.allowOutsideScroll) {
|
| + this._restoreScrollPosition();
|
| + } else {
|
| + this._refitOnScrollRAF && window.cancelAnimationFrame(this._refitOnScrollRAF);
|
| + this._refitOnScrollRAF = window.requestAnimationFrame(this.refit.bind(this));
|
| + }
|
| + },
|
| + _saveScrollPosition: function() {
|
| + if (document.scrollingElement) {
|
| + this._scrollTop = document.scrollingElement.scrollTop;
|
| + this._scrollLeft = document.scrollingElement.scrollLeft;
|
| + } else {
|
| + this._scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
|
| + this._scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
|
| + }
|
| + },
|
| + _restoreScrollPosition: function() {
|
| + if (document.scrollingElement) {
|
| + document.scrollingElement.scrollTop = this._scrollTop;
|
| + document.scrollingElement.scrollLeft = this._scrollLeft;
|
| + } else {
|
| + document.documentElement.scrollTop = this._scrollTop;
|
| + document.documentElement.scrollLeft = this._scrollLeft;
|
| + document.body.scrollTop = this._scrollTop;
|
| + document.body.scrollLeft = this._scrollLeft;
|
| + }
|
| + },
|
| + _updateAnimationConfig: function() {
|
| + var animations = (this.openAnimationConfig || []).concat(this.closeAnimationConfig || []);
|
| + for (var i = 0; i < animations.length; i++) {
|
| + animations[i].node = this.containedElement;
|
| + }
|
| + this.animationConfig = {
|
| + open: this.openAnimationConfig,
|
| + close: this.closeAnimationConfig
|
| + };
|
| + },
|
| + _updateOverlayPosition: function() {
|
| + if (this.isAttached) {
|
| + this.notifyResize();
|
| + }
|
| + },
|
| + _applyFocus: function() {
|
| + var focusTarget = this.focusTarget || this.containedElement;
|
| + if (focusTarget && this.opened && !this.noAutoFocus) {
|
| + focusTarget.focus();
|
| + } else {
|
| + Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
|
| + }
|
| + }
|
| + });
|
| +})();
|
| +
|
| +Polymer({
|
| + is: 'fade-in-animation',
|
| + behaviors: [ Polymer.NeonAnimationBehavior ],
|
| + configure: function(config) {
|
| + var node = config.node;
|
| + this._effect = new KeyframeEffect(node, [ {
|
| + opacity: '0'
|
| + }, {
|
| + opacity: '1'
|
| + } ], this.timingFromConfig(config));
|
| + return this._effect;
|
| + }
|
| +});
|
| +
|
| +Polymer({
|
| + is: 'fade-out-animation',
|
| + behaviors: [ Polymer.NeonAnimationBehavior ],
|
| + configure: function(config) {
|
| + var node = config.node;
|
| + this._effect = new KeyframeEffect(node, [ {
|
| + opacity: '1'
|
| + }, {
|
| + opacity: '0'
|
| + } ], this.timingFromConfig(config));
|
| + return this._effect;
|
| + }
|
| +});
|
| +
|
| +Polymer({
|
| + is: 'paper-menu-grow-height-animation',
|
| + behaviors: [ Polymer.NeonAnimationBehavior ],
|
| + configure: function(config) {
|
| + var node = config.node;
|
| + var rect = node.getBoundingClientRect();
|
| + var height = rect.height;
|
| + this._effect = new KeyframeEffect(node, [ {
|
| + height: height / 2 + 'px'
|
| + }, {
|
| + height: height + 'px'
|
| + } ], this.timingFromConfig(config));
|
| + return this._effect;
|
| + }
|
| +});
|
| +
|
| +Polymer({
|
| + is: 'paper-menu-grow-width-animation',
|
| + behaviors: [ Polymer.NeonAnimationBehavior ],
|
| + configure: function(config) {
|
| + var node = config.node;
|
| + var rect = node.getBoundingClientRect();
|
| + var width = rect.width;
|
| + this._effect = new KeyframeEffect(node, [ {
|
| + width: width / 2 + 'px'
|
| + }, {
|
| + width: width + 'px'
|
| + } ], this.timingFromConfig(config));
|
| + return this._effect;
|
| + }
|
| +});
|
| +
|
| +Polymer({
|
| + is: 'paper-menu-shrink-width-animation',
|
| + behaviors: [ Polymer.NeonAnimationBehavior ],
|
| + configure: function(config) {
|
| + var node = config.node;
|
| + var rect = node.getBoundingClientRect();
|
| + var width = rect.width;
|
| + this._effect = new KeyframeEffect(node, [ {
|
| + width: width + 'px'
|
| + }, {
|
| + width: width - width / 20 + 'px'
|
| + } ], this.timingFromConfig(config));
|
| + return this._effect;
|
| + }
|
| +});
|
| +
|
| +Polymer({
|
| + is: 'paper-menu-shrink-height-animation',
|
| + behaviors: [ Polymer.NeonAnimationBehavior ],
|
| + configure: function(config) {
|
| + var node = config.node;
|
| + var rect = node.getBoundingClientRect();
|
| + var height = rect.height;
|
| + var top = rect.top;
|
| + this.setPrefixedProperty(node, 'transformOrigin', '0 0');
|
| + this._effect = new KeyframeEffect(node, [ {
|
| + height: height + 'px',
|
| + transform: 'translateY(0)'
|
| + }, {
|
| + height: height / 2 + 'px',
|
| + transform: 'translateY(-20px)'
|
| + } ], this.timingFromConfig(config));
|
| + return this._effect;
|
| + }
|
| +});
|
| +
|
| +// Copyright 2016 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.
|
| +var SLIDE_CUBIC_BEZIER = 'cubic-bezier(0.3, 0.95, 0.5, 1)';
|
| +
|
| +Polymer({
|
| + is: 'cr-shared-menu',
|
| + behaviors: [ Polymer.IronA11yKeysBehavior ],
|
| + properties: {
|
| + menuOpen: {
|
| + type: Boolean,
|
| + observer: 'menuOpenChanged_',
|
| + value: false,
|
| + notify: true
|
| + },
|
| + itemData: {
|
| + type: Object,
|
| + value: null
|
| + },
|
| + keyEventTarget: {
|
| + type: Object,
|
| + value: function() {
|
| + return this.$.menu;
|
| + }
|
| + },
|
| + openAnimationConfig: {
|
| + type: Object,
|
| + value: function() {
|
| + return [ {
|
| + name: 'fade-in-animation',
|
| + timing: {
|
| + delay: 50,
|
| + duration: 200
|
| + }
|
| + }, {
|
| + name: 'paper-menu-grow-width-animation',
|
| + timing: {
|
| + delay: 50,
|
| + duration: 150,
|
| + easing: SLIDE_CUBIC_BEZIER
|
| + }
|
| + }, {
|
| + name: 'paper-menu-grow-height-animation',
|
| + timing: {
|
| + delay: 100,
|
| + duration: 275,
|
| + easing: SLIDE_CUBIC_BEZIER
|
| + }
|
| + } ];
|
| + }
|
| + },
|
| + closeAnimationConfig: {
|
| + type: Object,
|
| + value: function() {
|
| + return [ {
|
| + name: 'fade-out-animation',
|
| + timing: {
|
| + duration: 150
|
| + }
|
| + } ];
|
| + }
|
| + }
|
| + },
|
| + keyBindings: {
|
| + tab: 'onTabPressed_'
|
| + },
|
| + listeners: {
|
| + 'dropdown.iron-overlay-canceled': 'onOverlayCanceled_'
|
| + },
|
| + lastAnchor_: null,
|
| + firstFocus_: null,
|
| + lastFocus_: null,
|
| + attached: function() {
|
| + window.addEventListener('resize', this.closeMenu.bind(this));
|
| + },
|
| + closeMenu: function() {
|
| + if (this.root.activeElement == null) {
|
| + this.$.dropdown.restoreFocusOnClose = false;
|
| + }
|
| + this.menuOpen = false;
|
| + },
|
| + openMenu: function(anchor, opt_itemData) {
|
| + if (this.lastAnchor_ == anchor && this.menuOpen) return;
|
| + if (this.menuOpen) this.closeMenu();
|
| + this.itemData = opt_itemData || null;
|
| + this.lastAnchor_ = anchor;
|
| + this.$.dropdown.restoreFocusOnClose = true;
|
| + var focusableChildren = Polymer.dom(this).querySelectorAll('[tabindex]:not([disabled]):not([hidden]),' + 'button:not([disabled]):not([hidden])');
|
| + if (focusableChildren.length > 0) {
|
| + this.$.dropdown.focusTarget = focusableChildren[0];
|
| + this.firstFocus_ = focusableChildren[0];
|
| + this.lastFocus_ = focusableChildren[focusableChildren.length - 1];
|
| + }
|
| + this.$.dropdown.positionTarget = anchor;
|
| + this.menuOpen = true;
|
| + },
|
| + toggleMenu: function(anchor, opt_itemData) {
|
| + if (anchor == this.lastAnchor_ && this.menuOpen) this.closeMenu(); else this.openMenu(anchor, opt_itemData);
|
| + },
|
| + onTabPressed_: function(e) {
|
| + if (!this.firstFocus_ || !this.lastFocus_) return;
|
| + var toFocus;
|
| + var keyEvent = e.detail.keyboardEvent;
|
| + if (keyEvent.shiftKey && keyEvent.target == this.firstFocus_) toFocus = this.lastFocus_; else if (!keyEvent.shiftKey && keyEvent.target == this.lastFocus_) toFocus = this.firstFocus_;
|
| + if (!toFocus) return;
|
| + e.preventDefault();
|
| + toFocus.focus();
|
| + },
|
| + menuOpenChanged_: function() {
|
| + if (!this.menuOpen) {
|
| + this.itemData = null;
|
| + this.lastAnchor_ = null;
|
| + }
|
| + },
|
| + onOverlayCanceled_: function(e) {
|
| + if (e.detail.type == 'tap') this.$.dropdown.restoreFocusOnClose = false;
|
| + }
|
| +});
|
| +
|
| +Polymer({
|
| + is: 'paper-icon-button-light',
|
| + "extends": 'button',
|
| + behaviors: [ Polymer.PaperRippleBehavior ],
|
| + listeners: {
|
| + down: '_rippleDown',
|
| + up: '_rippleUp',
|
| + focus: '_rippleDown',
|
| + blur: '_rippleUp'
|
| + },
|
| + _rippleDown: function() {
|
| + this.getRipple().downAction();
|
| + },
|
| + _rippleUp: function() {
|
| + this.getRipple().upAction();
|
| + },
|
| + ensureRipple: function(var_args) {
|
| + var lastRipple = this._ripple;
|
| + Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
|
| + if (this._ripple && this._ripple !== lastRipple) {
|
| + this._ripple.center = true;
|
| + this._ripple.classList.add('circle');
|
| + }
|
| + }
|
| +});
|
| +
|
| +// Copyright 2016 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.
|
| +Polymer({
|
| + is: 'history-synced-device-card',
|
| + properties: {
|
| + device: String,
|
| + lastUpdateTime: String,
|
| + tabs: {
|
| + type: Array,
|
| + value: function() {
|
| + return [];
|
| + },
|
| + observer: 'updateIcons_'
|
| + },
|
| + separatorIndexes: Array,
|
| + opened: Boolean,
|
| + searchTerm: String,
|
| + sessionTag: String
|
| + },
|
| + openTab_: function(e) {
|
| + var tab = e.model.tab;
|
| + var browserService = md_history.BrowserService.getInstance();
|
| + browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.LINK_CLICKED, SyncedTabsHistogram.LIMIT);
|
| + browserService.openForeignSessionTab(this.sessionTag, tab.windowId, tab.sessionId, e);
|
| + e.preventDefault();
|
| + },
|
| + toggleTabCard: function() {
|
| + var histogramValue = this.$.collapse.opened ? SyncedTabsHistogram.COLLAPSE_SESSION : SyncedTabsHistogram.EXPAND_SESSION;
|
| + md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, histogramValue, SyncedTabsHistogram.LIMIT);
|
| + this.$.collapse.toggle();
|
| + this.$['dropdown-indicator'].icon = this.$.collapse.opened ? 'cr:expand-less' : 'cr:expand-more';
|
| + },
|
| + updateIcons_: function() {
|
| + this.async(function() {
|
| + var icons = Polymer.dom(this.root).querySelectorAll('.website-icon');
|
| + for (var i = 0; i < this.tabs.length; i++) {
|
| + icons[i].style.backgroundImage = cr.icon.getFavicon(this.tabs[i].url);
|
| + }
|
| + });
|
| + },
|
| + isWindowSeparatorIndex_: function(index, separatorIndexes) {
|
| + return this.separatorIndexes.indexOf(index) != -1;
|
| + },
|
| + getCollapseIcon_: function(opened) {
|
| + return opened ? 'cr:expand-less' : 'cr:expand-more';
|
| + },
|
| + getCollapseTitle_: function(opened) {
|
| + return opened ? loadTimeData.getString('collapseSessionButton') : loadTimeData.getString('expandSessionButton');
|
| + },
|
| + onMenuButtonTap_: function(e) {
|
| + this.fire('toggle-menu', {
|
| + target: Polymer.dom(e).localTarget,
|
| + tag: this.sessionTag
|
| + });
|
| + e.stopPropagation();
|
| + },
|
| + onLinkRightClick_: function() {
|
| + md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.LINK_RIGHT_CLICKED, SyncedTabsHistogram.LIMIT);
|
| + }
|
| +});
|
| +
|
| +// Copyright 2016 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.
|
| +var ForeignDeviceInternal;
|
| +
|
| +Polymer({
|
| + is: 'history-synced-device-manager',
|
| + properties: {
|
| + sessionList: {
|
| + type: Array,
|
| + observer: 'updateSyncedDevices'
|
| + },
|
| + searchTerm: {
|
| + type: String,
|
| + observer: 'searchTermChanged'
|
| + },
|
| + syncedDevices_: {
|
| + type: Array,
|
| + value: function() {
|
| + return [];
|
| + }
|
| + },
|
| + signInState: {
|
| + type: Boolean,
|
| + observer: 'signInStateChanged_'
|
| + },
|
| + guestSession_: {
|
| + type: Boolean,
|
| + value: loadTimeData.getBoolean('isGuestSession')
|
| + },
|
| + fetchingSyncedTabs_: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + hasSeenForeignData_: Boolean
|
| + },
|
| + listeners: {
|
| + 'toggle-menu': 'onToggleMenu_',
|
| + scroll: 'onListScroll_'
|
| + },
|
| + attached: function() {
|
| + chrome.send('otherDevicesInitialized');
|
| + md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.INITIALIZED, SyncedTabsHistogram.LIMIT);
|
| + },
|
| + getContentScrollTarget: function() {
|
| + return this;
|
| + },
|
| + createInternalDevice_: function(session) {
|
| + var tabs = [];
|
| + var separatorIndexes = [];
|
| + for (var i = 0; i < session.windows.length; i++) {
|
| + var windowId = session.windows[i].sessionId;
|
| + var newTabs = session.windows[i].tabs;
|
| + if (newTabs.length == 0) continue;
|
| + newTabs.forEach(function(tab) {
|
| + tab.windowId = windowId;
|
| + });
|
| + var windowAdded = false;
|
| + if (!this.searchTerm) {
|
| + tabs = tabs.concat(newTabs);
|
| + windowAdded = true;
|
| + } else {
|
| + var searchText = this.searchTerm.toLowerCase();
|
| + for (var j = 0; j < newTabs.length; j++) {
|
| + var tab = newTabs[j];
|
| + if (tab.title.toLowerCase().indexOf(searchText) != -1) {
|
| + tabs.push(tab);
|
| + windowAdded = true;
|
| + }
|
| + }
|
| + }
|
| + if (windowAdded && i != session.windows.length - 1) separatorIndexes.push(tabs.length - 1);
|
| + }
|
| + return {
|
| + device: session.name,
|
| + lastUpdateTime: '– ' + session.modifiedTime,
|
| + opened: true,
|
| + separatorIndexes: separatorIndexes,
|
| + timestamp: session.timestamp,
|
| + tabs: tabs,
|
| + tag: session.tag
|
| + };
|
| + },
|
| + onSignInTap_: function() {
|
| + chrome.send('startSignInFlow');
|
| + },
|
| + onListScroll_: function() {
|
| + var menu = this.$.menu.getIfExists();
|
| + if (menu) menu.closeMenu();
|
| + },
|
| + onToggleMenu_: function(e) {
|
| + var menu = this.$.menu.get();
|
| + menu.toggleMenu(e.detail.target, e.detail.tag);
|
| + if (menu.menuOpen) {
|
| + md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.SHOW_SESSION_MENU, SyncedTabsHistogram.LIMIT);
|
| + }
|
| + },
|
| + onOpenAllTap_: function() {
|
| + var menu = assert(this.$.menu.getIfExists());
|
| + var browserService = md_history.BrowserService.getInstance();
|
| + browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.OPEN_ALL, SyncedTabsHistogram.LIMIT);
|
| + browserService.openForeignSessionAllTabs(menu.itemData);
|
| + menu.closeMenu();
|
| + },
|
| + onDeleteSessionTap_: function() {
|
| + var menu = assert(this.$.menu.getIfExists());
|
| + var browserService = md_history.BrowserService.getInstance();
|
| + browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.HIDE_FOR_NOW, SyncedTabsHistogram.LIMIT);
|
| + browserService.deleteForeignSession(menu.itemData);
|
| + menu.closeMenu();
|
| + },
|
| + clearDisplayedSyncedDevices_: function() {
|
| + this.syncedDevices_ = [];
|
| + },
|
| + showNoSyncedMessage: function(signInState, syncedDevicesLength, guestSession) {
|
| + if (guestSession) return true;
|
| + return signInState && syncedDevicesLength == 0;
|
| + },
|
| + showSignInGuide: function(signInState, guestSession) {
|
| + var show = !signInState && !guestSession;
|
| + if (show) {
|
| + md_history.BrowserService.getInstance().recordAction('Signin_Impression_FromRecentTabs');
|
| + }
|
| + return show;
|
| + },
|
| + noSyncedTabsMessage: function(fetchingSyncedTabs) {
|
| + return loadTimeData.getString(fetchingSyncedTabs ? 'loading' : 'noSyncedResults');
|
| + },
|
| + updateSyncedDevices: function(sessionList) {
|
| + this.fetchingSyncedTabs_ = false;
|
| + if (!sessionList) return;
|
| + if (sessionList.length > 0 && !this.hasSeenForeignData_) {
|
| + this.hasSeenForeignData_ = true;
|
| + md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.HAS_FOREIGN_DATA, SyncedTabsHistogram.LIMIT);
|
| + }
|
| + var updateCount = Math.min(sessionList.length, this.syncedDevices_.length);
|
| + for (var i = 0; i < updateCount; i++) {
|
| + var oldDevice = this.syncedDevices_[i];
|
| + if (oldDevice.tag != sessionList[i].tag || oldDevice.timestamp != sessionList[i].timestamp) {
|
| + this.splice('syncedDevices_', i, 1, this.createInternalDevice_(sessionList[i]));
|
| + }
|
| + }
|
| + if (sessionList.length >= this.syncedDevices_.length) {
|
| + for (var i = updateCount; i < sessionList.length; i++) {
|
| + this.push('syncedDevices_', this.createInternalDevice_(sessionList[i]));
|
| + }
|
| + } else {
|
| + this.splice('syncedDevices_', updateCount, this.syncedDevices_.length - updateCount);
|
| + }
|
| + },
|
| + tabSyncDisabled: function() {
|
| + this.fetchingSyncedTabs_ = false;
|
| + this.clearDisplayedSyncedDevices_();
|
| + },
|
| + signInStateChanged_: function() {
|
| + this.fire('history-view-changed');
|
| + if (!this.signInState) {
|
| + this.clearDisplayedSyncedDevices_();
|
| + return;
|
| + }
|
| + this.fetchingSyncedTabs_ = true;
|
| + },
|
| + searchTermChanged: function(searchTerm) {
|
| + this.clearDisplayedSyncedDevices_();
|
| + this.updateSyncedDevices(this.sessionList);
|
| + }
|
| +});
|
| +
|
| +// Copyright 2016 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.
|
| +Polymer({
|
| + is: 'cr-dialog',
|
| + "extends": 'dialog',
|
| + created: function() {
|
| + window.addEventListener('popstate', function() {
|
| + if (this.open) this.cancel();
|
| + }.bind(this));
|
| + },
|
| + cancel: function() {
|
| + this.fire('cancel');
|
| + HTMLDialogElement.prototype.close.call(this, '');
|
| + },
|
| + close: function(opt_returnValue) {
|
| + HTMLDialogElement.prototype.close.call(this, 'success');
|
| + },
|
| + getCloseButton: function() {
|
| + return this.$.close;
|
| + }
|
| +});
|
| +
|
| +Polymer({
|
| + is: 'app-drawer',
|
| + properties: {
|
| + opened: {
|
| + type: Boolean,
|
| + value: false,
|
| + notify: true,
|
| + reflectToAttribute: true
|
| + },
|
| + persistent: {
|
| + type: Boolean,
|
| + value: false,
|
| + reflectToAttribute: true
|
| + },
|
| + align: {
|
| + type: String,
|
| + value: 'left'
|
| + },
|
| + position: {
|
| + type: String,
|
| + readOnly: true,
|
| + value: 'left',
|
| + reflectToAttribute: true
|
| + },
|
| + swipeOpen: {
|
| + type: Boolean,
|
| + value: false,
|
| + reflectToAttribute: true
|
| + },
|
| + noFocusTrap: {
|
| + type: Boolean,
|
| + value: false
|
| + }
|
| + },
|
| + observers: [ 'resetLayout(position)', '_resetPosition(align, isAttached)' ],
|
| + _translateOffset: 0,
|
| + _trackDetails: null,
|
| + _drawerState: 0,
|
| + _boundEscKeydownHandler: null,
|
| + _firstTabStop: null,
|
| + _lastTabStop: null,
|
| + ready: function() {
|
| + this.setScrollDirection('y');
|
| + this._setTransitionDuration('0s');
|
| + },
|
| + attached: function() {
|
| + Polymer.RenderStatus.afterNextRender(this, function() {
|
| + this._setTransitionDuration('');
|
| + this._boundEscKeydownHandler = this._escKeydownHandler.bind(this);
|
| + this._resetDrawerState();
|
| + this.listen(this, 'track', '_track');
|
| + this.addEventListener('transitionend', this._transitionend.bind(this));
|
| + this.addEventListener('keydown', this._tabKeydownHandler.bind(this));
|
| + });
|
| + },
|
| + detached: function() {
|
| + document.removeEventListener('keydown', this._boundEscKeydownHandler);
|
| + },
|
| + open: function() {
|
| + this.opened = true;
|
| + },
|
| + close: function() {
|
| + this.opened = false;
|
| + },
|
| + toggle: function() {
|
| + this.opened = !this.opened;
|
| + },
|
| + getWidth: function() {
|
| + return this.$.contentContainer.offsetWidth;
|
| + },
|
| + resetLayout: function() {
|
| + this.debounce('_resetLayout', function() {
|
| + this.fire('app-drawer-reset-layout');
|
| + }, 1);
|
| + },
|
| + _isRTL: function() {
|
| + return window.getComputedStyle(this).direction === 'rtl';
|
| + },
|
| + _resetPosition: function() {
|
| + switch (this.align) {
|
| + case 'start':
|
| + this._setPosition(this._isRTL() ? 'right' : 'left');
|
| + return;
|
| +
|
| + case 'end':
|
| + this._setPosition(this._isRTL() ? 'left' : 'right');
|
| + return;
|
| + }
|
| + this._setPosition(this.align);
|
| + },
|
| + _escKeydownHandler: function(event) {
|
| + var ESC_KEYCODE = 27;
|
| + if (event.keyCode === ESC_KEYCODE) {
|
| + event.preventDefault();
|
| + this.close();
|
| + }
|
| + },
|
| + _track: function(event) {
|
| + if (this.persistent) {
|
| + return;
|
| + }
|
| + event.preventDefault();
|
| + switch (event.detail.state) {
|
| + case 'start':
|
| + this._trackStart(event);
|
| + break;
|
| +
|
| + case 'track':
|
| + this._trackMove(event);
|
| + break;
|
| +
|
| + case 'end':
|
| + this._trackEnd(event);
|
| + break;
|
| + }
|
| + },
|
| + _trackStart: function(event) {
|
| + this._drawerState = this._DRAWER_STATE.TRACKING;
|
| + this._setTransitionDuration('0s');
|
| + this.style.visibility = 'visible';
|
| + var rect = this.$.contentContainer.getBoundingClientRect();
|
| + if (this.position === 'left') {
|
| + this._translateOffset = rect.left;
|
| + } else {
|
| + this._translateOffset = rect.right - window.innerWidth;
|
| + }
|
| + this._trackDetails = [];
|
| + },
|
| + _trackMove: function(event) {
|
| + this._translateDrawer(event.detail.dx + this._translateOffset);
|
| + this._trackDetails.push({
|
| + dx: event.detail.dx,
|
| + timeStamp: Date.now()
|
| + });
|
| + },
|
| + _trackEnd: function(event) {
|
| + var x = event.detail.dx + this._translateOffset;
|
| + var drawerWidth = this.getWidth();
|
| + var isPositionLeft = this.position === 'left';
|
| + var isInEndState = isPositionLeft ? x >= 0 || x <= -drawerWidth : x <= 0 || x >= drawerWidth;
|
| + if (!isInEndState) {
|
| + var trackDetails = this._trackDetails;
|
| + this._trackDetails = null;
|
| + this._flingDrawer(event, trackDetails);
|
| + if (this._drawerState === this._DRAWER_STATE.FLINGING) {
|
| + return;
|
| + }
|
| + }
|
| + var halfWidth = drawerWidth / 2;
|
| + if (event.detail.dx < -halfWidth) {
|
| + this.opened = this.position === 'right';
|
| + } else if (event.detail.dx > halfWidth) {
|
| + this.opened = this.position === 'left';
|
| + }
|
| + if (isInEndState) {
|
| + this._resetDrawerState();
|
| + }
|
| + this._setTransitionDuration('');
|
| + this._resetDrawerTranslate();
|
| + this.style.visibility = '';
|
| + },
|
| + _calculateVelocity: function(event, trackDetails) {
|
| + var now = Date.now();
|
| + var timeLowerBound = now - 100;
|
| + var trackDetail;
|
| + var min = 0;
|
| + var max = trackDetails.length - 1;
|
| + while (min <= max) {
|
| + var mid = min + max >> 1;
|
| + var d = trackDetails[mid];
|
| + if (d.timeStamp >= timeLowerBound) {
|
| + trackDetail = d;
|
| + max = mid - 1;
|
| + } else {
|
| + min = mid + 1;
|
| + }
|
| + }
|
| + if (trackDetail) {
|
| + var dx = event.detail.dx - trackDetail.dx;
|
| + var dt = now - trackDetail.timeStamp || 1;
|
| + return dx / dt;
|
| + }
|
| + return 0;
|
| + },
|
| + _flingDrawer: function(event, trackDetails) {
|
| + var velocity = this._calculateVelocity(event, trackDetails);
|
| + if (Math.abs(velocity) < this._MIN_FLING_THRESHOLD) {
|
| + return;
|
| + }
|
| + this._drawerState = this._DRAWER_STATE.FLINGING;
|
| + var x = event.detail.dx + this._translateOffset;
|
| + var drawerWidth = this.getWidth();
|
| + var isPositionLeft = this.position === 'left';
|
| + var isVelocityPositive = velocity > 0;
|
| + var isClosingLeft = !isVelocityPositive && isPositionLeft;
|
| + var isClosingRight = isVelocityPositive && !isPositionLeft;
|
| + var dx;
|
| + if (isClosingLeft) {
|
| + dx = -(x + drawerWidth);
|
| + } else if (isClosingRight) {
|
| + dx = drawerWidth - x;
|
| + } else {
|
| + dx = -x;
|
| + }
|
| + if (isVelocityPositive) {
|
| + velocity = Math.max(velocity, this._MIN_TRANSITION_VELOCITY);
|
| + this.opened = this.position === 'left';
|
| + } else {
|
| + velocity = Math.min(velocity, -this._MIN_TRANSITION_VELOCITY);
|
| + this.opened = this.position === 'right';
|
| + }
|
| + this._setTransitionDuration(this._FLING_INITIAL_SLOPE * dx / velocity + 'ms');
|
| + this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);
|
| + this._resetDrawerTranslate();
|
| + },
|
| + _transitionend: function(event) {
|
| + var target = Polymer.dom(event).rootTarget;
|
| + if (target === this.$.contentContainer || target === this.$.scrim) {
|
| + if (this._drawerState === this._DRAWER_STATE.FLINGING) {
|
| + this._setTransitionDuration('');
|
| + this._setTransitionTimingFunction('');
|
| + this.style.visibility = '';
|
| + }
|
| + this._resetDrawerState();
|
| + }
|
| + },
|
| + _setTransitionDuration: function(duration) {
|
| + this.$.contentContainer.style.transitionDuration = duration;
|
| + this.$.scrim.style.transitionDuration = duration;
|
| + },
|
| + _setTransitionTimingFunction: function(timingFunction) {
|
| + this.$.contentContainer.style.transitionTimingFunction = timingFunction;
|
| + this.$.scrim.style.transitionTimingFunction = timingFunction;
|
| + },
|
| + _translateDrawer: function(x) {
|
| + var drawerWidth = this.getWidth();
|
| + if (this.position === 'left') {
|
| + x = Math.max(-drawerWidth, Math.min(x, 0));
|
| + this.$.scrim.style.opacity = 1 + x / drawerWidth;
|
| + } else {
|
| + x = Math.max(0, Math.min(x, drawerWidth));
|
| + this.$.scrim.style.opacity = 1 - x / drawerWidth;
|
| + }
|
| + this.translate3d(x + 'px', '0', '0', this.$.contentContainer);
|
| + },
|
| + _resetDrawerTranslate: function() {
|
| + this.$.scrim.style.opacity = '';
|
| + this.transform('', this.$.contentContainer);
|
| + },
|
| + _resetDrawerState: function() {
|
| + var oldState = this._drawerState;
|
| + if (this.opened) {
|
| + this._drawerState = this.persistent ? this._DRAWER_STATE.OPENED_PERSISTENT : this._DRAWER_STATE.OPENED;
|
| + } else {
|
| + this._drawerState = this._DRAWER_STATE.CLOSED;
|
| + }
|
| + if (oldState !== this._drawerState) {
|
| + if (this._drawerState === this._DRAWER_STATE.OPENED) {
|
| + this._setKeyboardFocusTrap();
|
| + document.addEventListener('keydown', this._boundEscKeydownHandler);
|
| + document.body.style.overflow = 'hidden';
|
| + } else {
|
| + document.removeEventListener('keydown', this._boundEscKeydownHandler);
|
| + document.body.style.overflow = '';
|
| + }
|
| + if (oldState !== this._DRAWER_STATE.INIT) {
|
| + this.fire('app-drawer-transitioned');
|
| + }
|
| + }
|
| + },
|
| + _setKeyboardFocusTrap: function() {
|
| + if (this.noFocusTrap) {
|
| + return;
|
| + }
|
| + var focusableElementsSelector = [ 'a[href]:not([tabindex="-1"])', 'area[href]:not([tabindex="-1"])', 'input:not([disabled]):not([tabindex="-1"])', 'select:not([disabled]):not([tabindex="-1"])', 'textarea:not([disabled]):not([tabindex="-1"])', 'button:not([disabled]):not([tabindex="-1"])', 'iframe:not([tabindex="-1"])', '[tabindex]:not([tabindex="-1"])', '[contentEditable=true]:not([tabindex="-1"])' ].join(',');
|
| + var focusableElements = Polymer.dom(this).querySelectorAll(focusableElementsSelector);
|
| + if (focusableElements.length > 0) {
|
| + this._firstTabStop = focusableElements[0];
|
| + this._lastTabStop = focusableElements[focusableElements.length - 1];
|
| + } else {
|
| + this._firstTabStop = null;
|
| + this._lastTabStop = null;
|
| + }
|
| + var tabindex = this.getAttribute('tabindex');
|
| + if (tabindex && parseInt(tabindex, 10) > -1) {
|
| + this.focus();
|
| + } else if (this._firstTabStop) {
|
| + this._firstTabStop.focus();
|
| + }
|
| + },
|
| + _tabKeydownHandler: function(event) {
|
| + if (this.noFocusTrap) {
|
| + return;
|
| + }
|
| + var TAB_KEYCODE = 9;
|
| + if (this._drawerState === this._DRAWER_STATE.OPENED && event.keyCode === TAB_KEYCODE) {
|
| + if (event.shiftKey) {
|
| + if (this._firstTabStop && Polymer.dom(event).localTarget === this._firstTabStop) {
|
| + event.preventDefault();
|
| + this._lastTabStop.focus();
|
| + }
|
| + } else {
|
| + if (this._lastTabStop && Polymer.dom(event).localTarget === this._lastTabStop) {
|
| + event.preventDefault();
|
| + this._firstTabStop.focus();
|
| + }
|
| + }
|
| + }
|
| + },
|
| + _MIN_FLING_THRESHOLD: .2,
|
| + _MIN_TRANSITION_VELOCITY: 1.2,
|
| + _FLING_TIMING_FUNCTION: 'cubic-bezier(0.667, 1, 0.667, 1)',
|
| + _FLING_INITIAL_SLOPE: 1.5,
|
| + _DRAWER_STATE: {
|
| + INIT: 0,
|
| + OPENED: 1,
|
| + OPENED_PERSISTENT: 2,
|
| + CLOSED: 3,
|
| + TRACKING: 4,
|
| + FLINGING: 5
|
| + }
|
| +});
|
| +
|
| +Polymer.IronFormElementBehavior = {
|
| + properties: {
|
| + name: {
|
| + type: String
|
| + },
|
| + value: {
|
| + notify: true,
|
| + type: String
|
| + },
|
| + required: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + _parentForm: {
|
| + type: Object
|
| + }
|
| + },
|
| + attached: function() {
|
| + this.fire('iron-form-element-register');
|
| + },
|
| + detached: function() {
|
| + if (this._parentForm) {
|
| + this._parentForm.fire('iron-form-element-unregister', {
|
| + target: this
|
| + });
|
| + }
|
| + }
|
| +};
|
| +
|
| +Polymer.IronCheckedElementBehaviorImpl = {
|
| + properties: {
|
| + checked: {
|
| + type: Boolean,
|
| + value: false,
|
| + reflectToAttribute: true,
|
| + notify: true,
|
| + observer: '_checkedChanged'
|
| + },
|
| + toggles: {
|
| + type: Boolean,
|
| + value: true,
|
| + reflectToAttribute: true
|
| + },
|
| + value: {
|
| + type: String,
|
| + value: 'on',
|
| + observer: '_valueChanged'
|
| + }
|
| + },
|
| + observers: [ '_requiredChanged(required)' ],
|
| + created: function() {
|
| + this._hasIronCheckedElementBehavior = true;
|
| + },
|
| + _getValidity: function(_value) {
|
| + return this.disabled || !this.required || this.checked;
|
| + },
|
| + _requiredChanged: function() {
|
| + if (this.required) {
|
| + this.setAttribute('aria-required', 'true');
|
| + } else {
|
| + this.removeAttribute('aria-required');
|
| + }
|
| + },
|
| + _checkedChanged: function() {
|
| + this.active = this.checked;
|
| + this.fire('iron-change');
|
| + },
|
| + _valueChanged: function() {
|
| + if (this.value === undefined || this.value === null) {
|
| + this.value = 'on';
|
| + }
|
| + }
|
| +};
|
| +
|
| +Polymer.IronCheckedElementBehavior = [ Polymer.IronFormElementBehavior, Polymer.IronValidatableBehavior, Polymer.IronCheckedElementBehaviorImpl ];
|
| +
|
| +Polymer.PaperCheckedElementBehaviorImpl = {
|
| + _checkedChanged: function() {
|
| + Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this);
|
| + if (this.hasRipple()) {
|
| + if (this.checked) {
|
| + this._ripple.setAttribute('checked', '');
|
| + } else {
|
| + this._ripple.removeAttribute('checked');
|
| + }
|
| + }
|
| + },
|
| + _buttonStateChanged: function() {
|
| + Polymer.PaperRippleBehavior._buttonStateChanged.call(this);
|
| + if (this.disabled) {
|
| + return;
|
| + }
|
| + if (this.isAttached) {
|
| + this.checked = this.active;
|
| + }
|
| + }
|
| +};
|
| +
|
| +Polymer.PaperCheckedElementBehavior = [ Polymer.PaperInkyFocusBehavior, Polymer.IronCheckedElementBehavior, Polymer.PaperCheckedElementBehaviorImpl ];
|
| +
|
| +Polymer({
|
| + is: 'paper-checkbox',
|
| + behaviors: [ Polymer.PaperCheckedElementBehavior ],
|
| + hostAttributes: {
|
| + role: 'checkbox',
|
| + 'aria-checked': false,
|
| + tabindex: 0
|
| + },
|
| + properties: {
|
| + ariaActiveAttribute: {
|
| + type: String,
|
| + value: 'aria-checked'
|
| + }
|
| + },
|
| + attached: function() {
|
| + var inkSize = this.getComputedStyleValue('--calculated-paper-checkbox-ink-size');
|
| + if (inkSize === '-1px') {
|
| + var checkboxSize = parseFloat(this.getComputedStyleValue('--calculated-paper-checkbox-size'));
|
| + var defaultInkSize = Math.floor(8 / 3 * checkboxSize);
|
| + if (defaultInkSize % 2 !== checkboxSize % 2) {
|
| + defaultInkSize++;
|
| + }
|
| + this.customStyle['--paper-checkbox-ink-size'] = defaultInkSize + 'px';
|
| + this.updateStyles();
|
| + }
|
| + },
|
| + _computeCheckboxClass: function(checked, invalid) {
|
| + var className = '';
|
| + if (checked) {
|
| + className += 'checked ';
|
| + }
|
| + if (invalid) {
|
| + className += 'invalid';
|
| + }
|
| + return className;
|
| + },
|
| + _computeCheckmarkClass: function(checked) {
|
| + return checked ? '' : 'hidden';
|
| + },
|
| + _createRipple: function() {
|
| + this._rippleContainer = this.$.checkboxContainer;
|
| + return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this);
|
| + }
|
| +});
|
| +
|
| +Polymer({
|
| + is: 'paper-tab',
|
| + behaviors: [ Polymer.IronControlState, Polymer.IronButtonState, Polymer.PaperRippleBehavior ],
|
| + properties: {
|
| + link: {
|
| + type: Boolean,
|
| + value: false,
|
| + reflectToAttribute: true
|
| + }
|
| + },
|
| + hostAttributes: {
|
| + role: 'tab'
|
| + },
|
| + listeners: {
|
| + down: '_updateNoink',
|
| + tap: '_onTap'
|
| + },
|
| + attached: function() {
|
| + this._updateNoink();
|
| + },
|
| + get _parentNoink() {
|
| + var parent = Polymer.dom(this).parentNode;
|
| + return !!parent && !!parent.noink;
|
| + },
|
| + _updateNoink: function() {
|
| + this.noink = !!this.noink || !!this._parentNoink;
|
| + },
|
| + _onTap: function(event) {
|
| + if (this.link) {
|
| + var anchor = this.queryEffectiveChildren('a');
|
| + if (!anchor) {
|
| + return;
|
| + }
|
| + if (event.target === anchor) {
|
| + return;
|
| + }
|
| + anchor.click();
|
| + }
|
| + }
|
| +});
|
| +
|
| +Polymer.IronMenuBehaviorImpl = {
|
| + properties: {
|
| + focusedItem: {
|
| + observer: '_focusedItemChanged',
|
| + readOnly: true,
|
| + type: Object
|
| + },
|
| + attrForItemTitle: {
|
| + type: String
|
| + }
|
| + },
|
| + hostAttributes: {
|
| + role: 'menu',
|
| + tabindex: '0'
|
| + },
|
| + observers: [ '_updateMultiselectable(multi)' ],
|
| + listeners: {
|
| + focus: '_onFocus',
|
| + keydown: '_onKeydown',
|
| + 'iron-items-changed': '_onIronItemsChanged'
|
| + },
|
| + keyBindings: {
|
| + up: '_onUpKey',
|
| + down: '_onDownKey',
|
| + esc: '_onEscKey',
|
| + 'shift+tab:keydown': '_onShiftTabDown'
|
| + },
|
| + attached: function() {
|
| + this._resetTabindices();
|
| + },
|
| + select: function(value) {
|
| + if (this._defaultFocusAsync) {
|
| + this.cancelAsync(this._defaultFocusAsync);
|
| + this._defaultFocusAsync = null;
|
| + }
|
| + var item = this._valueToItem(value);
|
| + if (item && item.hasAttribute('disabled')) return;
|
| + this._setFocusedItem(item);
|
| + Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
|
| + },
|
| + _resetTabindices: function() {
|
| + var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
|
| + this.items.forEach(function(item) {
|
| + item.setAttribute('tabindex', item === selectedItem ? '0' : '-1');
|
| + }, this);
|
| + },
|
| + _updateMultiselectable: function(multi) {
|
| + if (multi) {
|
| + this.setAttribute('aria-multiselectable', 'true');
|
| + } else {
|
| + this.removeAttribute('aria-multiselectable');
|
| + }
|
| + },
|
| + _focusWithKeyboardEvent: function(event) {
|
| + for (var i = 0, item; item = this.items[i]; i++) {
|
| + var attr = this.attrForItemTitle || 'textContent';
|
| + var title = item[attr] || item.getAttribute(attr);
|
| + if (!item.hasAttribute('disabled') && title && title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) {
|
| + this._setFocusedItem(item);
|
| + break;
|
| + }
|
| + }
|
| + },
|
| + _focusPrevious: function() {
|
| + var length = this.items.length;
|
| + var curFocusIndex = Number(this.indexOf(this.focusedItem));
|
| + for (var i = 1; i < length + 1; i++) {
|
| + var item = this.items[(curFocusIndex - i + length) % length];
|
| + if (!item.hasAttribute('disabled')) {
|
| + var owner = Polymer.dom(item).getOwnerRoot() || document;
|
| + this._setFocusedItem(item);
|
| + if (Polymer.dom(owner).activeElement == item) {
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + },
|
| + _focusNext: function() {
|
| + var length = this.items.length;
|
| + var curFocusIndex = Number(this.indexOf(this.focusedItem));
|
| + for (var i = 1; i < length + 1; i++) {
|
| + var item = this.items[(curFocusIndex + i) % length];
|
| + if (!item.hasAttribute('disabled')) {
|
| + var owner = Polymer.dom(item).getOwnerRoot() || document;
|
| + this._setFocusedItem(item);
|
| + if (Polymer.dom(owner).activeElement == item) {
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + },
|
| + _applySelection: function(item, isSelected) {
|
| + if (isSelected) {
|
| + item.setAttribute('aria-selected', 'true');
|
| + } else {
|
| + item.removeAttribute('aria-selected');
|
| + }
|
| + Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
|
| + },
|
| + _focusedItemChanged: function(focusedItem, old) {
|
| + old && old.setAttribute('tabindex', '-1');
|
| + if (focusedItem) {
|
| + focusedItem.setAttribute('tabindex', '0');
|
| + focusedItem.focus();
|
| + }
|
| + },
|
| + _onIronItemsChanged: function(event) {
|
| + if (event.detail.addedNodes.length) {
|
| + this._resetTabindices();
|
| + }
|
| + },
|
| + _onShiftTabDown: function(event) {
|
| + var oldTabIndex = this.getAttribute('tabindex');
|
| + Polymer.IronMenuBehaviorImpl._shiftTabPressed = true;
|
| + this._setFocusedItem(null);
|
| + this.setAttribute('tabindex', '-1');
|
| + this.async(function() {
|
| + this.setAttribute('tabindex', oldTabIndex);
|
| + Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
|
| + }, 1);
|
| + },
|
| + _onFocus: function(event) {
|
| + if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
|
| + return;
|
| + }
|
| + var rootTarget = Polymer.dom(event).rootTarget;
|
| + if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
|
| + return;
|
| + }
|
| + this._defaultFocusAsync = this.async(function() {
|
| + var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
|
| + this._setFocusedItem(null);
|
| + if (selectedItem) {
|
| + this._setFocusedItem(selectedItem);
|
| + } else if (this.items[0]) {
|
| + this._focusNext();
|
| + }
|
| + });
|
| + },
|
| + _onUpKey: function(event) {
|
| + this._focusPrevious();
|
| + event.detail.keyboardEvent.preventDefault();
|
| + },
|
| + _onDownKey: function(event) {
|
| + this._focusNext();
|
| + event.detail.keyboardEvent.preventDefault();
|
| + },
|
| + _onEscKey: function(event) {
|
| + this.focusedItem.blur();
|
| + },
|
| + _onKeydown: function(event) {
|
| + if (!this.keyboardEventMatchesKeys(event, 'up down esc')) {
|
| + this._focusWithKeyboardEvent(event);
|
| + }
|
| + event.stopPropagation();
|
| + },
|
| + _activateHandler: function(event) {
|
| + Polymer.IronSelectableBehavior._activateHandler.call(this, event);
|
| + event.stopPropagation();
|
| + }
|
| +};
|
| +
|
| +Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
|
| +
|
| +Polymer.IronMenuBehavior = [ Polymer.IronMultiSelectableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronMenuBehaviorImpl ];
|
| +
|
| +Polymer.IronMenubarBehaviorImpl = {
|
| + hostAttributes: {
|
| + role: 'menubar'
|
| + },
|
| + keyBindings: {
|
| + left: '_onLeftKey',
|
| + right: '_onRightKey'
|
| + },
|
| + _onUpKey: function(event) {
|
| + this.focusedItem.click();
|
| + event.detail.keyboardEvent.preventDefault();
|
| + },
|
| + _onDownKey: function(event) {
|
| + this.focusedItem.click();
|
| + event.detail.keyboardEvent.preventDefault();
|
| + },
|
| + get _isRTL() {
|
| + return window.getComputedStyle(this)['direction'] === 'rtl';
|
| + },
|
| + _onLeftKey: function(event) {
|
| + if (this._isRTL) {
|
| + this._focusNext();
|
| + } else {
|
| + this._focusPrevious();
|
| + }
|
| + event.detail.keyboardEvent.preventDefault();
|
| + },
|
| + _onRightKey: function(event) {
|
| + if (this._isRTL) {
|
| + this._focusPrevious();
|
| + } else {
|
| + this._focusNext();
|
| + }
|
| + event.detail.keyboardEvent.preventDefault();
|
| + },
|
| + _onKeydown: function(event) {
|
| + if (this.keyboardEventMatchesKeys(event, 'up down left right esc')) {
|
| + return;
|
| + }
|
| + this._focusWithKeyboardEvent(event);
|
| + }
|
| +};
|
| +
|
| +Polymer.IronMenubarBehavior = [ Polymer.IronMenuBehavior, Polymer.IronMenubarBehaviorImpl ];
|
| +
|
| +Polymer({
|
| + is: 'paper-tabs',
|
| + behaviors: [ Polymer.IronResizableBehavior, Polymer.IronMenubarBehavior ],
|
| + properties: {
|
| + noink: {
|
| + type: Boolean,
|
| + value: false,
|
| + observer: '_noinkChanged'
|
| + },
|
| + noBar: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + noSlide: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + scrollable: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + fitContainer: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + disableDrag: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + hideScrollButtons: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + alignBottom: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + selectable: {
|
| + type: String,
|
| + value: 'paper-tab'
|
| + },
|
| + autoselect: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + autoselectDelay: {
|
| + type: Number,
|
| + value: 0
|
| + },
|
| + _step: {
|
| + type: Number,
|
| + value: 10
|
| + },
|
| + _holdDelay: {
|
| + type: Number,
|
| + value: 1
|
| + },
|
| + _leftHidden: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + _rightHidden: {
|
| + type: Boolean,
|
| + value: false
|
| + },
|
| + _previousTab: {
|
| + type: Object
|
| + }
|
| + },
|
| + hostAttributes: {
|
| + role: 'tablist'
|
| + },
|
| + listeners: {
|
| + 'iron-resize': '_onTabSizingChanged',
|
| + 'iron-items-changed': '_onTabSizingChanged',
|
| + 'iron-select': '_onIronSelect',
|
| + 'iron-deselect': '_onIronDeselect'
|
| + },
|
| + keyBindings: {
|
| + 'left:keyup right:keyup': '_onArrowKeyup'
|
| + },
|
| + created: function() {
|
| + this._holdJob = null;
|
| + this._pendingActivationItem = undefined;
|
| + this._pendingActivationTimeout = undefined;
|
| + this._bindDelayedActivationHandler = this._delayedActivationHandler.bind(this);
|
| + this.addEventListener('blur', this._onBlurCapture.bind(this), true);
|
| + },
|
| + ready: function() {
|
| + this.setScrollDirection('y', this.$.tabsContainer);
|
| + },
|
| + detached: function() {
|
| + this._cancelPendingActivation();
|
| + },
|
| + _noinkChanged: function(noink) {
|
| + var childTabs = Polymer.dom(this).querySelectorAll('paper-tab');
|
| + childTabs.forEach(noink ? this._setNoinkAttribute : this._removeNoinkAttribute);
|
| + },
|
| + _setNoinkAttribute: function(element) {
|
| + element.setAttribute('noink', '');
|
| + },
|
| + _removeNoinkAttribute: function(element) {
|
| + element.removeAttribute('noink');
|
| + },
|
| + _computeScrollButtonClass: function(hideThisButton, scrollable, hideScrollButtons) {
|
| + if (!scrollable || hideScrollButtons) {
|
| + return 'hidden';
|
| + }
|
| + if (hideThisButton) {
|
| + return 'not-visible';
|
| + }
|
| + return '';
|
| + },
|
| + _computeTabsContentClass: function(scrollable, fitContainer) {
|
| + return scrollable ? 'scrollable' + (fitContainer ? ' fit-container' : '') : ' fit-container';
|
| + },
|
| + _computeSelectionBarClass: function(noBar, alignBottom) {
|
| + if (noBar) {
|
| + return 'hidden';
|
| + } else if (alignBottom) {
|
| + return 'align-bottom';
|
| + }
|
| + return '';
|
| + },
|
| + _onTabSizingChanged: function() {
|
| + this.debounce('_onTabSizingChanged', function() {
|
| + this._scroll();
|
| + this._tabChanged(this.selectedItem);
|
| + }, 10);
|
| + },
|
| + _onIronSelect: function(event) {
|
| + this._tabChanged(event.detail.item, this._previousTab);
|
| + this._previousTab = event.detail.item;
|
| + this.cancelDebouncer('tab-changed');
|
| + },
|
| + _onIronDeselect: function(event) {
|
| + this.debounce('tab-changed', function() {
|
| + this._tabChanged(null, this._previousTab);
|
| + this._previousTab = null;
|
| + }, 1);
|
| + },
|
| + _activateHandler: function() {
|
| + this._cancelPendingActivation();
|
| + Polymer.IronMenuBehaviorImpl._activateHandler.apply(this, arguments);
|
| + },
|
| + _scheduleActivation: function(item, delay) {
|
| + this._pendingActivationItem = item;
|
| + this._pendingActivationTimeout = this.async(this._bindDelayedActivationHandler, delay);
|
| + },
|
| + _delayedActivationHandler: function() {
|
| + var item = this._pendingActivationItem;
|
| + this._pendingActivationItem = undefined;
|
| + this._pendingActivationTimeout = undefined;
|
| + item.fire(this.activateEvent, null, {
|
| + bubbles: true,
|
| + cancelable: true
|
| + });
|
| + },
|
| + _cancelPendingActivation: function() {
|
| + if (this._pendingActivationTimeout !== undefined) {
|
| + this.cancelAsync(this._pendingActivationTimeout);
|
| + this._pendingActivationItem = undefined;
|
| + this._pendingActivationTimeout = undefined;
|
| + }
|
| + },
|
| + _onArrowKeyup: function(event) {
|
| + if (this.autoselect) {
|
| + this._scheduleActivation(this.focusedItem, this.autoselectDelay);
|
| + }
|
| + },
|
| + _onBlurCapture: function(event) {
|
| + if (event.target === this._pendingActivationItem) {
|
| + this._cancelPendingActivation();
|
| + }
|
| + },
|
| + get _tabContainerScrollSize() {
|
| + return Math.max(0, this.$.tabsContainer.scrollWidth - this.$.tabsContainer.offsetWidth);
|
| + },
|
| + _scroll: function(e, detail) {
|
| + if (!this.scrollable) {
|
| + return;
|
| + }
|
| + var ddx = detail && -detail.ddx || 0;
|
| + this._affectScroll(ddx);
|
| + },
|
| + _down: function(e) {
|
| + this.async(function() {
|
| + if (this._defaultFocusAsync) {
|
| + this.cancelAsync(this._defaultFocusAsync);
|
| + this._defaultFocusAsync = null;
|
| + }
|
| + }, 1);
|
| + },
|
| + _affectScroll: function(dx) {
|
| + this.$.tabsContainer.scrollLeft += dx;
|
| + var scrollLeft = this.$.tabsContainer.scrollLeft;
|
| + this._leftHidden = scrollLeft === 0;
|
| + this._rightHidden = scrollLeft === this._tabContainerScrollSize;
|
| + },
|
| + _onLeftScrollButtonDown: function() {
|
| + this._scrollToLeft();
|
| + this._holdJob = setInterval(this._scrollToLeft.bind(this), this._holdDelay);
|
| + },
|
| + _onRightScrollButtonDown: function() {
|
| + this._scrollToRight();
|
| + this._holdJob = setInterval(this._scrollToRight.bind(this), this._holdDelay);
|
| + },
|
| + _onScrollButtonUp: function() {
|
| + clearInterval(this._holdJob);
|
| + this._holdJob = null;
|
| + },
|
| + _scrollToLeft: function() {
|
| + this._affectScroll(-this._step);
|
| + },
|
| + _scrollToRight: function() {
|
| + this._affectScroll(this._step);
|
| + },
|
| + _tabChanged: function(tab, old) {
|
| + if (!tab) {
|
| + this.$.selectionBar.classList.remove('expand');
|
| + this.$.selectionBar.classList.remove('contract');
|
| + this._positionBar(0, 0);
|
| + return;
|
| + }
|
| + var r = this.$.tabsContent.getBoundingClientRect();
|
| + var w = r.width;
|
| + var tabRect = tab.getBoundingClientRect();
|
| + var tabOffsetLeft = tabRect.left - r.left;
|
| + this._pos = {
|
| + width: this._calcPercent(tabRect.width, w),
|
| + left: this._calcPercent(tabOffsetLeft, w)
|
| + };
|
| + if (this.noSlide || old == null) {
|
| + this.$.selectionBar.classList.remove('expand');
|
| + this.$.selectionBar.classList.remove('contract');
|
| + this._positionBar(this._pos.width, this._pos.left);
|
| + return;
|
| + }
|
| + var oldRect = old.getBoundingClientRect();
|
| + var oldIndex = this.items.indexOf(old);
|
| + var index = this.items.indexOf(tab);
|
| + var m = 5;
|
| + this.$.selectionBar.classList.add('expand');
|
| + var moveRight = oldIndex < index;
|
| + var isRTL = this._isRTL;
|
| + if (isRTL) {
|
| + moveRight = !moveRight;
|
| + }
|
| + if (moveRight) {
|
| + this._positionBar(this._calcPercent(tabRect.left + tabRect.width - oldRect.left, w) - m, this._left);
|
| + } else {
|
| + this._positionBar(this._calcPercent(oldRect.left + oldRect.width - tabRect.left, w) - m, this._calcPercent(tabOffsetLeft, w) + m);
|
| + }
|
| + if (this.scrollable) {
|
| + this._scrollToSelectedIfNeeded(tabRect.width, tabOffsetLeft);
|
| + }
|
| + },
|
| + _scrollToSelectedIfNeeded: function(tabWidth, tabOffsetLeft) {
|
| + var l = tabOffsetLeft - this.$.tabsContainer.scrollLeft;
|
| + if (l < 0) {
|
| + this.$.tabsContainer.scrollLeft += l;
|
| + } else {
|
| + l += tabWidth - this.$.tabsContainer.offsetWidth;
|
| + if (l > 0) {
|
| + this.$.tabsContainer.scrollLeft += l;
|
| + }
|
| + }
|
| + },
|
| + _calcPercent: function(w, w0) {
|
| + return 100 * w / w0;
|
| + },
|
| + _positionBar: function(width, left) {
|
| + width = width || 0;
|
| + left = left || 0;
|
| + this._width = width;
|
| + this._left = left;
|
| + this.transform('translateX(' + left + '%) scaleX(' + width / 100 + ')', this.$.selectionBar);
|
| + },
|
| + _onBarTransitionEnd: function(e) {
|
| + var cl = this.$.selectionBar.classList;
|
| + if (cl.contains('expand')) {
|
| + cl.remove('expand');
|
| + cl.add('contract');
|
| + this._positionBar(this._pos.width, this._pos.left);
|
| + } else if (cl.contains('contract')) {
|
| + cl.remove('contract');
|
| + }
|
| + }
|
| +});
|
|
|