matrix-react-sdk
Version:
SDK for matrix.org using React
760 lines (734 loc) • 132 kB
JavaScript
"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