UNPKG

matrix-react-sdk

Version:
760 lines (734 loc) 132 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.HEADER_HEIGHT = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _classnames = _interopRequireDefault(require("classnames")); var _reResizable = require("re-resizable"); var _react = _interopRequireWildcard(require("react")); var React = _react; var _polyfill = require("../../../@types/polyfill"); var _KeyboardShortcuts = require("../../../accessibility/KeyboardShortcuts"); var _RovingTabIndex = require("../../../accessibility/RovingTabIndex"); var _actions = require("../../../dispatcher/actions"); var _dispatcher = _interopRequireDefault(require("../../../dispatcher/dispatcher")); var _KeyBindingsManager = require("../../../KeyBindingsManager"); var _languageHandler = require("../../../languageHandler"); var _RoomNotificationStateStore = require("../../../stores/notifications/RoomNotificationStateStore"); var _models = require("../../../stores/room-list/algorithms/models"); var _models2 = require("../../../stores/room-list/models"); var _RoomListLayoutStore = _interopRequireDefault(require("../../../stores/room-list/RoomListLayoutStore")); var _RoomListStore = _interopRequireWildcard(require("../../../stores/room-list/RoomListStore")); var _arrays = require("../../../utils/arrays"); var _objects = require("../../../utils/objects"); var _ContextMenu = _interopRequireWildcard(require("../../structures/ContextMenu")); var _AccessibleButton = _interopRequireDefault(require("../../views/elements/AccessibleButton")); var _SettingsStore = _interopRequireDefault(require("../../../settings/SettingsStore")); var _SlidingSyncManager = require("../../../SlidingSyncManager"); var _NotificationBadge = _interopRequireDefault(require("./NotificationBadge")); var _RoomTile = _interopRequireDefault(require("./RoomTile")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /* Copyright 2024 New Vector Ltd. Copyright 2020 The Matrix.org Foundation C.I.C. Copyright 2017, 2018 Vector Creations Ltd Copyright 2015, 2016 OpenMarket Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS const HEADER_HEIGHT = exports.HEADER_HEIGHT = 32; // As defined by CSS const MAX_PADDING_HEIGHT = SHOW_N_BUTTON_HEIGHT + RESIZE_HANDLE_HEIGHT; // HACK: We really shouldn't have to do this. (0, _polyfill.polyfillTouchEvent)(); function getLabelId(tagId) { return `mx_RoomSublist_label_${tagId}`; } // TODO: Use re-resizer's NumberSize when it is exposed as the type class RoomSublist extends React.Component { constructor(props) { super(props); // when this setting is toggled it restarts the app so it's safe to not watch this. (0, _defineProperty2.default)(this, "headerButton", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "sublistRef", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "tilesRef", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "dispatcherRef", void 0); (0, _defineProperty2.default)(this, "layout", void 0); (0, _defineProperty2.default)(this, "heightAtStart", void 0); (0, _defineProperty2.default)(this, "notificationState", void 0); (0, _defineProperty2.default)(this, "slidingSyncMode", void 0); (0, _defineProperty2.default)(this, "onListsLoading", (tagId, isLoading) => { if (this.props.tagId !== tagId) { return; } this.setState({ roomsLoading: isLoading }); }); (0, _defineProperty2.default)(this, "onListsUpdated", () => { const stateUpdates = {}; const currentRooms = this.state.rooms; const newRooms = (0, _arrays.arrayFastClone)(_RoomListStore.default.instance.orderedLists[this.props.tagId] || []); if ((0, _arrays.arrayHasOrderChange)(currentRooms, newRooms)) { stateUpdates.rooms = newRooms; } if (Object.keys(stateUpdates).length > 0) { this.setState(stateUpdates); } }); (0, _defineProperty2.default)(this, "onAction", payload => { if (payload.action === _actions.Action.ViewRoom && payload.show_room_tile && this.state.rooms) { // XXX: we have to do this a tick later because we have incorrect intermediate props during a room change // where we lose the room we are changing from temporarily and then it comes back in an update right after. setTimeout(() => { const roomIndex = this.state.rooms.findIndex(r => r.roomId === payload.room_id); if (!this.state.isExpanded && roomIndex > -1) { this.toggleCollapsed(); } // extend the visible section to include the room if it is entirely invisible if (roomIndex >= this.numVisibleTiles) { this.layout.visibleTiles = this.layout.tilesWithPadding(roomIndex + 1, MAX_PADDING_HEIGHT); this.forceUpdate(); // because the layout doesn't trigger a re-render } }, 0); } }); (0, _defineProperty2.default)(this, "onResize", (e, travelDirection, refToElement, delta) => { const newHeight = this.heightAtStart + delta.height; this.applyHeightChange(newHeight); this.setState({ height: newHeight }); }); (0, _defineProperty2.default)(this, "onResizeStart", () => { this.heightAtStart = this.state.height; this.setState({ isResizing: true }); }); (0, _defineProperty2.default)(this, "onResizeStop", (e, travelDirection, refToElement, delta) => { const newHeight = this.heightAtStart + delta.height; this.applyHeightChange(newHeight); this.setState({ isResizing: false, height: newHeight }); }); (0, _defineProperty2.default)(this, "onShowAllClick", async () => { if (this.slidingSyncMode) { const count = _RoomListStore.default.instance.getCount(this.props.tagId); await _SlidingSyncManager.SlidingSyncManager.instance.ensureListRegistered(this.props.tagId, { ranges: [[0, count]] }); } // read number of visible tiles before we mutate it const numVisibleTiles = this.numVisibleTiles; const newHeight = this.layout.tilesToPixelsWithPadding(this.numTiles, this.padding); this.applyHeightChange(newHeight); this.setState({ height: newHeight }, () => { // focus the top-most new room this.focusRoomTile(numVisibleTiles); }); }); (0, _defineProperty2.default)(this, "onShowLessClick", () => { const newHeight = this.layout.tilesToPixelsWithPadding(this.layout.defaultVisibleTiles, this.padding); this.applyHeightChange(newHeight); this.setState({ height: newHeight }); }); (0, _defineProperty2.default)(this, "focusRoomTile", index => { if (!this.sublistRef.current) return; const elements = this.sublistRef.current.querySelectorAll(".mx_RoomTile"); const element = elements && elements[index]; if (element) { element.focus(); } }); (0, _defineProperty2.default)(this, "onOpenMenuClick", ev => { ev.preventDefault(); ev.stopPropagation(); const target = ev.target; this.setState({ contextMenuPosition: target.getBoundingClientRect() }); }); (0, _defineProperty2.default)(this, "onContextMenu", ev => { ev.preventDefault(); ev.stopPropagation(); this.setState({ contextMenuPosition: { left: ev.clientX, top: ev.clientY, height: 0 } }); }); (0, _defineProperty2.default)(this, "onCloseMenu", () => { this.setState({ contextMenuPosition: undefined }); }); (0, _defineProperty2.default)(this, "onUnreadFirstChanged", () => { const isUnreadFirst = _RoomListStore.default.instance.getListOrder(this.props.tagId) === _models.ListAlgorithm.Importance; const newAlgorithm = isUnreadFirst ? _models.ListAlgorithm.Natural : _models.ListAlgorithm.Importance; _RoomListStore.default.instance.setListOrder(this.props.tagId, newAlgorithm); this.forceUpdate(); // because if the sublist doesn't have any changes then we will miss the list order change }); (0, _defineProperty2.default)(this, "onTagSortChanged", async sort => { _RoomListStore.default.instance.setTagSorting(this.props.tagId, sort); this.forceUpdate(); }); (0, _defineProperty2.default)(this, "onMessagePreviewChanged", () => { this.layout.showPreviews = !this.layout.showPreviews; this.forceUpdate(); // because the layout doesn't trigger a re-render }); (0, _defineProperty2.default)(this, "onBadgeClick", ev => { ev.preventDefault(); ev.stopPropagation(); let room; if (this.props.tagId === _models2.DefaultTagID.Invite) { // switch to first room as that'll be the top of the list for the user room = this.state.rooms && this.state.rooms[0]; } else { // find the first room with a count of the same colour as the badge count room = _RoomListStore.default.instance.orderedLists[this.props.tagId].find(r => { const notifState = this.notificationState.getForRoom(r); return notifState.count > 0 && notifState.level === this.notificationState.level; }); } if (room) { _dispatcher.default.dispatch({ action: _actions.Action.ViewRoom, room_id: room.roomId, show_room_tile: true, // to make sure the room gets scrolled into view metricsTrigger: "WebRoomListNotificationBadge", metricsViaKeyboard: ev.type !== "click" }); } }); (0, _defineProperty2.default)(this, "onHeaderClick", () => { const possibleSticky = this.headerButton.current?.parentElement; const sublist = possibleSticky?.parentElement?.parentElement; const list = sublist?.parentElement?.parentElement; if (!possibleSticky || !list) return; // the scrollTop is capped at the height of the header in LeftPanel, the top header is always sticky const listScrollTop = Math.round(list.scrollTop); const isAtTop = listScrollTop <= Math.round(HEADER_HEIGHT); const isAtBottom = listScrollTop >= Math.round(list.scrollHeight - list.offsetHeight); const isStickyTop = possibleSticky.classList.contains("mx_RoomSublist_headerContainer_stickyTop"); const isStickyBottom = possibleSticky.classList.contains("mx_RoomSublist_headerContainer_stickyBottom"); if (isStickyBottom && !isAtBottom || isStickyTop && !isAtTop) { // is sticky - jump to list sublist.scrollIntoView({ behavior: "smooth" }); } else { // on screen - toggle collapse const isExpanded = this.state.isExpanded; this.toggleCollapsed(); // if the bottom list is collapsed then scroll it in so it doesn't expand off screen if (!isExpanded && isStickyBottom) { setTimeout(() => { sublist.scrollIntoView({ behavior: "smooth" }); }, 0); } } }); (0, _defineProperty2.default)(this, "toggleCollapsed", () => { if (this.props.forceExpanded) return; this.layout.isCollapsed = this.state.isExpanded; this.setState({ isExpanded: !this.layout.isCollapsed }); if (this.props.onListCollapse) { this.props.onListCollapse(!this.layout.isCollapsed); } }); (0, _defineProperty2.default)(this, "onHeaderKeyDown", ev => { const action = (0, _KeyBindingsManager.getKeyBindingsManager)().getRoomListAction(ev); switch (action) { case _KeyboardShortcuts.KeyBindingAction.CollapseRoomListSection: ev.stopPropagation(); if (this.state.isExpanded) { // Collapse the room sublist if it isn't already this.toggleCollapsed(); } break; case _KeyboardShortcuts.KeyBindingAction.ExpandRoomListSection: { ev.stopPropagation(); if (!this.state.isExpanded) { // Expand the room sublist if it isn't already this.toggleCollapsed(); } else if (this.sublistRef.current) { // otherwise focus the first room const element = this.sublistRef.current.querySelector(".mx_RoomTile"); if (element) { element.focus(); } } break; } } }); (0, _defineProperty2.default)(this, "onKeyDown", ev => { const action = (0, _KeyBindingsManager.getKeyBindingsManager)().getAccessibilityAction(ev); switch (action) { // On ArrowLeft go to the sublist header case _KeyboardShortcuts.KeyBindingAction.ArrowLeft: ev.stopPropagation(); this.headerButton.current?.focus(); break; // Consume ArrowRight so it doesn't cause focus to get sent to composer case _KeyboardShortcuts.KeyBindingAction.ArrowRight: ev.stopPropagation(); } }); this.slidingSyncMode = _SettingsStore.default.getValue("feature_sliding_sync"); this.layout = _RoomListLayoutStore.default.instance.getLayoutFor(this.props.tagId); this.heightAtStart = 0; this.notificationState = _RoomNotificationStateStore.RoomNotificationStateStore.instance.getListState(this.props.tagId); this.state = { isResizing: false, isExpanded: !this.layout.isCollapsed, height: 0, // to be fixed in a moment, we need `rooms` to calculate this. rooms: (0, _arrays.arrayFastClone)(_RoomListStore.default.instance.orderedLists[this.props.tagId] || []), roomsLoading: false }; // Why Object.assign() and not this.state.height? Because TypeScript says no. this.state = Object.assign(this.state, { height: this.calculateInitialHeight() }); } calculateInitialHeight() { const requestedVisibleTiles = Math.max(Math.floor(this.layout.visibleTiles), this.layout.minVisibleTiles); const tileCount = Math.min(this.numTiles, requestedVisibleTiles); return this.layout.tilesToPixelsWithPadding(tileCount, this.padding); } get padding() { let padding = RESIZE_HANDLE_HEIGHT; // this is used for calculating the max height of the whole container, // and takes into account whether there should be room reserved for the show more/less button // when fully expanded. We can't rely purely on the layout's defaultVisible tile count // because there are conditions in which we need to know that the 'show more' button // is present while well under the default tile limit. const needsShowMore = this.numTiles > this.numVisibleTiles; // ...but also check this or we'll miss if the section is expanded and we need a // 'show less' const needsShowLess = this.numTiles > this.layout.defaultVisibleTiles; if (needsShowMore || needsShowLess) { padding += SHOW_N_BUTTON_HEIGHT; } return padding; } get extraTiles() { return this.props.extraTiles ?? null; } get numTiles() { return RoomSublist.calcNumTiles(this.state.rooms, this.extraTiles); } static calcNumTiles(rooms, extraTiles) { return (rooms || []).length + (extraTiles || []).length; } get numVisibleTiles() { if (this.slidingSyncMode) { return this.state.rooms.length; } const nVisible = Math.ceil(this.layout.visibleTiles); return Math.min(nVisible, this.numTiles); } componentDidUpdate(prevProps, prevState) { const prevExtraTiles = prevProps.extraTiles; // as the rooms can come in one by one we need to reevaluate // the amount of available rooms to cap the amount of requested visible rooms by the layout if (RoomSublist.calcNumTiles(prevState.rooms, prevExtraTiles) !== this.numTiles) { this.setState({ height: this.calculateInitialHeight() }); } } shouldComponentUpdate(nextProps, nextState) { if ((0, _objects.objectHasDiff)(this.props, nextProps)) { // Something we don't care to optimize has updated, so update. return true; } // Do the same check used on props for state, without the rooms we're going to no-op const prevStateNoRooms = (0, _objects.objectExcluding)(this.state, ["rooms"]); const nextStateNoRooms = (0, _objects.objectExcluding)(nextState, ["rooms"]); if ((0, _objects.objectHasDiff)(prevStateNoRooms, nextStateNoRooms)) { return true; } // If we're supposed to handle extra tiles, take the performance hit and re-render all the // time so we don't have to consider them as part of the visible room optimization. const prevExtraTiles = this.props.extraTiles || []; const nextExtraTiles = nextProps.extraTiles || []; if (prevExtraTiles.length > 0 || nextExtraTiles.length > 0) { return true; } // If we're about to update the height of the list, we don't really care about which rooms // are visible or not for no-op purposes, so ensure that the height calculation runs through. if (RoomSublist.calcNumTiles(nextState.rooms, nextExtraTiles) !== this.numTiles) { return true; } // Before we go analyzing the rooms, we can see if we're collapsed. If we're collapsed, we don't need // to render anything. We do this after the height check though to ensure that the height gets appropriately // calculated for when/if we become uncollapsed. if (!nextState.isExpanded) { return false; } // Quickly double check we're not about to break something due to the number of rooms changing. if (this.state.rooms.length !== nextState.rooms.length) { return true; } // Finally, determine if the room update (as presumably that's all that's left) is within // our visible range. If it is, then do a render. If the update is outside our visible range // then we can skip the update. // // We also optimize for order changing here: if the update did happen in our visible range // but doesn't result in the list re-sorting itself then there's no reason for us to update // on our own. const prevSlicedRooms = this.state.rooms.slice(0, this.numVisibleTiles); const nextSlicedRooms = nextState.rooms.slice(0, this.numVisibleTiles); if ((0, _arrays.arrayHasOrderChange)(prevSlicedRooms, nextSlicedRooms)) { return true; } // Finally, nothing happened so no-op the update return false; } componentDidMount() { this.dispatcherRef = _dispatcher.default.register(this.onAction); _RoomListStore.default.instance.on(_RoomListStore.LISTS_UPDATE_EVENT, this.onListsUpdated); _RoomListStore.default.instance.on(_RoomListStore.LISTS_LOADING_EVENT, this.onListsLoading); // Using the passive option to not block the main thread // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners this.tilesRef.current?.addEventListener("scroll", this.onScrollPrevent, { passive: true }); } componentWillUnmount() { if (this.dispatcherRef) _dispatcher.default.unregister(this.dispatcherRef); _RoomListStore.default.instance.off(_RoomListStore.LISTS_UPDATE_EVENT, this.onListsUpdated); _RoomListStore.default.instance.off(_RoomListStore.LISTS_LOADING_EVENT, this.onListsLoading); this.tilesRef.current?.removeEventListener("scroll", this.onScrollPrevent); } applyHeightChange(newHeight) { const heightInTiles = Math.ceil(this.layout.pixelsToTiles(newHeight - this.padding)); this.layout.visibleTiles = Math.min(this.numTiles, heightInTiles); } renderVisibleTiles() { if (!this.state.isExpanded && !this.props.forceExpanded) { // don't waste time on rendering return []; } const tiles = []; if (this.state.rooms) { let visibleRooms = this.state.rooms; if (!this.props.forceExpanded) { visibleRooms = visibleRooms.slice(0, this.numVisibleTiles); } for (const room of visibleRooms) { tiles.push( /*#__PURE__*/React.createElement(_RoomTile.default, { room: room, key: `room-${room.roomId}`, showMessagePreview: this.layout.showPreviews, isMinimized: this.props.isMinimized, tag: this.props.tagId })); } } if (this.extraTiles) { // HACK: We break typing here, but this 'extra tiles' property shouldn't exist. tiles.push(...this.extraTiles); } // We only have to do this because of the extra tiles. We do it conditionally // to avoid spending cycles on slicing. It's generally fine to do this though // as users are unlikely to have more than a handful of tiles when the extra // tiles are used. if (tiles.length > this.numVisibleTiles && !this.props.forceExpanded) { return tiles.slice(0, this.numVisibleTiles); } return tiles; } renderMenu() { if (this.props.tagId === _models2.DefaultTagID.Suggested) return null; // not sortable let contextMenu; if (this.state.contextMenuPosition) { let isAlphabetical = _RoomListStore.default.instance.getTagSorting(this.props.tagId) === _models.SortAlgorithm.Alphabetic; let isUnreadFirst = _RoomListStore.default.instance.getListOrder(this.props.tagId) === _models.ListAlgorithm.Importance; if (this.slidingSyncMode) { const slidingList = _SlidingSyncManager.SlidingSyncManager.instance.slidingSync?.getListParams(this.props.tagId); isAlphabetical = (slidingList?.sort || [])[0] === "by_name"; isUnreadFirst = (slidingList?.sort || [])[0] === "by_notification_level"; } // Invites don't get some nonsense options, so only add them if we have to. let otherSections; if (this.props.tagId !== _models2.DefaultTagID.Invite) { otherSections = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("hr", null), /*#__PURE__*/React.createElement("fieldset", null, /*#__PURE__*/React.createElement("legend", { className: "mx_RoomSublist_contextMenu_title" }, (0, _languageHandler._t)("common|appearance")), /*#__PURE__*/React.createElement(_ContextMenu.StyledMenuItemCheckbox, { onClose: this.onCloseMenu, onChange: this.onUnreadFirstChanged, checked: isUnreadFirst }, (0, _languageHandler._t)("room_list|sort_unread_first")), /*#__PURE__*/React.createElement(_ContextMenu.StyledMenuItemCheckbox, { onClose: this.onCloseMenu, onChange: this.onMessagePreviewChanged, checked: this.layout.showPreviews }, (0, _languageHandler._t)("room_list|show_previews")))); } contextMenu = /*#__PURE__*/React.createElement(_ContextMenu.default, { chevronFace: _ContextMenu.ChevronFace.None, left: this.state.contextMenuPosition.left, top: this.state.contextMenuPosition.top + this.state.contextMenuPosition.height, onFinished: this.onCloseMenu }, /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_contextMenu" }, /*#__PURE__*/React.createElement("fieldset", null, /*#__PURE__*/React.createElement("legend", { className: "mx_RoomSublist_contextMenu_title" }, (0, _languageHandler._t)("room_list|sort_by")), /*#__PURE__*/React.createElement(_ContextMenu.StyledMenuItemRadio, { onClose: this.onCloseMenu, onChange: () => this.onTagSortChanged(_models.SortAlgorithm.Recent), checked: !isAlphabetical, name: `mx_${this.props.tagId}_sortBy` }, (0, _languageHandler._t)("room_list|sort_by_activity")), /*#__PURE__*/React.createElement(_ContextMenu.StyledMenuItemRadio, { onClose: this.onCloseMenu, onChange: () => this.onTagSortChanged(_models.SortAlgorithm.Alphabetic), checked: isAlphabetical, name: `mx_${this.props.tagId}_sortBy` }, (0, _languageHandler._t)("room_list|sort_by_alphabet"))), otherSections)); } return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_ContextMenu.ContextMenuTooltipButton, { className: "mx_RoomSublist_menuButton", onClick: this.onOpenMenuClick, title: (0, _languageHandler._t)("room_list|sublist_options"), isExpanded: !!this.state.contextMenuPosition }), contextMenu); } renderHeader() { return /*#__PURE__*/React.createElement(_RovingTabIndex.RovingTabIndexWrapper, { inputRef: this.headerButton }, ({ onFocus, isActive, ref }) => { const tabIndex = isActive ? 0 : -1; let ariaLabel = (0, _languageHandler._t)("a11y_jump_first_unread_room"); if (this.props.tagId === _models2.DefaultTagID.Invite) { ariaLabel = (0, _languageHandler._t)("a11y|jump_first_invite"); } const badge = /*#__PURE__*/React.createElement(_NotificationBadge.default, { hideIfDot: true, notification: this.notificationState, onClick: this.onBadgeClick, tabIndex: tabIndex, "aria-label": ariaLabel, showUnsentTooltip: true }); let addRoomButton; if (this.props.AuxButtonComponent) { const AuxButtonComponent = this.props.AuxButtonComponent; addRoomButton = /*#__PURE__*/React.createElement(AuxButtonComponent, { tabIndex: tabIndex }); } const collapseClasses = (0, _classnames.default)({ mx_RoomSublist_collapseBtn: true, mx_RoomSublist_collapseBtn_collapsed: !this.state.isExpanded && !this.props.forceExpanded }); const classes = (0, _classnames.default)({ mx_RoomSublist_headerContainer: true, mx_RoomSublist_headerContainer_withAux: !!addRoomButton }); const badgeContainer = /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_badgeContainer" }, badge); // Note: the addRoomButton conditionally gets moved around // the DOM depending on whether or not the list is minimized. // If we're minimized, we want it below the header so it // doesn't become sticky. // The same applies to the notification badge. return /*#__PURE__*/React.createElement("div", { className: classes, onKeyDown: this.onHeaderKeyDown, onFocus: onFocus, "aria-label": this.props.label, role: "treeitem", "aria-expanded": this.state.isExpanded, "aria-level": 1, "aria-selected": "false" }, /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_stickableContainer" }, /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_stickable" }, /*#__PURE__*/React.createElement(_AccessibleButton.default, { onFocus: onFocus, ref: ref, tabIndex: tabIndex, className: "mx_RoomSublist_headerText", "aria-expanded": this.state.isExpanded, onClick: this.onHeaderClick, onContextMenu: this.onContextMenu, title: this.props.isMinimized ? this.props.label : undefined }, /*#__PURE__*/React.createElement("span", { className: collapseClasses }), /*#__PURE__*/React.createElement("span", { id: getLabelId(this.props.tagId) }, this.props.label)), this.renderMenu(), this.props.isMinimized ? null : badgeContainer, this.props.isMinimized ? null : addRoomButton)), this.props.isMinimized ? badgeContainer : null, this.props.isMinimized ? addRoomButton : null); }); } onScrollPrevent(e) { // the RoomTile calls scrollIntoView and the browser may scroll a div we do not wish to be scrollable // this fixes https://github.com/vector-im/element-web/issues/14413 e.target.scrollTop = 0; } render() { const visibleTiles = this.renderVisibleTiles(); const hidden = !this.state.rooms.length && !this.props.extraTiles?.length && this.props.alwaysVisible !== true; const classes = (0, _classnames.default)({ mx_RoomSublist: true, mx_RoomSublist_hasMenuOpen: !!this.state.contextMenuPosition, mx_RoomSublist_minimized: this.props.isMinimized, mx_RoomSublist_hidden: hidden }); let content; if (this.state.roomsLoading) { content = /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_skeletonUI" }); } else if (visibleTiles.length > 0 && this.props.forceExpanded) { content = /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_resizeBox mx_RoomSublist_resizeBox_forceExpanded" }, /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_tiles", ref: this.tilesRef }, visibleTiles)); } else if (visibleTiles.length > 0) { const layout = this.layout; // to shorten calls const minTiles = Math.min(layout.minVisibleTiles, this.numTiles); const showMoreAtMinHeight = minTiles < this.numTiles; const minHeightPadding = RESIZE_HANDLE_HEIGHT + (showMoreAtMinHeight ? SHOW_N_BUTTON_HEIGHT : 0); const minTilesPx = layout.tilesToPixelsWithPadding(minTiles, minHeightPadding); const maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, this.padding); const showMoreBtnClasses = (0, _classnames.default)({ mx_RoomSublist_showNButton: true }); // If we're hiding rooms, show a 'show more' button to the user. This button // floats above the resize handle, if we have one present. If the user has all // tiles visible, it becomes 'show less'. let showNButton; const hasMoreSlidingSync = this.slidingSyncMode && _RoomListStore.default.instance.getCount(this.props.tagId) > this.state.rooms.length; if (maxTilesPx > this.state.height || hasMoreSlidingSync) { // the height of all the tiles is greater than the section height: we need a 'show more' button const nonPaddedHeight = this.state.height - RESIZE_HANDLE_HEIGHT - SHOW_N_BUTTON_HEIGHT; const amountFullyShown = Math.floor(nonPaddedHeight / this.layout.tileHeight); let numMissing = this.numTiles - amountFullyShown; if (this.slidingSyncMode) { numMissing = _RoomListStore.default.instance.getCount(this.props.tagId) - amountFullyShown; } const label = (0, _languageHandler._t)("room_list|show_n_more", { count: numMissing }); let showMoreText = /*#__PURE__*/React.createElement("span", { className: "mx_RoomSublist_showNButtonText" }, label); if (this.props.isMinimized) showMoreText = null; showNButton = /*#__PURE__*/React.createElement(_RovingTabIndex.RovingAccessibleButton, { role: "treeitem", onClick: this.onShowAllClick, className: showMoreBtnClasses, "aria-label": label }, /*#__PURE__*/React.createElement("span", { className: "mx_RoomSublist_showMoreButtonChevron mx_RoomSublist_showNButtonChevron" }), showMoreText); } else if (this.numTiles > this.layout.defaultVisibleTiles) { // we have all tiles visible - add a button to show less const label = (0, _languageHandler._t)("room_list|show_less"); let showLessText = /*#__PURE__*/React.createElement("span", { className: "mx_RoomSublist_showNButtonText" }, label); if (this.props.isMinimized) showLessText = null; showNButton = /*#__PURE__*/React.createElement(_RovingTabIndex.RovingAccessibleButton, { role: "treeitem", onClick: this.onShowLessClick, className: showMoreBtnClasses, "aria-label": label }, /*#__PURE__*/React.createElement("span", { className: "mx_RoomSublist_showLessButtonChevron mx_RoomSublist_showNButtonChevron" }), showLessText); } // Figure out if we need a handle const handles = { bottom: true, // the only one we need, but the others must be explicitly false bottomLeft: false, bottomRight: false, left: false, right: false, top: false, topLeft: false, topRight: false }; if (layout.visibleTiles >= this.numTiles && this.numTiles <= layout.minVisibleTiles) { // we're at a minimum, don't have a bottom handle handles.bottom = false; } // We have to account for padding so we can accommodate a 'show more' button and // the resize handle, which are pinned to the bottom of the container. This is the // easiest way to have a resize handle below the button as otherwise we're writing // our own resize handling and that doesn't sound fun. // // The layout class has some helpers for dealing with padding, as we don't want to // apply it in all cases. If we apply it in all cases, the resizing feels like it // goes backwards and can become wildly incorrect (visibleTiles says 18 when there's // only mathematically 7 possible). const handleWrapperClasses = (0, _classnames.default)({ mx_RoomSublist_resizerHandles: true, mx_RoomSublist_resizerHandles_showNButton: !!showNButton }); content = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_reResizable.Resizable, { size: { height: this.state.height }, minHeight: minTilesPx, maxHeight: maxTilesPx, onResizeStart: this.onResizeStart, onResizeStop: this.onResizeStop, onResize: this.onResize, handleWrapperClass: handleWrapperClasses, handleClasses: { bottom: "mx_RoomSublist_resizerHandle" }, className: "mx_RoomSublist_resizeBox", enable: handles }, /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_tiles", ref: this.tilesRef }, visibleTiles), showNButton)); } else if (this.props.showSkeleton && this.state.isExpanded) { content = /*#__PURE__*/React.createElement("div", { className: "mx_RoomSublist_skeletonUI" }); } return /*#__PURE__*/React.createElement("div", { ref: this.sublistRef, className: classes, role: "group", "aria-hidden": hidden, "aria-labelledby": getLabelId(this.props.tagId), onKeyDown: this.onKeyDown }, this.renderHeader(), content); } } exports.default = RoomSublist; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY2xhc3NuYW1lcyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX3JlUmVzaXphYmxlIiwiX3JlYWN0IiwiX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQiLCJSZWFjdCIsIl9wb2x5ZmlsbCIsIl9LZXlib2FyZFNob3J0Y3V0cyIsIl9Sb3ZpbmdUYWJJbmRleCIsIl9hY3Rpb25zIiwiX2Rpc3BhdGNoZXIiLCJfS2V5QmluZGluZ3NNYW5hZ2VyIiwiX2xhbmd1YWdlSGFuZGxlciIsIl9Sb29tTm90aWZpY2F0aW9uU3RhdGVTdG9yZSIsIl9tb2RlbHMiLCJfbW9kZWxzMiIsIl9Sb29tTGlzdExheW91dFN0b3JlIiwiX1Jvb21MaXN0U3RvcmUiLCJfYXJyYXlzIiwiX29iamVjdHMiLCJfQ29udGV4dE1lbnUiLCJfQWNjZXNzaWJsZUJ1dHRvbiIsIl9TZXR0aW5nc1N0b3JlIiwiX1NsaWRpbmdTeW5jTWFuYWdlciIsIl9Ob3RpZmljYXRpb25CYWRnZSIsIl9Sb29tVGlsZSIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIlNIT1dfTl9CVVRUT05fSEVJR0hUIiwiUkVTSVpFX0hBTkRMRV9IRUlHSFQiLCJIRUFERVJfSEVJR0hUIiwiZXhwb3J0cyIsIk1BWF9QQURESU5HX0hFSUdIVCIsInBvbHlmaWxsVG91Y2hFdmVudCIsImdldExhYmVsSWQiLCJ0YWdJZCIsIlJvb21TdWJsaXN0IiwiQ29tcG9uZW50IiwiY29uc3RydWN0b3IiLCJwcm9wcyIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJjcmVhdGVSZWYiLCJpc0xvYWRpbmciLCJzZXRTdGF0ZSIsInJvb21zTG9hZGluZyIsInN0YXRlVXBkYXRlcyIsImN1cnJlbnRSb29tcyIsInN0YXRlIiwicm9vbXMiLCJuZXdSb29tcyIsImFycmF5RmFzdENsb25lIiwiUm9vbUxpc3RTdG9yZSIsImluc3RhbmNlIiwib3JkZXJlZExpc3RzIiwiYXJyYXlIYXNPcmRlckNoYW5nZSIsImtleXMiLCJsZW5ndGgiLCJwYXlsb2FkIiwiYWN0aW9uIiwiQWN0aW9uIiwiVmlld1Jvb20iLCJzaG93X3Jvb21fdGlsZSIsInNldFRpbWVvdXQiLCJyb29tSW5kZXgiLCJmaW5kSW5kZXgiLCJyb29tSWQiLCJyb29tX2lkIiwiaXNFeHBhbmRlZCIsInRvZ2dsZUNvbGxhcHNlZCIsIm51bVZpc2libGVUaWxlcyIsImxheW91dCIsInZpc2libGVUaWxlcyIsInRpbGVzV2l0aFBhZGRpbmciLCJmb3JjZVVwZGF0ZSIsInRyYXZlbERpcmVjdGlvbiIsInJlZlRvRWxlbWVudCIsImRlbHRhIiwibmV3SGVpZ2h0IiwiaGVpZ2h0QXRTdGFydCIsImhlaWdodCIsImFwcGx5SGVpZ2h0Q2hhbmdlIiwiaXNSZXNpemluZyIsInNsaWRpbmdTeW5jTW9kZSIsImNvdW50IiwiZ2V0Q291bnQiLCJTbGlkaW5nU3luY01hbmFnZXIiLCJlbnN1cmVMaXN0UmVnaXN0ZXJlZCIsInJhbmdlcyIsInRpbGVzVG9QaXhlbHNXaXRoUGFkZGluZyIsIm51bVRpbGVzIiwicGFkZGluZyIsImZvY3VzUm9vbVRpbGUiLCJkZWZhdWx0VmlzaWJsZVRpbGVzIiwiaW5kZXgiLCJzdWJsaXN0UmVmIiwiY3VycmVudCIsImVsZW1lbnRzIiwicXVlcnlTZWxlY3RvckFsbCIsImVsZW1lbnQiLCJmb2N1cyIsImV2IiwicHJldmVudERlZmF1bHQiLCJzdG9wUHJvcGFnYXRpb24iLCJ0YXJnZXQiLCJjb250ZXh0TWVudVBvc2l0aW9uIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwibGVmdCIsImNsaWVudFgiLCJ0b3AiLCJjbGllbnRZIiwidW5kZWZpbmVkIiwiaXNVbnJlYWRGaXJzdCIsImdldExpc3RPcmRlciIsIkxpc3RBbGdvcml0aG0iLCJJbXBvcnRhbmNlIiwibmV3QWxnb3JpdGhtIiwiTmF0dXJhbCIsInNldExpc3RPcmRlciIsInNvcnQiLCJzZXRUYWdTb3J0aW5nIiwic2hvd1ByZXZpZXdzIiwicm9vbSIsIkRlZmF1bHRUYWdJRCIsIkludml0ZSIsImZpbmQiLCJub3RpZlN0YXRlIiwibm90aWZpY2F0aW9uU3RhdGUiLCJnZXRGb3JSb29tIiwibGV2ZWwiLCJkZWZhdWx0RGlzcGF0Y2hlciIsImRpc3BhdGNoIiwibWV0cmljc1RyaWdnZXIiLCJtZXRyaWNzVmlhS2V5Ym9hcmQiLCJ0eXBlIiwicG9zc2libGVTdGlja3kiLCJoZWFkZXJCdXR0b24iLCJwYXJlbnRFbGVtZW50Iiwic3VibGlzdCIsImxpc3QiLCJsaXN0U2Nyb2xsVG9wIiwiTWF0aCIsInJvdW5kIiwic2Nyb2xsVG9wIiwiaXNBdFRvcCIsImlzQXRCb3R0b20iLCJzY3JvbGxIZWlnaHQiLCJvZmZzZXRIZWlnaHQiLCJpc1N0aWNreVRvcCIsImNsYXNzTGlzdCIsImNvbnRhaW5zIiwiaXNTdGlja3lCb3R0b20iLCJzY3JvbGxJbnRvVmlldyIsImJlaGF2aW9yIiwiZm9yY2VFeHBhbmRlZCIsImlzQ29sbGFwc2VkIiwib25MaXN0Q29sbGFwc2UiLCJnZXRLZXlCaW5kaW5nc01hbmFnZXIiLCJnZXRSb29tTGlzdEFjdGlvbiIsIktleUJpbmRpbmdBY3Rpb24iLCJDb2xsYXBzZVJvb21MaXN0U2VjdGlvbiIsIkV4cGFuZFJvb21MaXN0U2VjdGlvbiIsInF1ZXJ5U2VsZWN0b3IiLCJnZXRBY2Nlc3NpYmlsaXR5QWN0aW9uIiwiQXJyb3dMZWZ0IiwiQXJyb3dSaWdodCIsIlNldHRpbmdzU3RvcmUiLCJnZXRWYWx1ZSIsIlJvb21MaXN0TGF5b3V0U3RvcmUiLCJnZXRMYXlvdXRGb3IiLCJSb29tTm90aWZpY2F0aW9uU3RhdGVTdG9yZSIsImdldExpc3RTdGF0ZSIsImFzc2lnbiIsImNhbGN1bGF0ZUluaXRpYWxIZWlnaHQiLCJyZXF1ZXN0ZWRWaXNpYmxlVGlsZXMiLCJtYXgiLCJmbG9vciIsIm1pblZpc2libGVUaWxlcyIsInRpbGVDb3VudCIsIm1pbiIsIm5lZWRzU2hvd01vcmUiLCJuZWVkc1Nob3dMZXNzIiwiZXh0cmFUaWxlcyIsImNhbGNOdW1UaWxlcyIsIm5WaXNpYmxlIiwiY2VpbCIsImNvbXBvbmVudERpZFVwZGF0ZSIsInByZXZQcm9wcyIsInByZXZTdGF0ZSIsInByZXZFeHRyYVRpbGVzIiwic2hvdWxkQ29tcG9uZW50VXBkYXRlIiwibmV4dFByb3BzIiwibmV4dFN0YXRlIiwib2JqZWN0SGFzRGlmZiIsInByZXZTdGF0ZU5vUm9vbXMiLCJvYmplY3RFeGNsdWRpbmciLCJuZXh0U3RhdGVOb1Jvb21zIiwibmV4dEV4dHJhVGlsZXMiLCJwcmV2U2xpY2VkUm9vbXMiLCJzbGljZSIsIm5leHRTbGljZWRSb29tcyIsImNvbXBvbmVudERpZE1vdW50IiwiZGlzcGF0Y2hlclJlZiIsInJlZ2lzdGVyIiwib25BY3Rpb24iLCJvbiIsIkxJU1RTX1VQREFURV9FVkVOVCIsIm9uTGlzdHNVcGRhdGVkIiwiTElTVFNfTE9BRElOR19FVkVOVCIsIm9uTGlzdHNMb2FkaW5nIiwidGlsZXNSZWYiLCJhZGRFdmVudExpc3RlbmVyIiwib25TY3JvbGxQcmV2ZW50IiwicGFzc2l2ZSIsImNvbXBvbmVudFdpbGxVbm1vdW50IiwidW5yZWdpc3RlciIsIm9mZiIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJoZWlnaHRJblRpbGVzIiwicGl4ZWxzVG9UaWxlcyIsInJlbmRlclZpc2libGVUaWxlcyIsInRpbGVzIiwidmlzaWJsZVJvb21zIiwicHVzaCIsImNyZWF0ZUVsZW1lbnQiLCJrZXkiLCJzaG93TWVzc2FnZVByZXZpZXciLCJpc01pbmltaXplZCIsInRhZyIsInJlbmRlck1lbnUiLCJTdWdnZXN0ZWQiLCJjb250ZXh0TWVudSIsImlzQWxwaGFiZXRpY2FsIiwiZ2V0VGFnU29ydGluZyIsIlNvcnRBbGdvcml0aG0iLCJBbHBoYWJldGljIiwic2xpZGluZ0xpc3QiLCJzbGlkaW5nU3luYyIsImdldExpc3RQYXJhbXMiLCJvdGhlclNlY3Rpb25zIiwiRnJhZ21lbnQiLCJjbGFzc05hbWUiLCJfdCIsIlN0eWxlZE1lbnVJdGVtQ2hlY2tib3giLCJvbkNsb3NlIiwib25DbG9zZU1lbnUiLCJvbkNoYW5nZSIsIm9uVW5yZWFkRmlyc3RDaGFuZ2VkIiwiY2hlY2tlZCIsIm9uTWVzc2FnZVByZXZpZXdDaGFuZ2VkIiwiY2hldnJvbkZhY2UiLCJDaGV2cm9uRmFjZSIsIk5vbmUiLCJvbkZpbmlzaGVkIiwiU3R5bGVkTWVudUl0ZW1SYWRpbyIsIm9uVGFnU29ydENoYW5nZWQiLCJSZWNlbnQiLCJuYW1lIiwiQ29udGV4dE1lbnVUb29sdGlwQnV0dG9uIiwib25DbGljayIsIm9uT3Blbk1lbnVDbGljayIsInRpdGxlIiwicmVuZGVySGVhZGVyIiwiUm92aW5nVGFiSW5kZXhXcmFwcGVyIiwiaW5wdXRSZWYiLCJvbkZvY3VzIiwiaXNBY3RpdmUiLCJyZWYiLCJ0YWJJbmRleCIsImFyaWFMYWJlbCIsImJhZGdlIiwiaGlkZUlmRG90Iiwibm90aWZpY2F0aW9uIiwib25CYWRnZUNsaWNrIiwic2hvd1Vuc2VudFRvb2x0aXAiLCJhZGRSb29tQnV0dG9uIiwiQXV4QnV0dG9uQ29tcG9uZW50IiwiY29sbGFwc2VDbGFzc2VzIiwiY2xhc3NOYW1lcyIsIm14X1Jvb21TdWJsaXN0X2NvbGxhcHNlQnRuIiwibXhfUm9vbVN1Ymxpc3RfY29sbGFwc2VCdG5fY29sbGFwc2VkIiwiY2xhc3NlcyIsIm14X1Jvb21TdWJsaXN0X2hlYWRlckNvbnRhaW5lciIsIm14X1Jvb21TdWJsaXN0X2hlYWRlckNvbnRhaW5lcl93aXRoQXV4IiwiYmFkZ2VDb250YWluZXIiLCJvbktleURvd24iLCJvbkhlYWRlcktleURvd24iLCJsYWJlbCIsInJvbGUiLCJvbkhlYWRlckNsaWNrIiwib25Db250ZXh0TWVudSIsImlkIiwicmVuZGVyIiwiaGlkZGVuIiwiYWx3YXlzVmlzaWJsZSIsIm14X1Jvb21TdWJsaXN0IiwibXhfUm9vbVN1Ymxpc3RfaGFzTWVudU9wZW4iLCJteF9Sb29tU3VibGlzdF9taW5pbWl6ZWQiLCJteF9Sb29tU3VibGlzdF9oaWRkZW4iLCJjb250ZW50IiwibWluVGlsZXMiLCJzaG93TW9yZUF0TWluSGVpZ2h0IiwibWluSGVpZ2h0UGFkZGluZyIsIm1pblRpbGVzUHgiLCJtYXhUaWxlc1B4Iiwic2hvd01vcmVCdG5DbGFzc2VzIiwibXhfUm9vbVN1Ymxpc3Rfc2hvd05CdXR0b24iLCJzaG93TkJ1dHRvbiIsImhhc01vcmVTbGlkaW5nU3luYyIsIm5vblBhZGRlZEhlaWdodCIsImFtb3VudEZ1bGx5U2hvd24iLCJ0aWxlSGVpZ2h0IiwibnVtTWlzc2luZyIsInNob3dNb3JlVGV4dCIsIlJvdmluZ0FjY2Vzc2libGVCdXR0b24iLCJvblNob3dBbGxDbGljayIsInNob3dMZXNzVGV4dCIsIm9uU2hvd0xlc3NDbGljayIsImhhbmRsZXMiLCJib3R0b20iLCJib3R0b21MZWZ0IiwiYm90dG9tUmlnaHQiLCJyaWdodCIsInRvcExlZnQiLCJ0b3BSaWdodCIsImhhbmRsZVdyYXBwZXJDbGFzc2VzIiwibXhfUm9vbVN1Ymxpc3RfcmVzaXplckhhbmRsZXMiLCJteF9Sb29tU3VibGlzdF9yZXNpemVySGFuZGxlc19zaG93TkJ1dHRvbiIsIlJlc2l6YWJsZSIsInNpemUiLCJtaW5IZWlnaHQiLCJtYXhIZWlnaHQiLCJvblJlc2l6ZVN0YXJ0Iiwib25SZXNpemVTdG9wIiwib25SZXNpemUiLCJoYW5kbGVXcmFwcGVyQ2xhc3MiLCJoYW5kbGVDbGFzc2VzIiwiZW5hYmxlIiwic2hvd1NrZWxldG9uIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdmlld3Mvcm9vbXMvUm9vbVN1Ymxpc3QudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIwIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5Db3B5cmlnaHQgMjAxNywgMjAxOCBWZWN0b3IgQ3JlYXRpb25zIEx0ZFxuQ29weXJpZ2h0IDIwMTUsIDIwMTYgT3Blbk1hcmtldCBMdGRcblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgUm9vbSB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCBjbGFzc05hbWVzIGZyb20gXCJjbGFzc25hbWVzXCI7XG5pbXBvcnQgeyBFbmFibGUsIFJlc2l6YWJsZSB9IGZyb20gXCJyZS1yZXNpemFibGVcIjtcbmltcG9ydCB7IERpcmVjdGlvbiB9IGZyb20gXCJyZS1yZXNpemFibGUvbGliL3Jlc2l6ZXJcIjtcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHsgQ29tcG9uZW50VHlwZSwgY3JlYXRlUmVmLCBSZWFjdENvbXBvbmVudEVsZW1lbnQsIFJlYWN0Tm9kZSB9IGZyb20gXCJyZWFjdFwiO1xuXG5pbXBvcnQgeyBwb2x5ZmlsbFRvdWNoRXZlbnQgfSBmcm9tIFwiLi4vLi4vLi4vQHR5cGVzL3BvbHlmaWxsXCI7XG5pbXBvcnQgeyBLZXlCaW5kaW5nQWN0aW9uIH0gZnJvbSBcIi4uLy4uLy4uL2FjY2Vzc2liaWxpdHkvS2V5Ym9hcmRTaG9ydGN1dHNcIjtcbmltcG9ydCB7IFJvdmluZ0FjY2Vzc2libGVCdXR0b24sIFJvdmluZ1RhYkluZGV4V3JhcHBlciB9IGZyb20gXCIuLi8uLi8uLi9hY2Nlc3NpYmlsaXR5L1JvdmluZ1RhYkluZGV4XCI7XG5pbXBvcnQgeyBBY3Rpb24gfSBmcm9tIFwiLi4vLi4vLi4vZGlzcGF0Y2hlci9hY3Rpb25zXCI7XG5pbXBvcnQgZGVmYXVsdERpc3BhdGNoZXIsIHsgTWF0cml4RGlzcGF0Y2hlciB9IGZyb20gXCIuLi8uLi8uLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCB7IEFjdGlvblBheWxvYWQgfSBmcm9tIFwiLi4vLi4vLi4vZGlzcGF0Y2hlci9wYXlsb2Fkc1wiO1xuaW1wb3J0IHsgVmlld1Jvb21QYXlsb2FkIH0gZnJvbSBcIi4uLy4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHMvVmlld1Jvb21QYXlsb2FkXCI7XG5pbXBvcnQgeyBnZXRLZXlCaW5kaW5nc01hbmFnZXIgfSBmcm9tIFwiLi4vLi4vLi4vS2V5QmluZGluZ3NNYW5hZ2VyXCI7XG5pbXBvcnQgeyBfdCB9IGZyb20gXCIuLi8uLi8uLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCB7IExpc3ROb3RpZmljYXRpb25TdGF0ZSB9IGZyb20gXCIuLi8uLi8uLi9zdG9yZXMvbm90aWZpY2F0aW9ucy9MaXN0Tm90aWZpY2F0aW9uU3RhdGVcIjtcbmltcG9ydCB7IFJvb21Ob3RpZmljYXRpb25TdGF0ZVN0b3JlIH0gZnJvbSBcIi4uLy4uLy4uL3N0b3Jlcy9ub3RpZmljYXRpb25zL1Jvb21Ob3RpZmljYXRpb25TdGF0ZVN0b3JlXCI7XG5pbXBvcnQgeyBMaXN0QWxnb3JpdGhtLCBTb3J0QWxnb3JpdGhtIH0gZnJvbSBcIi4uLy4uLy4uL3N0b3Jlcy9yb29tLWxpc3QvYWxnb3JpdGhtcy9tb2RlbHNcIjtcbmltcG9ydCB7IExpc3RMYXlvdXQgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3Jvb20tbGlzdC9MaXN0TGF5b3V0XCI7XG5pbXBvcnQgeyBEZWZhdWx0VGFnSUQsIFRhZ0lEIH0gZnJvbSBcIi4uLy4uLy4uL3N0b3Jlcy9yb29tLWxpc3QvbW9kZWxzXCI7XG5pbXBvcnQgUm9vbUxpc3RMYXlvdXRTdG9yZSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3Jvb20tbGlzdC9Sb29tTGlzdExheW91dFN0b3JlXCI7XG5pbXBvcnQgUm9vbUxpc3RTdG9yZSwgeyBMSVNUU19VUERBVEVfRVZFTlQsIExJU1RTX0xPQURJTkdfRVZFTlQgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3Jvb20tbGlzdC9Sb29tTGlzdFN0b3JlXCI7XG5pbXBvcnQgeyBhcnJheUZhc3RDbG9uZSwgYXJyYXlIYXNPcmRlckNoYW5nZSB9IGZyb20gXCIuLi8uLi8uLi91dGlscy9hcnJheXNcIjtcbmltcG9ydCB7IG9iamVjdEV4Y2x1ZGluZywgb2JqZWN0SGFzRGlmZiB9IGZyb20gXCIuLi8uLi8uLi91dGlscy9vYmplY3RzXCI7XG5pbXBvcnQgUmVzaXplTm90aWZpZXIgZnJvbSBcIi4uLy4uLy4uL3V0aWxzL1Jlc2l6ZU5vdGlmaWVyXCI7XG5pbXBvcnQgQ29udGV4dE1lbnUsIHtcbiAgICBDaGV2cm9uRmFjZSxcbiAgICBDb250ZXh0TWVudVRvb2x0aXBCdXR0b24sXG4gICAgU3R5bGVkTWVudUl0ZW1DaGVja2JveCxcbiAgICBTdHlsZWRNZW51SXRlbVJhZGlvLFxufSBmcm9tIFwiLi4vLi4vc3RydWN0dXJlcy9Db250ZXh0TWVudVwiO1xuaW1wb3J0IEFjY2Vzc2libGVCdXR0b24sIHsgQnV0dG9uRXZlbnQgfSBmcm9tIFwiLi4vLi4vdmlld3MvZWxlbWVudHMvQWNjZXNzaWJsZUJ1dHRvblwiO1xuaW1wb3J0IEV4dHJhVGlsZSBmcm9tIFwiLi9FeHRyYVRpbGVcIjtcbmltcG9ydCBTZXR0aW5nc1N0b3JlIGZyb20gXCIuLi8uLi8uLi9zZXR0aW5ncy9TZXR0aW5nc1N0b3JlXCI7XG5pbXBvcnQgeyBTbGlkaW5nU3luY01hbmFnZXIgfSBmcm9tIFwiLi4vLi4vLi4vU2xpZGluZ1N5bmNNYW5hZ2VyXCI7XG5pbXBvcnQgTm90aWZpY2F0aW9uQmFkZ2UgZnJvbSBcIi4vTm90aWZpY2F0aW9uQmFkZ2VcIjtcbmltcG9ydCBSb29tVGlsZSBmcm9tIFwiLi9Sb29tVGlsZVwiO1xuXG5jb25zdCBTSE9XX05fQlVUVE9OX0hFSUdIVCA9IDI4OyAvLyBBcyBkZWZpbmVkIGJ5IENTU1xuY29uc3QgUkVTSVpFX0hBTkRMRV9IRUlHSFQgPSA0OyAvLyBBcyBkZWZpbmVkIGJ5IENTU1xuZXhwb3J0IGNvbnN0IEhFQURFUl9IRUlHSFQgPSAzMjsgLy8gQXMgZGVmaW5lZCBieSBDU1NcblxuY29uc3QgTUFYX1BBRERJTkdfSEVJR0hUID0gU0hPV19OX0JVVFRPTl9IRUlHSFQgKyBSRVNJWkVfSEFORExFX0hFSUdIVDtcblxuLy8gSEFDSzogV2UgcmVhbGx5IHNob3VsZG4ndCBoYXZlIHRvIGRvIHRoaXMuXG5wb2x5ZmlsbFRvdWNoRXZlbnQoKTtcblxuZXhwb3J0IGludGVyZmFjZSBJQXV4QnV0dG9uUHJvcHMge1xuICAgIHRhYkluZGV4OiBudW1iZXI7XG4gICAgZGlzcGF0Y2hlcj86IE1hdHJpeERpc3BhdGNoZXI7XG59XG5cbmludGVyZmFjZSBJUHJvcHMge1xuICAgIGZvclJvb21zOiBib29sZWFuO1xuICAgIHN0YXJ0QXNIaWRkZW46IGJvb2xlYW47XG4gICAgbGFiZWw6IHN0cmluZztcbiAgICBBdXhCdXR0b25Db21wb25lbnQ/OiBDb21wb25lbnRUeXBlPElBdXhCdXR0b25Qcm9wcz47XG4gICAgaXNNaW5pbWl6ZWQ6IGJvb2xlYW47XG4gICAgdGFnSWQ6IFRhZ0lEO1xuICAgIHNob3dTa2VsZXRvbj86IGJvb2xlYW47XG4gICAgYWx3YXlzVmlzaWJsZT86IGJvb2xlYW47XG4gICAgZm9yY2VFeHBhbmRlZD86IGJvb2xlYW47XG4gICAgcmVzaXplTm90aWZpZXI6IFJlc2l6ZU5vdGlmaWVyO1xuICAgIGV4dHJhVGlsZXM/OiBSZWFjdENvbXBvbmVudEVsZW1lbnQ8dHlwZW9mIEV4dHJhVGlsZT5bXSB8IG51bGw7XG4gICAgb25MaXN0Q29sbGFwc2U/OiAoaXNFeHBhbmRlZDogYm9vbGVhbikgPT4gdm9pZDtcbn1cblxuZnVuY3Rpb24gZ2V0TGFiZWxJZCh0YWdJZDogVGFnSUQpOiBzdHJpbmcge1xuICAgIHJldHVybiBgbXhfUm9vbVN1Ymxpc3RfbGFiZWxfJHt0YWdJZH1gO1xufVxuXG4vLyBUT0RPOiBVc2UgcmUtcmVzaXplcidzIE51bWJlclNpemUgd2hlbiBpdCBpcyBleHBvc2VkIGFzIHRoZSB0eXBlXG5pbnRlcmZhY2UgUmVzaXplRGVsdGEge1xuICAgIHdpZHRoOiBudW1iZXI7XG4gICAgaGVpZ2h0OiBudW1iZXI7XG59XG5cbnR5cGUgUGFydGlhbERPTVJlY3QgPSBQaWNrPERPTVJlY3QsIFwibGVmdFwiIHwgXCJ0b3BcIiB8IFwiaGVpZ2h0XCI+O1xuXG5pbnRlcmZhY2UgSVN0YXRlIHtcbiAgICBjb250ZXh0TWVudVBvc2l0aW9uPzogUGFydGlhbERPTVJlY3Q7XG4gICAgaXNSZXNpemluZzogYm9vbGVhbjtcbiAgICBpc0V4cGFuZGVkOiBib29sZWFuOyAvLyB1c2VkIGZvciB0aGUgZm9yIGV4cGFuZCBvZiB0aGUgc3VibGlzdCB3aGVuIHRoZSByb29tIGxpc3QgaXMgYmVpbmcgZmlsdGVyZWRcbiAgICBoZWlnaHQ6IG51bWJlcjtcbiAgICByb29tczogUm9vbVtdO1xuICAgIHJvb21zTG9hZGluZzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUm9vbVN1Ymxpc3QgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQ8SVByb3BzLCBJU3RhdGU+IHtcbiAgICBwcml2YXRlIGhlYWRlckJ1dHRvbiA9IGNyZWF0ZVJlZjxIVE1MRGl2RWxlbWVudD4oKTtcbiAgICBwcml2YXRlIHN1Ymxpc3RSZWYgPSBjcmVhdGVSZWY8SFRNTERpdkVsZW1lbnQ+KCk7XG4gICAgcHJpdmF0ZSB0aWxlc1JlZiA9IGNyZWF0ZVJlZjxIVE1MRGl2RWxlbWVudD4oKTtcbiAgICBwcml2YXRlIGRpc3BhdGNoZXJSZWY/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBsYXlvdXQ6IExpc3RMYXlvdXQ7XG4gICAgcHJpdmF0ZSBoZWlnaHRBdFN0YXJ0OiBudW1iZXI7XG4gICAgcHJpdmF0ZSBub3RpZmljYXRpb25TdGF0ZTogTGlzdE5vdGlmaWNhdGlvblN0YXRlO1xuXG4gICAgcHJpdmF0ZSBzbGlkaW5nU3luY01vZGU6IGJvb2xlYW47XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJvcHM6IElQcm9wcykge1xuICAgICAgICBzdXBlcihwcm9wcyk7XG4gICAgICAgIC8vIHdoZW4gdGhpcyBzZXR0aW5nIGlzIHRvZ2dsZWQgaXQgcmVzdGFydHMgdGhlIGFwcCBzbyBpdCdzIHNhZmUgdG8gbm90IHdhdGNoIHRoaXMuXG4gICAgICAgIHRoaXMuc2xpZGluZ1N5bmNNb2RlID0gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcImZlYXR1cmVfc2xpZGluZ19zeW5jXCIpO1xuXG4gICAgICAgIHRoaXMubGF5b3V0ID0gUm9vbUxpc3RMYXlvdXRTdG9yZS5pbnN0YW5jZS5nZXRMYXlvdXRGb3IodGhpcy5wcm9wcy50YWdJZCk7XG4gICAgICAgIHRoaXMuaGVpZ2h0QXRTdGFydCA9IDA7XG4gICAgICAgIHRoaXMubm90aWZpY2F0aW9uU3RhdGUgPSBSb29tTm90aWZpY2F0aW9uU3RhdGVTdG9yZS5pbnN0YW5jZS5nZXRMaXN0U3RhdGUodGhpcy5wcm9wcy50YWdJZCk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBpc1Jlc2l6aW5nOiBmYWxzZSxcbiAgICAgICAgICAgIGlzRXhwYW5kZWQ6ICF0aGlzLmxheW91dC5pc0NvbGxhcHNlZCxcbiAgICAgICAgICAgIGhlaWdodDogMCwgLy8gdG8gYmUgZml4ZWQgaW4gYSBtb21lbnQsIHdlIG5lZWQgYHJvb21zYCB0byBjYWxjdWxhdGUgdGhpcy5cbiAgICAgICAgICAgIHJvb21zOiBhcnJheUZhc3RDbG9uZShSb29tTGlzdFN0b3JlLmluc3RhbmNlLm9yZGVyZWRMaXN0c1t0aGlzLnByb3BzLnRhZ0lkXSB8fCBbXSksXG4gICAgICAgICAgICByb29tc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICB9O1xuICAgICAgICAvLyBXaHkgT2JqZWN0LmFzc2lnbigpIGFuZCBub3QgdGhpcy5zdGF0ZS5oZWlnaHQ/IEJlY2F1c2UgVHlwZVNjcmlwdCBzYXlzIG5vLlxuICAgICAgICB0