focus-components-v3
Version:
Focus web components to build applications (based on Material Design)
368 lines (282 loc) • 36.3 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _class;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _buttonBackToTop = require('../button-back-to-top');
var _buttonBackToTop2 = _interopRequireDefault(_buttonBackToTop);
var _stickyMenu = require('./sticky-menu');
var _stickyMenu2 = _interopRequireDefault(_stickyMenu);
var _scroll = require('../behaviours/scroll');
var _scroll2 = _interopRequireDefault(_scroll);
var _grid = require('../grid');
var _grid2 = _interopRequireDefault(_grid);
var _column = require('../column');
var _column2 = _interopRequireDefault(_column);
var _debounce = require('lodash/debounce');
var _debounce2 = _interopRequireDefault(_debounce);
var _filter = require('lodash/filter');
var _filter2 = _interopRequireDefault(_filter);
var _first = require('lodash/first');
var _first2 = _interopRequireDefault(_first);
var _last = require('lodash/last');
var _last2 = _interopRequireDefault(_last);
var _xor = require('lodash/xor');
var _xor2 = _interopRequireDefault(_xor);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); }
var BackToTopComponent = _buttonBackToTop2.default;
// component default props.
var defaultProps = {
hasMenu: true, //Activate the presence of the sticky navigation component.
hasBackToTop: true, //Activate the presence of BackToTop button
offset: 100, //offset position when affix
scrollDelay: 10 //defaut debounce delay for scroll spy call
};
// component props definition.
var propTypes = {
hasMenu: _react.PropTypes.bool,
hasBackToTop: _react.PropTypes.bool,
offset: _react.PropTypes.number,
scrollDelay: _react.PropTypes.number
};
/**
* ScrollspyContainer component.
*/
var ScrollspyContainer = (0, _scroll2.default)(_class = function (_Component) {
_inherits(ScrollspyContainer, _Component);
function ScrollspyContainer(props) {
_classCallCheck(this, ScrollspyContainer);
var _this = _possibleConstructorReturn(this, _Component.call(this, props));
_this._executeRefreshMenu = function (time) {
_this._timeouts = [];
for (var i = 0; i < time; i++) {
_this._timeouts.push(setTimeout(_this._refreshMenu.bind(_this), i * 1000));
}
};
_this._debounceRefreshMenu = function () {
_this._debouncedRefresh();
};
_this._refreshMenu = function () {
if (!_this.props.hasMenu) {
return;
}
var stickyMenu = _this.refs.stickyMenu;
var clickedId = _this.state.clickedId;
var menus = _this._buildMenuList(); //build the menu list
//TODO remove this check
var affix = stickyMenu ? _this._isMenuAffix() : _this.state.affix; //Calculate menu position (affix or not)
// Check if scroll is at cliked item level
var isAtClickedItem = void 0;
if (clickedId !== undefined) {
var selector = '[data-spy=\'' + clickedId + '\']';
var node = document.querySelector(selector);
var nodePosition = _this.scrollPosition(node);
var positionTop = _this._getElementRealPosition(nodePosition.top);
isAtClickedItem = _this.scrollPosition().top === positionTop;
}
_this.setState({
menuList: menus,
clickedId: isAtClickedItem ? undefined : clickedId,
affix: affix
});
};
_this._buildMenuList = function () {
var hasMenu = _this.props.hasMenu;
if (!hasMenu) {
return [];
}
var detectionOffset = window.screen.height / 5;
var currentScrollPosition = { top: _this.scrollPosition().top, left: _this.scrollPosition().left };
var isAtPageBottom = _this.isAtPageBottom();
//get the menu list (without blocks in popin)
var thisComponentNode = _reactDom2.default.findDOMNode(_this);
var allDataSpy = thisComponentNode.querySelectorAll('[data-spy]');
var popinDataSpy = thisComponentNode.querySelectorAll('[data-focus=\'popin-window\'] [data-spy]');
var selectionList = (0, _xor2.default)(allDataSpy, popinDataSpy);
if (selectionList.length === 0) {
return;
}
var menuList = selectionList.map(function (selection, index) {
var title = selection.querySelector('[data-spy-title]');
var nodeId = selection.getAttribute('data-spy');
return {
index: index,
label: title.innerHTML,
nodeId: nodeId,
scrollTop: _this.scrollPosition(selection).top, // offset of 10 to be safe
isActive: false,
onClick: _this._getMenuItemClickHandler(nodeId)
};
});
var nextTitles = (0, _filter2.default)(menuList, function (n) {
return currentScrollPosition.top + detectionOffset < _this._getElementRealPosition(n.scrollTop);
});
//Calculate current node
//by default, first node is indexed
var currentIndex = menuList[0].index;
if (0 < nextTitles.length) {
//check the first node
var firstNode = (0, _first2.default)(nextTitles);
var index = firstNode.index;
if (0 < index) {
currentIndex = menuList[index - 1].index;
}
} else {
//means that the position is the last title
currentIndex = (0, _last2.default)(menuList).index;
}
var clickedId = _this.state.clickedId;
if (isAtPageBottom && undefined !== clickedId) {
menuList = menuList.map(function (item) {
if (item.nodeId === clickedId) {
item.isActive = true;
}
return item;
});
_this.setState({ clickedId: undefined });
} else {
menuList[currentIndex].isActive = true;
}
return menuList;
};
_this._getElementRealPosition = function (position) {
var sscDomNode = _reactDom2.default.findDOMNode(_this);
var sscPosition = _this.scrollPosition(sscDomNode);
return position - sscPosition.top;
};
_this._isMenuAffix = function () {
var offset = _this.props.offset;
var hasMenu = _this.props.hasMenu;
if (!hasMenu) {
return false;
}
var sscDomNode = _reactDom2.default.findDOMNode(_this);
var currentViewPosition = sscDomNode.getBoundingClientRect();
var containerPaddingTop = _this._getPaddingTopValue();
offset -= containerPaddingTop;
return currentViewPosition.top <= offset;
};
_this._getPaddingTopValue = function () {
var sscDomNode = _reactDom2.default.findDOMNode(_this);
var computedStyles = window.getComputedStyle(sscDomNode, null);
var paddingTop = computedStyles.getPropertyValue('padding-top');
return paddingTop ? parseInt(paddingTop, 0) : 0;
};
var state = {
menuList: [],
affix: false
};
_this.state = state;
return _this;
}
/** @inheritDoc */
ScrollspyContainer.prototype.componentDidMount = function componentDidMount() {
this._scrollCarrier = window;
this._debouncedRefresh = (0, _debounce2.default)(this._refreshMenu, this.props.scrollDelay);
this._scrollCarrier.addEventListener('scroll', this._debounceRefreshMenu);
this._scrollCarrier.addEventListener('resize', this._debounceRefreshMenu);
this._executeRefreshMenu(10);
};
/** @inheritDoc */
ScrollspyContainer.prototype.componentWillUnmount = function componentWillUnmount() {
this._timeouts.map(clearTimeout);
this._scrollCarrier.removeEventListener('scroll', this._debounceRefreshMenu);
this._scrollCarrier.removeEventListener('resize', this._debounceRefreshMenu);
this._debouncedRefresh.cancel();
};
/**
* Refresh screen X times.
* @param {number} time number of execution
*/
/**
* The scroll event handler
* @private
*/
/**
* Build the list of menus.
* @private
* @return {array} the list of menus.
*/
/**
* Calculate the real position of an element, depending on declared offset in props.
* @private
* @param {number} position position
* @return {number} the real position
*/
/**
* Calculate menu position (affix or not)
* @private
* @return {Boolean} true is menu must be affix, else false
*/
/**
* Handle click on item menu function.
* @private
* @param {string} menuId node spyId in DOM to scroll to
* @return {function} function to call
*/
ScrollspyContainer.prototype._getMenuItemClickHandler = function _getMenuItemClickHandler(menuId) {
var _this2 = this;
return function () {
_this2.setState({
clickedId: menuId
}, function () {
_this2._refreshMenu();
_this2._onMenuItemClick(menuId);
});
};
};
/**
* Menu click function. Scroll to the node position.
* @private
* @param {string} menuId node spyId in DOM to scroll to
*/
ScrollspyContainer.prototype._onMenuItemClick = function _onMenuItemClick(menuId) {
var selector = '[data-spy=\'' + menuId + '\']';
var node = document.querySelector(selector);
var nodePosition = this.scrollPosition(node);
var positionTop = this._getElementRealPosition(nodePosition.top);
this.scrollTo(undefined, positionTop);
};
/** @inheritedDoc */
ScrollspyContainer.prototype.render = function render() {
var _props = this.props,
children = _props.children,
hasMenu = _props.hasMenu,
hasBackToTop = _props.hasBackToTop,
offset = _props.offset,
scrollDelay = _props.scrollDelay,
otherProps = _objectWithoutProperties(_props, ['children', 'hasMenu', 'hasBackToTop', 'offset', 'scrollDelay']);
var _state = this.state,
affix = _state.affix,
menuList = _state.menuList;
return _react2.default.createElement(
'div',
_extends({ 'data-focus': 'scrollspy-container' }, otherProps),
hasMenu && _react2.default.createElement(_stickyMenu2.default, { affix: affix, affixOffset: offset, menuList: menuList, ref: 'stickyMenu' }),
_react2.default.createElement(
'div',
{ 'data-focus': 'scrollspy-container-content' },
children
),
hasBackToTop && _react2.default.createElement(BackToTopComponent, null)
);
};
return ScrollspyContainer;
}(_react.Component)) || _class;
//Static props.
ScrollspyContainer.displayName = 'ScrollspyContainer';
ScrollspyContainer.defaultProps = defaultProps;
ScrollspyContainer.propTypes = propTypes;
exports.default = ScrollspyContainer;
module.exports = exports['default'];
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZyLUZSLmpzIl0sIm5hbWVzIjpbIkJhY2tUb1RvcENvbXBvbmVudCIsImRlZmF1bHRQcm9wcyIsImhhc01lbnUiLCJoYXNCYWNrVG9Ub3AiLCJvZmZzZXQiLCJzY3JvbGxEZWxheSIsInByb3BUeXBlcyIsImJvb2wiLCJudW1iZXIiLCJTY3JvbGxzcHlDb250YWluZXIiLCJwcm9wcyIsIl9leGVjdXRlUmVmcmVzaE1lbnUiLCJfdGltZW91dHMiLCJpIiwidGltZSIsInB1c2giLCJzZXRUaW1lb3V0IiwiX3JlZnJlc2hNZW51IiwiYmluZCIsIl9kZWJvdW5jZVJlZnJlc2hNZW51IiwiX2RlYm91bmNlZFJlZnJlc2giLCJzdGlja3lNZW51IiwicmVmcyIsImNsaWNrZWRJZCIsInN0YXRlIiwibWVudXMiLCJfYnVpbGRNZW51TGlzdCIsImFmZml4IiwiX2lzTWVudUFmZml4IiwiaXNBdENsaWNrZWRJdGVtIiwidW5kZWZpbmVkIiwic2VsZWN0b3IiLCJub2RlIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwibm9kZVBvc2l0aW9uIiwic2Nyb2xsUG9zaXRpb24iLCJwb3NpdGlvblRvcCIsIl9nZXRFbGVtZW50UmVhbFBvc2l0aW9uIiwidG9wIiwic2V0U3RhdGUiLCJtZW51TGlzdCIsImRldGVjdGlvbk9mZnNldCIsIndpbmRvdyIsInNjcmVlbiIsImhlaWdodCIsImN1cnJlbnRTY3JvbGxQb3NpdGlvbiIsImxlZnQiLCJpc0F0UGFnZUJvdHRvbSIsInRoaXNDb21wb25lbnROb2RlIiwiZmluZERPTU5vZGUiLCJhbGxEYXRhU3B5IiwicXVlcnlTZWxlY3RvckFsbCIsInBvcGluRGF0YVNweSIsInNlbGVjdGlvbkxpc3QiLCJsZW5ndGgiLCJtYXAiLCJzZWxlY3Rpb24iLCJpbmRleCIsInRpdGxlIiwibm9kZUlkIiwiZ2V0QXR0cmlidXRlIiwibGFiZWwiLCJpbm5lckhUTUwiLCJzY3JvbGxUb3AiLCJpc0FjdGl2ZSIsIm9uQ2xpY2siLCJfZ2V0TWVudUl0ZW1DbGlja0hhbmRsZXIiLCJuZXh0VGl0bGVzIiwibiIsImN1cnJlbnRJbmRleCIsImZpcnN0Tm9kZSIsIml0ZW0iLCJwb3NpdGlvbiIsInNzY0RvbU5vZGUiLCJzc2NQb3NpdGlvbiIsImN1cnJlbnRWaWV3UG9zaXRpb24iLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJjb250YWluZXJQYWRkaW5nVG9wIiwiX2dldFBhZGRpbmdUb3BWYWx1ZSIsImNvbXB1dGVkU3R5bGVzIiwiZ2V0Q29tcHV0ZWRTdHlsZSIsInBhZGRpbmdUb3AiLCJnZXRQcm9wZXJ0eVZhbHVlIiwicGFyc2VJbnQiLCJjb21wb25lbnREaWRNb3VudCIsIl9zY3JvbGxDYXJyaWVyIiwiYWRkRXZlbnRMaXN0ZW5lciIsImNvbXBvbmVudFdpbGxVbm1vdW50IiwiY2xlYXJUaW1lb3V0IiwicmVtb3ZlRXZlbnRMaXN0ZW5lciIsImNhbmNlbCIsIm1lbnVJZCIsIl9vbk1lbnVJdGVtQ2xpY2siLCJzY3JvbGxUbyIsInJlbmRlciIsImNoaWxkcmVuIiwib3RoZXJQcm9wcyIsImRpc3BsYXlOYW1lIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUE7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFFQTs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOzs7Ozs7Ozs7Ozs7Ozs7O0FBRUEsSUFBTUEsOENBQU47O0FBRUE7QUFDQSxJQUFNQyxlQUFlO0FBQ2pCQyxhQUFTLElBRFEsRUFDRjtBQUNmQyxrQkFBYyxJQUZHLEVBRUc7QUFDcEJDLFlBQVEsR0FIUyxFQUdKO0FBQ2JDLGlCQUFhLEVBSkksQ0FJRDtBQUpDLENBQXJCOztBQU9BO0FBQ0EsSUFBTUMsWUFBWTtBQUNkSixhQUFTLGlCQUFVSyxJQURMO0FBRWRKLGtCQUFjLGlCQUFVSSxJQUZWO0FBR2RILFlBQVEsaUJBQVVJLE1BSEo7QUFJZEgsaUJBQWEsaUJBQVVHO0FBSlQsQ0FBbEI7O0FBT0E7Ozs7SUFJTUMsa0I7Y0FBQUEs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QUFDQXpGLG1CQUFtQlIsWUFBbkIsR0FBa0NBLFlBQWxDO0FBQ0FRLG1CQUFtQkgsU0FBbkIsR0FBK0JBLFNBQS9COztrQkFFZUcsa0IiLCJmaWxlIjoiZnItRlIuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QsIHtDb21wb25lbnQsIFByb3BUeXBlc30gZnJvbSAncmVhY3QnO1xyXG5pbXBvcnQgUmVhY3RET00gZnJvbSAncmVhY3QtZG9tJztcclxuaW1wb3J0IEJhY2tUb1RvcCBmcm9tICcuLi9idXR0b24tYmFjay10by10b3AnXHJcbmltcG9ydCBTdGlja3lNZW51IGZyb20gJy4vc3RpY2t5LW1lbnUnO1xyXG5pbXBvcnQgU2Nyb2xsIGZyb20gJy4uL2JlaGF2aW91cnMvc2Nyb2xsJztcclxuaW1wb3J0IEdyaWQgZnJvbSAnLi4vZ3JpZCc7XHJcbmltcG9ydCBDb2x1bW4gZnJvbSAnLi4vY29sdW1uJztcclxuXHJcbmltcG9ydCBkZWJvdW5jZSBmcm9tICdsb2Rhc2gvZGVib3VuY2UnO1xyXG5pbXBvcnQgZmlsdGVyIGZyb20gJ2xvZGFzaC9maWx0ZXInO1xyXG5pbXBvcnQgZmlyc3QgZnJvbSAnbG9kYXNoL2ZpcnN0JztcclxuaW1wb3J0IGxhc3QgZnJvbSAnbG9kYXNoL2xhc3QnO1xyXG5pbXBvcnQgeG9yIGZyb20gJ2xvZGFzaC94b3InO1xyXG5cclxuY29uc3QgQmFja1RvVG9wQ29tcG9uZW50ID0gQmFja1RvVG9wO1xyXG5cclxuLy8gY29tcG9uZW50IGRlZmF1bHQgcHJvcHMuXHJcbmNvbnN0IGRlZmF1bHRQcm9wcyA9IHtcclxuICAgIGhhc01lbnU6IHRydWUsIC8vQWN0aXZhdGUgdGhlIHByZXNlbmNlIG9mIHRoZSBzdGlja3kgbmF2aWdhdGlvbiBjb21wb25lbnQuXHJcbiAgICBoYXNCYWNrVG9Ub3A6IHRydWUsIC8vQWN0aXZhdGUgdGhlIHByZXNlbmNlIG9mIEJhY2tUb1RvcCBidXR0b25cclxuICAgIG9mZnNldDogMTAwLCAvL29mZnNldCBwb3NpdGlvbiB3aGVuIGFmZml4XHJcbiAgICBzY3JvbGxEZWxheTogMTAgLy9kZWZhdXQgZGVib3VuY2UgZGVsYXkgZm9yIHNjcm9sbCBzcHkgY2FsbFxyXG59O1xyXG5cclxuLy8gY29tcG9uZW50IHByb3BzIGRlZmluaXRpb24uXHJcbmNvbnN0IHByb3BUeXBlcyA9IHtcclxuICAgIGhhc01lbnU6IFByb3BUeXBlcy5ib29sLFxyXG4gICAgaGFzQmFja1RvVG9wOiBQcm9wVHlwZXMuYm9vbCxcclxuICAgIG9mZnNldDogUHJvcFR5cGVzLm51bWJlcixcclxuICAgIHNjcm9sbERlbGF5OiBQcm9wVHlwZXMubnVtYmVyXHJcbn07XHJcblxyXG4vKipcclxuKiBTY3JvbGxzcHlDb250YWluZXIgY29tcG9uZW50LlxyXG4qL1xyXG5AU2Nyb2xsXHJcbmNsYXNzIFNjcm9sbHNweUNvbnRhaW5lciBleHRlbmRzIENvbXBvbmVudCB7XHJcbiAgICBjb25zdHJ1Y3Rvcihwcm9wcykge1xyXG4gICAgICAgIHN1cGVyKHByb3BzKTtcclxuICAgICAgICBjb25zdCBzdGF0ZSA9IHtcclxuICAgICAgICAgICAgbWVudUxpc3Q6IFtdLFxyXG4gICAgICAgICAgICBhZmZpeDogZmFsc2VcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRoaXMuc3RhdGUgPSBzdGF0ZTtcclxuICAgIH1cclxuXHJcbiAgICAvKiogQGluaGVyaXREb2MgKi9cclxuICAgIGNvbXBvbmVudERpZE1vdW50KCkge1xyXG4gICAgICAgIHRoaXMuX3Njcm9sbENhcnJpZXIgPSB3aW5kb3c7XHJcbiAgICAgICAgdGhpcy5fZGVib3VuY2VkUmVmcmVzaCA9IGRlYm91bmNlKHRoaXMuX3JlZnJlc2hNZW51LCB0aGlzLnByb3BzLnNjcm9sbERlbGF5KTtcclxuICAgICAgICB0aGlzLl9zY3JvbGxDYXJyaWVyLmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRoaXMuX2RlYm91bmNlUmVmcmVzaE1lbnUpO1xyXG4gICAgICAgIHRoaXMuX3Njcm9sbENhcnJpZXIuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdGhpcy5fZGVib3VuY2VSZWZyZXNoTWVudSk7XHJcbiAgICAgICAgdGhpcy5fZXhlY3V0ZVJlZnJlc2hNZW51KDEwKTtcclxuICAgIH1cclxuXHJcbiAgICAvKiogQGluaGVyaXREb2MgKi9cclxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xyXG4gICAgICAgIHRoaXMuX3RpbWVvdXRzLm1hcChjbGVhclRpbWVvdXQpO1xyXG4gICAgICAgIHRoaXMuX3Njcm9sbENhcnJpZXIucmVtb3ZlRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhpcy5fZGVib3VuY2VSZWZyZXNoTWVudSk7XHJcbiAgICAgICAgdGhpcy5fc2Nyb2xsQ2Fycmllci5yZW1vdmVFdmVudExpc3RlbmVyKCdyZXNpemUnLCB0aGlzLl9kZWJvdW5jZVJlZnJlc2hNZW51KTtcclxuICAgICAgICB0aGlzLl9kZWJvdW5jZWRSZWZyZXNoLmNhbmNlbCgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgKiBSZWZyZXNoIHNjcmVlbiBYIHRpbWVzLlxyXG4gICAgKiBAcGFyYW0gIHtudW1iZXJ9IHRpbWUgbnVtYmVyIG9mIGV4ZWN1dGlvblxyXG4gICAgKi9cclxuICAgIF9leGVjdXRlUmVmcmVzaE1lbnUgPSB0aW1lID0+IHtcclxuICAgICAgICB0aGlzLl90aW1lb3V0cyA9IFtdO1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGltZTsgaSsrKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3RpbWVvdXRzLnB1c2goc2V0VGltZW91dCh0aGlzLl9yZWZyZXNoTWVudS5iaW5kKHRoaXMpLCBpICogMTAwMCkpO1xyXG4gICAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgX2RlYm91bmNlUmVmcmVzaE1lbnUgPSAoKSA9PiB7XHJcbiAgICAgICAgdGhpcy5fZGVib3VuY2VkUmVmcmVzaCgpO1xyXG4gICAgfTtcclxuXHJcbiAgICAvKipcclxuICAgICogVGhlIHNjcm9sbCBldmVudCBoYW5kbGVyXHJcbiAgICAqIEBwcml2YXRlXHJcbiAgICAqL1xyXG4gICAgX3JlZnJlc2hNZW51ID0gKCkgPT4ge1xyXG4gICAgICAgIGlmKCF0aGlzLnByb3BzLmhhc01lbnUpIHsgcmV0dXJuOyB9XHJcbiAgICAgICAgY29uc3Qge3N0aWNreU1lbnV9ID0gdGhpcy5yZWZzO1xyXG4gICAgICAgIGNvbnN0IHtjbGlja2VkSWR9ID0gdGhpcy5zdGF0ZTtcclxuICAgICAgICBjb25zdCBtZW51cyA9IHRoaXMuX2J1aWxkTWVudUxpc3QoKTsgLy9idWlsZCB0aGUgbWVudSBsaXN0XHJcbiAgICAgICAgLy9UT0RPIHJlbW92ZSB0aGlzIGNoZWNrXHJcbiAgICAgICAgY29uc3QgYWZmaXggPSBzdGlja3lNZW51ID8gdGhpcy5faXNNZW51QWZmaXgoKSA6IHRoaXMuc3RhdGUuYWZmaXg7IC8vQ2FsY3VsYXRlIG1lbnUgcG9zaXRpb24gKGFmZml4IG9yIG5vdClcclxuICAgICAgICAvLyBDaGVjayBpZiBzY3JvbGwgaXMgYXQgY2xpa2VkIGl0ZW0gbGV2ZWxcclxuICAgICAgICBsZXQgaXNBdENsaWNrZWRJdGVtO1xyXG4gICAgICAgIGlmIChjbGlja2VkSWQgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICBjb25zdCBzZWxlY3RvciA9IGBbZGF0YS1zcHk9JyR7Y2xpY2tlZElkfSddYDtcclxuICAgICAgICAgICAgY29uc3Qgbm9kZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3IpO1xyXG4gICAgICAgICAgICBjb25zdCBub2RlUG9zaXRpb24gPSB0aGlzLnNjcm9sbFBvc2l0aW9uKG5vZGUpO1xyXG4gICAgICAgICAgICBjb25zdCBwb3NpdGlvblRvcCA9IHRoaXMuX2dldEVsZW1lbnRSZWFsUG9zaXRpb24obm9kZVBvc2l0aW9uLnRvcCk7XHJcbiAgICAgICAgICAgIGlzQXRDbGlja2VkSXRlbSA9IHRoaXMuc2Nyb2xsUG9zaXRpb24oKS50b3AgPT09IHBvc2l0aW9uVG9wO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcclxuICAgICAgICAgICAgbWVudUxpc3Q6IG1lbnVzLFxyXG4gICAgICAgICAgICBjbGlja2VkSWQ6IGlzQXRDbGlja2VkSXRlbSA/IHVuZGVmaW5lZCA6IGNsaWNrZWRJZCxcclxuICAgICAgICAgICAgYWZmaXhcclxuICAgICAgICB9KTtcclxuICAgIH07XHJcblxyXG4gICAgLyoqXHJcbiAgICAqIEJ1aWxkIHRoZSBsaXN0IG9mIG1lbnVzLlxyXG4gICAgKiBAcHJpdmF0ZVxyXG4gICAgKiBAcmV0dXJuIHthcnJheX0gdGhlIGxpc3Qgb2YgbWVudXMuXHJcbiAgICAqL1xyXG4gICAgX2J1aWxkTWVudUxpc3QgPSAoKSA9PiB7XHJcbiAgICAgICAgY29uc3Qge2hhc01lbnV9ID0gdGhpcy5wcm9wcztcclxuICAgICAgICBpZighaGFzTWVudSkge1xyXG4gICAgICAgICAgICByZXR1cm4gW107XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IGRldGVjdGlvbk9mZnNldCA9IHdpbmRvdy5zY3JlZW4uaGVpZ2h0IC8gNTtcclxuICAgICAgICBsZXQgY3VycmVudFNjcm9sbFBvc2l0aW9uID0ge3RvcDogdGhpcy5zY3JvbGxQb3NpdGlvbigpLnRvcCwgbGVmdDogdGhpcy5zY3JvbGxQb3NpdGlvbigpLmxlZnR9O1xyXG4gICAgICAgIGxldCBpc0F0UGFnZUJvdHRvbSA9IHRoaXMuaXNBdFBhZ2VCb3R0b20oKTtcclxuXHJcbiAgICAgICAgLy9nZXQgdGhlIG1lbnUgbGlzdCAod2l0aG91dCBibG9ja3MgaW4gcG9waW4pXHJcbiAgICAgICAgY29uc3QgdGhpc0NvbXBvbmVudE5vZGUgPSBSZWFjdERPTS5maW5kRE9NTm9kZSh0aGlzKTtcclxuICAgICAgICBjb25zdCBhbGxEYXRhU3B5ID0gdGhpc0NvbXBvbmVudE5vZGUucXVlcnlTZWxlY3RvckFsbCgnW2RhdGEtc3B5XScpO1xyXG4gICAgICAgIGNvbnN0IHBvcGluRGF0YVNweSA9IHRoaXNDb21wb25lbnROb2RlLnF1ZXJ5U2VsZWN0b3JBbGwoYFtkYXRhLWZvY3VzPSdwb3Bpbi13aW5kb3cnXSBbZGF0YS1zcHldYCk7XHJcbiAgICAgICAgY29uc3Qgc2VsZWN0aW9uTGlzdCA9IHhvcihhbGxEYXRhU3B5LCBwb3BpbkRhdGFTcHkpO1xyXG5cclxuICAgICAgICBpZihzZWxlY3Rpb25MaXN0Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBtZW51TGlzdCA9IHNlbGVjdGlvbkxpc3QubWFwKChzZWxlY3Rpb24sIGluZGV4KSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IHRpdGxlID0gc2VsZWN0aW9uLnF1ZXJ5U2VsZWN0b3IoJ1tkYXRhLXNweS10aXRsZV0nKTtcclxuICAgICAgICAgICAgY29uc3Qgbm9kZUlkID0gc2VsZWN0aW9uLmdldEF0dHJpYnV0ZSgnZGF0YS1zcHknKTtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIGluZGV4OiBpbmRleCxcclxuICAgICAgICAgICAgICAgIGxhYmVsOiB0aXRsZS5pbm5lckhUTUwsXHJcbiAgICAgICAgICAgICAgICBub2RlSWQ6IG5vZGVJZCxcclxuICAgICAgICAgICAgICAgIHNjcm9sbFRvcDogdGhpcy5zY3JvbGxQb3NpdGlvbihzZWxlY3Rpb24pLnRvcCwgLy8gb2Zmc2V0IG9mIDEwIHRvIGJlIHNhZmVcclxuICAgICAgICAgICAgICAgIGlzQWN0aXZlOiBmYWxzZSxcclxuICAgICAgICAgICAgICAgIG9uQ2xpY2s6IHRoaXMuX2dldE1lbnVJdGVtQ2xpY2tIYW5kbGVyKG5vZGVJZClcclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgY29uc3QgbmV4dFRpdGxlcyA9IGZpbHRlcihtZW51TGlzdCwgbiA9PiAoY3VycmVudFNjcm9sbFBvc2l0aW9uLnRvcCArIGRldGVjdGlvbk9mZnNldCA8IHRoaXMuX2dldEVsZW1lbnRSZWFsUG9zaXRpb24obi5zY3JvbGxUb3ApKSk7XHJcblxyXG4gICAgICAgIC8vQ2FsY3VsYXRlIGN1cnJlbnQgbm9kZVxyXG4gICAgICAgIC8vYnkgZGVmYXVsdCwgZmlyc3Qgbm9kZSBpcyBpbmRleGVkXHJcbiAgICAgICAgbGV0IGN1cnJlbnRJbmRleCA9IG1lbnVMaXN0WzBdLmluZGV4O1xyXG4gICAgICAgIGlmKDAgPCBuZXh0VGl0bGVzLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAvL2NoZWNrIHRoZSBmaXJzdCBub2RlXHJcbiAgICAgICAgICAgIGNvbnN0IGZpcnN0Tm9kZSA9IGZpcnN0KG5leHRUaXRsZXMpO1xyXG4gICAgICAgICAgICBjb25zdCBpbmRleCA9IGZpcnN0Tm9kZS5pbmRleDtcclxuICAgICAgICAgICAgaWYoMCA8IGluZGV4KSB7XHJcbiAgICAgICAgICAgICAgICBjdXJyZW50SW5kZXggPSBtZW51TGlzdFtpbmRleCAtIDFdLmluZGV4O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy9tZWFucyB0aGF0IHRoZSBwb3NpdGlvbiBpcyB0aGUgbGFzdCB0aXRsZVxyXG4gICAgICAgICAgICBjdXJyZW50SW5kZXggPSBsYXN0KG1lbnVMaXN0KS5pbmRleDtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGV0IGNsaWNrZWRJZCA9IHRoaXMuc3RhdGUuY2xpY2tlZElkO1xyXG4gICAgICAgIGlmKGlzQXRQYWdlQm90dG9tICYmIHVuZGVmaW5lZCAhPT0gY2xpY2tlZElkKSB7XHJcbiAgICAgICAgICAgIG1lbnVMaXN0ID0gbWVudUxpc3QubWFwKGl0ZW0gPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0ubm9kZUlkID09PSBjbGlja2VkSWQpIHtcclxuICAgICAgICAgICAgICAgICAgICBpdGVtLmlzQWN0aXZlID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHJldHVybiBpdGVtO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7Y2xpY2tlZElkOiB1bmRlZmluZWR9KTtcclxuICAgICAgICB9ZWxzZSB7XHJcbiAgICAgICAgICAgIG1lbnVMaXN0W2N1cnJlbnRJbmRleF0uaXNBY3RpdmUgPSB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gbWVudUxpc3Q7XHJcbiAgICB9O1xyXG5cclxuICAgIC8qKlxyXG4gICAgKiBDYWxjdWxhdGUgdGhlIHJlYWwgcG9zaXRpb24gb2YgYW4gZWxlbWVudCwgZGVwZW5kaW5nIG9uIGRlY2xhcmVkIG9mZnNldCBpbiBwcm9wcy5cclxuICAgICogQHByaXZhdGVcclxuICAgICogQHBhcmFtICB7bnVtYmVyfSBwb3NpdGlvbiBwb3NpdGlvblxyXG4gICAgKiBAcmV0dXJuIHtudW1iZXJ9IHRoZSByZWFsIHBvc2l0aW9uXHJcbiAgICAqL1xyXG4gICAgX2dldEVsZW1lbnRSZWFsUG9zaXRpb24gPSAocG9zaXRpb24pID0+IHtcclxuICAgICAgICBjb25zdCBzc2NEb21Ob2RlID0gUmVhY3RET00uZmluZERPTU5vZGUodGhpcyk7XHJcbiAgICAgICAgY29uc3Qgc3NjUG9zaXRpb24gPSB0aGlzLnNjcm9sbFBvc2l0aW9uKHNzY0RvbU5vZGUpO1xyXG4gICAgICAgIHJldHVybiBwb3NpdGlvbiAtIHNzY1Bvc2l0aW9uLnRvcDtcclxuICAgIH07XHJcblxyXG4gICAgLyoqXHJcbiAgICAqIENhbGN1bGF0ZSBtZW51IHBvc2l0aW9uIChhZmZpeCBvciBub3QpXHJcbiAgICAqIEBwcml2YXRlXHJcbiAgICAqIEByZXR1cm4ge0Jvb2xlYW59IHRydWUgaXMgbWVudSBtdXN0IGJlIGFmZml4LCBlbHNlIGZhbHNlXHJcbiAgICAqL1xyXG4gICAgX2lzTWVudUFmZml4ID0gKCkgPT4ge1xyXG4gICAgICAgIGxldCB7b2Zmc2V0fSA9IHRoaXMucHJvcHM7XHJcbiAgICAgICAgY29uc3Qge2hhc01lbnV9ID0gdGhpcy5wcm9wcztcclxuICAgICAgICBpZighaGFzTWVudSkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHNzY0RvbU5vZGUgPSBSZWFjdERPTS5maW5kRE9NTm9kZSh0aGlzKTtcclxuICAgICAgICBjb25zdCBjdXJyZW50Vmlld1Bvc2l0aW9uID0gc3NjRG9tTm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgICAgICBjb25zdCBjb250YWluZXJQYWRkaW5nVG9wID0gdGhpcy5fZ2V0UGFkZGluZ1RvcFZhbHVlKCk7XHJcbiAgICAgICAgb2Zmc2V0IC09IGNvbnRhaW5lclBhZGRpbmdUb3A7XHJcbiAgICAgICAgcmV0dXJuIGN1cnJlbnRWaWV3UG9zaXRpb24udG9wIDw9IG9mZnNldDtcclxuICAgIH07XHJcblxyXG4gICAgX2dldFBhZGRpbmdUb3BWYWx1ZSA9ICgpID0+IHtcclxuICAgICAgICBjb25zdCBzc2NEb21Ob2RlID0gUmVhY3RET00uZmluZERPTU5vZGUodGhpcyk7XHJcbiAgICAgICAgY29uc3QgY29tcHV0ZWRTdHlsZXMgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShzc2NEb21Ob2RlLCBudWxsKTtcclxuICAgICAgICBjb25zdCBwYWRkaW5nVG9wID0gY29tcHV0ZWRTdHlsZXMuZ2V0UHJvcGVydHlWYWx1ZSgncGFkZGluZy10b3AnKTtcclxuICAgICAgICByZXR1cm4gcGFkZGluZ1RvcCA/IHBhcnNlSW50KHBhZGRpbmdUb3AsIDApIDogMDtcclxuICAgIH07XHJcblxyXG4gICAgLyoqXHJcbiAgICAqIEhhbmRsZSBjbGljayBvbiBpdGVtIG1lbnUgZnVuY3Rpb24uXHJcbiAgICAqIEBwcml2YXRlXHJcbiAgICAqIEBwYXJhbSAge3N0cmluZ30gbWVudUlkICBub2RlIHNweUlkIGluIERPTSB0byBzY3JvbGwgdG9cclxuICAgICogQHJldHVybiB7ZnVuY3Rpb259ICAgICAgICBmdW5jdGlvbiB0byBjYWxsXHJcbiAgICAqL1xyXG4gICAgX2dldE1lbnVJdGVtQ2xpY2tIYW5kbGVyKG1lbnVJZCkge1xyXG4gICAgICAgIHJldHVybiAoKSA9PiB7XHJcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xyXG4gICAgICAgICAgICAgICAgY2xpY2tlZElkOiBtZW51SWRcclxuICAgICAgICAgICAgfSwgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5fcmVmcmVzaE1lbnUoKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuX29uTWVudUl0ZW1DbGljayhtZW51SWQpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAqIE1lbnUgY2xpY2sgZnVuY3Rpb24uIFNjcm9sbCB0byB0aGUgbm9kZSBwb3NpdGlvbi5cclxuICAgICogQHByaXZhdGVcclxuICAgICogQHBhcmFtICB7c3RyaW5nfSBtZW51SWQgIG5vZGUgc3B5SWQgaW4gRE9NIHRvIHNjcm9sbCB0b1xyXG4gICAgKi9cclxuICAgIF9vbk1lbnVJdGVtQ2xpY2sobWVudUlkKSB7XHJcbiAgICAgICAgY29uc3Qgc2VsZWN0b3IgPSBgW2RhdGEtc3B5PScke21lbnVJZH0nXWA7XHJcbiAgICAgICAgY29uc3Qgbm9kZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3IpO1xyXG4gICAgICAgIGNvbnN0IG5vZGVQb3NpdGlvbiA9IHRoaXMuc2Nyb2xsUG9zaXRpb24obm9kZSk7XHJcbiAgICAgICAgY29uc3QgcG9zaXRpb25Ub3AgPSB0aGlzLl9nZXRFbGVtZW50UmVhbFBvc2l0aW9uKG5vZGVQb3NpdGlvbi50b3ApO1xyXG4gICAgICAgIHRoaXMuc2Nyb2xsVG8odW5kZWZpbmVkLCBwb3NpdGlvblRvcCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIEBpbmhlcml0ZWREb2MgKi9cclxuICAgIHJlbmRlcigpIHtcclxuICAgICAgICBjb25zdCB7Y2hpbGRyZW4sIGhhc01lbnUsIGhhc0JhY2tUb1RvcCwgb2Zmc2V0LCBzY3JvbGxEZWxheSwgLi4ub3RoZXJQcm9wc30gPSB0aGlzLnByb3BzO1xyXG4gICAgICAgIGNvbnN0IHthZmZpeCwgbWVudUxpc3R9ID0gdGhpcy5zdGF0ZTtcclxuICAgICAgICByZXR1cm4gKFxyXG4gICAgICAgICAgICA8ZGl2IGRhdGEtZm9jdXM9J3Njcm9sbHNweS1jb250YWluZXInIHsuLi5vdGhlclByb3BzfT5cclxuICAgICAgICAgICAgICAgIHtoYXNNZW51ICYmXHJcbiAgICAgICAgICAgICAgICAgICAgPFN0aWNreU1lbnUgYWZmaXg9e2FmZml4fSBhZmZpeE9mZnNldD17b2Zmc2V0fSBtZW51TGlzdD17bWVudUxpc3R9IHJlZj0nc3RpY2t5TWVudScgLz5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIDxkaXYgZGF0YS1mb2N1cz0nc2Nyb2xsc3B5LWNvbnRhaW5lci1jb250ZW50Jz5cclxuICAgICAgICAgICAgICAgICAgICB7Y2hpbGRyZW59XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgIHtoYXNCYWNrVG9Ub3AgJiZcclxuICAgICAgICAgICAgICAgICAgICA8QmFja1RvVG9wQ29tcG9uZW50IC8+XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcbn1cclxuXHJcbi8vU3RhdGljIHByb3BzLlxyXG5TY3JvbGxzcHlDb250YWluZXIuZGlzcGxheU5hbWUgPSAnU2Nyb2xsc3B5Q29udGFpbmVyJztcclxuU2Nyb2xsc3B5Q29udGFpbmVyLmRlZmF1bHRQcm9wcyA9IGRlZmF1bHRQcm9wcztcclxuU2Nyb2xsc3B5Q29udGFpbmVyLnByb3BUeXBlcyA9IHByb3BUeXBlcztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IFNjcm9sbHNweUNvbnRhaW5lcjtcclxuIl19
;