mirror of
https://github.com/element-hq/element-web
synced 2024-11-23 09:46:09 +03:00
Merge pull request #2507 from matrix-org/bwindels/roomlistjslayout
Redesign: new layout algorithm for room sublists.
This commit is contained in:
commit
55e0838c82
7 changed files with 379 additions and 73 deletions
|
@ -32,34 +32,13 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
.mx_RoomSubList {
|
||||
min-height: 31px;
|
||||
flex: 0 10000 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.mx_RoomSubList.resized-sized {
|
||||
/*
|
||||
flex-basis to 0 so sublists
|
||||
are not shrinking/growing relative
|
||||
to their content (as would be the case with auto),
|
||||
as this intervenes with sizing an item exactly
|
||||
when not available space is available
|
||||
in the flex container
|
||||
*/
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_nonEmpty {
|
||||
min-height: 74px;
|
||||
|
||||
.mx_AutoHideScrollbar_offset {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_RoomSubList_hidden {
|
||||
flex: none !important;
|
||||
.mx_RoomSubList_nonEmpty .mx_AutoHideScrollbar_offset {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_labelContainer {
|
||||
|
|
|
@ -17,13 +17,14 @@ limitations under the License.
|
|||
|
||||
.mx_RoomList {
|
||||
/* take up remaining space below TopLeftMenu */
|
||||
flex: 1 1 auto;
|
||||
/* use flexbox to layout sublists */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.mx_RoomList .mx_ResizeHandle {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mx_SearchBox {
|
||||
flex: none;
|
||||
}
|
||||
|
|
|
@ -212,6 +212,7 @@ const LeftPanel = React.createClass({
|
|||
<CallPreview ConferenceHandler={VectorConferenceHandler} />
|
||||
<RoomList
|
||||
ref={this.collectRoomList}
|
||||
toolbarShown={this.props.toolbarShown}
|
||||
collapsed={this.props.collapsed}
|
||||
searchFilter={this.state.searchFilter}
|
||||
ConferenceHandler={VectorConferenceHandler} />
|
||||
|
|
|
@ -545,6 +545,7 @@ const LoggedInView = React.createClass({
|
|||
<DragDropContext onDragEnd={this._onDragEnd}>
|
||||
<div ref={this._setResizeContainerRef} className={bodyClasses}>
|
||||
<LeftPanel
|
||||
toolbarShown={!!topBar}
|
||||
collapsed={this.props.collapseLhs || this.state.collapseLhs || false}
|
||||
disabled={this.props.leftDisabled}
|
||||
/>
|
||||
|
|
|
@ -313,6 +313,12 @@ const RoomSubList = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
setHeight: function(height) {
|
||||
if (this.refs.subList) {
|
||||
this.refs.subList.style.height = `${height}px`;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const len = this.props.list.length + this.props.extraTiles.length;
|
||||
if (len) {
|
||||
|
@ -322,13 +328,13 @@ const RoomSubList = React.createClass({
|
|||
"mx_RoomSubList_nonEmpty": len && !this.state.hidden,
|
||||
});
|
||||
if (this.state.hidden) {
|
||||
return <div className={subListClasses}>
|
||||
return <div ref="subList" className={subListClasses}>
|
||||
{this._getHeaderJsx()}
|
||||
</div>;
|
||||
} else {
|
||||
const tiles = this.makeRoomTiles();
|
||||
tiles.push(...this.props.extraTiles);
|
||||
return <div className={subListClasses}>
|
||||
return <div ref="subList" className={subListClasses}>
|
||||
{this._getHeaderJsx()}
|
||||
<IndicatorScrollbar ref="scroller" className="mx_RoomSubList_scroll">
|
||||
{ tiles }
|
||||
|
@ -343,7 +349,7 @@ const RoomSubList = React.createClass({
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomSubList">
|
||||
<div ref="subList" className="mx_RoomSubList">
|
||||
{ this._getHeaderJsx() }
|
||||
{ content }
|
||||
</div>
|
||||
|
|
|
@ -36,7 +36,8 @@ import GroupStore from '../../../stores/GroupStore';
|
|||
import RoomSubList from '../../structures/RoomSubList';
|
||||
import ResizeHandle from '../elements/ResizeHandle';
|
||||
|
||||
import {Resizer, RoomSubListDistributor} from '../../../resizer'
|
||||
import {Resizer} from '../../../resizer'
|
||||
import {Layout, Distributor} from '../../../resizer/distributors/roomsublist2';
|
||||
const HIDE_CONFERENCE_CHANS = true;
|
||||
const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/;
|
||||
|
||||
|
@ -79,6 +80,23 @@ module.exports = React.createClass({
|
|||
const collapsedJson = window.localStorage.getItem("mx_roomlist_collapsed");
|
||||
this.subListSizes = sizesJson ? JSON.parse(sizesJson) : {};
|
||||
this.collapsedState = collapsedJson ? JSON.parse(collapsedJson) : {};
|
||||
this._layoutSections = [];
|
||||
|
||||
this._layout = new Layout((key, size) => {
|
||||
const subList = this._subListRefs[key];
|
||||
if (subList) {
|
||||
subList.setHeight(size);
|
||||
}
|
||||
// update overflow indicators
|
||||
this._checkSubListsOverflow();
|
||||
// don't store height for collapsed sublists
|
||||
if(!this.collapsedState[key]) {
|
||||
this.subListSizes[key] = size;
|
||||
window.localStorage.setItem("mx_roomlist_sizes",
|
||||
JSON.stringify(this.subListSizes));
|
||||
}
|
||||
}, this.subListSizes, this.collapsedState);
|
||||
|
||||
return {
|
||||
isLoadingLeftRooms: false,
|
||||
totalRoomCount: null,
|
||||
|
@ -146,54 +164,38 @@ module.exports = React.createClass({
|
|||
this._delayedRefreshRoomListLoopCount = 0;
|
||||
},
|
||||
|
||||
_onSubListResize: function(newSize, id) {
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
if (typeof newSize === "string") {
|
||||
newSize = Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
if (newSize === null) {
|
||||
delete this.subListSizes[id];
|
||||
} else {
|
||||
this.subListSizes[id] = newSize;
|
||||
}
|
||||
window.localStorage.setItem("mx_roomlist_sizes", JSON.stringify(this.subListSizes));
|
||||
// update overflow indicators
|
||||
this._checkSubListsOverflow();
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
const cfg = {
|
||||
onResized: this._onSubListResize,
|
||||
layout: this._layout,
|
||||
};
|
||||
this.resizer = new Resizer(this.resizeContainer, RoomSubListDistributor, cfg);
|
||||
this.resizer = new Resizer(this.resizeContainer, Distributor, cfg);
|
||||
this.resizer.setClassNames({
|
||||
handle: "mx_ResizeHandle",
|
||||
vertical: "mx_ResizeHandle_vertical",
|
||||
reverse: "mx_ResizeHandle_reverse"
|
||||
});
|
||||
|
||||
// load stored sizes
|
||||
Object.keys(this.subListSizes).forEach((key) => {
|
||||
this._restoreSubListSize(key);
|
||||
});
|
||||
this._layout.update(
|
||||
this._layoutSections,
|
||||
this.resizeContainer && this.resizeContainer.offsetHeight,
|
||||
);
|
||||
this._checkSubListsOverflow();
|
||||
|
||||
this.resizer.attach();
|
||||
window.addEventListener("resize", this.onWindowResize);
|
||||
this.mounted = true;
|
||||
},
|
||||
|
||||
componentDidUpdate: function(prevProps) {
|
||||
this._repositionIncomingCallBox(undefined, false);
|
||||
if (this.props.searchFilter !== prevProps.searchFilter) {
|
||||
// restore sizes
|
||||
Object.keys(this.subListSizes).forEach((key) => {
|
||||
this._restoreSubListSize(key);
|
||||
});
|
||||
this._checkSubListsOverflow();
|
||||
}
|
||||
// if (this.props.searchFilter !== prevProps.searchFilter) {
|
||||
// this._checkSubListsOverflow();
|
||||
// }
|
||||
this._layout.update(
|
||||
this._layoutSections,
|
||||
this.resizeContainer && this.resizeContainer.clientHeight,
|
||||
);
|
||||
// TODO: call layout.setAvailableHeight, window height was changed when bannerShown prop was changed
|
||||
},
|
||||
|
||||
onAction: function(payload) {
|
||||
|
@ -222,6 +224,7 @@ module.exports = React.createClass({
|
|||
componentWillUnmount: function() {
|
||||
this.mounted = false;
|
||||
|
||||
window.removeEventListener("resize", this.onWindowResize);
|
||||
dis.unregister(this.dispatcherRef);
|
||||
if (MatrixClientPeg.get()) {
|
||||
MatrixClientPeg.get().removeListener("Room", this.onRoom);
|
||||
|
@ -251,6 +254,17 @@ module.exports = React.createClass({
|
|||
this._delayedRefreshRoomList.cancelPendingCall();
|
||||
},
|
||||
|
||||
onWindowResize: function() {
|
||||
if (this.mounted && this._layout && this.resizeContainer &&
|
||||
Array.isArray(this._layoutSections)
|
||||
) {
|
||||
this._layout.update(
|
||||
this._layoutSections,
|
||||
this.resizeContainer.offsetHeight
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
onRoom: function(room) {
|
||||
this.updateVisibleRooms();
|
||||
},
|
||||
|
@ -551,22 +565,16 @@ module.exports = React.createClass({
|
|||
this.collapsedState[key] = collapsed;
|
||||
window.localStorage.setItem("mx_roomlist_collapsed", JSON.stringify(this.collapsedState));
|
||||
// load the persisted size configuration of the expanded sub list
|
||||
if (!collapsed) {
|
||||
this._restoreSubListSize(key);
|
||||
if (collapsed) {
|
||||
this._layout.collapseSection(key);
|
||||
} else {
|
||||
this._layout.expandSection(key, this.subListSizes[key]);
|
||||
}
|
||||
// check overflow, as sub lists sizes have changed
|
||||
// important this happens after calling resize above
|
||||
this._checkSubListsOverflow();
|
||||
},
|
||||
|
||||
_restoreSubListSize(key) {
|
||||
const size = this.subListSizes[key];
|
||||
const handle = this.resizer.forHandleWithId(key);
|
||||
if (handle) {
|
||||
handle.resize(size);
|
||||
}
|
||||
},
|
||||
|
||||
// check overflow for scroll indicator gradient
|
||||
_checkSubListsOverflow() {
|
||||
Object.values(this._subListRefs).forEach(l => l.checkOverflow());
|
||||
|
@ -581,6 +589,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
_mapSubListProps: function(subListsProps) {
|
||||
this._layoutSections = [];
|
||||
const defaultProps = {
|
||||
collapsed: this.props.collapsed,
|
||||
isFiltered: !!this.props.searchFilter,
|
||||
|
@ -599,6 +608,7 @@ module.exports = React.createClass({
|
|||
return subListsProps.reduce((components, props, i) => {
|
||||
props = Object.assign({}, defaultProps, props);
|
||||
const isLast = i === subListsProps.length - 1;
|
||||
const len = props.list.length + (props.extraTiles ? props.extraTiles.length : 0);
|
||||
const {key, label, onHeaderClick, ... otherProps} = props;
|
||||
const chosenKey = key || label;
|
||||
const onSubListHeaderClick = (collapsed) => {
|
||||
|
@ -608,7 +618,10 @@ module.exports = React.createClass({
|
|||
}
|
||||
};
|
||||
const startAsHidden = props.startAsHidden || this.collapsedState[chosenKey];
|
||||
|
||||
this._layoutSections.push({
|
||||
id: chosenKey,
|
||||
count: len,
|
||||
});
|
||||
let subList = (<RoomSubList
|
||||
ref={this._subListRef.bind(this, chosenKey)}
|
||||
startAsHidden={startAsHidden}
|
||||
|
|
305
src/resizer/distributors/roomsublist2.js
Normal file
305
src/resizer/distributors/roomsublist2.js
Normal file
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
Copyright 2019 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import FixedDistributor from "./fixed";
|
||||
|
||||
// const allowWhitespace = true;
|
||||
const handleHeight = 1;
|
||||
|
||||
function log() {
|
||||
}
|
||||
|
||||
function clamp(height, min, max) {
|
||||
//log(`clamping ${height} between ${min} and ${max}`);
|
||||
if (height > max) return max;
|
||||
if (height < min) return min;
|
||||
return height;
|
||||
}
|
||||
|
||||
export class Layout {
|
||||
constructor(applyHeight, initialSizes, collapsedState) {
|
||||
this._applyHeight = applyHeight;
|
||||
this._sections = [];
|
||||
this._collapsedState = Object.assign({}, collapsedState);
|
||||
this._availableHeight = 0;
|
||||
// heights stored by section section id
|
||||
this._sectionHeights = Object.assign({}, initialSizes);
|
||||
// in-progress heights, while dragging. Committed on mouse-up.
|
||||
this._heights = [];
|
||||
}
|
||||
|
||||
setAvailableHeight(newSize) {
|
||||
this._availableHeight = newSize;
|
||||
// needs more work
|
||||
this._applyNewSize();
|
||||
}
|
||||
|
||||
expandSection(id, height) {
|
||||
this._collapsedState[id] = false;
|
||||
this._applyNewSize();
|
||||
this.openHandle(id).setHeight(height).finish();
|
||||
}
|
||||
|
||||
collapseSection(id) {
|
||||
this._collapsedState[id] = true;
|
||||
this._applyNewSize();
|
||||
}
|
||||
|
||||
// [{id, count}]
|
||||
update(sections, availableHeight) {
|
||||
if (Number.isFinite(availableHeight)) {
|
||||
this._availableHeight = availableHeight;
|
||||
}
|
||||
const totalHeight = this._getAvailableHeight();
|
||||
this._sections.forEach((section, i) => {
|
||||
if (!this._sectionHeights.hasOwnProperty(section.id)) {
|
||||
this._sectionHeights[section.id] = clamp(
|
||||
totalHeight / this._sections.length,
|
||||
this._getMinHeight(i),
|
||||
this._getMaxHeight(i),
|
||||
);
|
||||
}
|
||||
});
|
||||
this._sections = sections;
|
||||
this._applyNewSize();
|
||||
}
|
||||
|
||||
openHandle(id) {
|
||||
const index = this._getSectionIndex(id);
|
||||
//log(`openHandle resolved ${id} to ${index}`);
|
||||
return new Handle(this, index, this._sectionHeights[id]);
|
||||
}
|
||||
|
||||
_getAvailableHeight() {
|
||||
const nonCollapsedSectionCount = this._sections.reduce((count, section) => {
|
||||
const collapsed = this._collapsedState[section.id];
|
||||
return count + (collapsed ? 0 : 1);
|
||||
}, 0);
|
||||
return this._availableHeight - ((nonCollapsedSectionCount - 1) * handleHeight);
|
||||
}
|
||||
|
||||
_applyNewSize() {
|
||||
const newHeight = this._getAvailableHeight();
|
||||
const currHeight = this._sections.reduce((sum, section) => {
|
||||
return sum + this._sectionHeights[section.id];
|
||||
}, 0);
|
||||
const offset = newHeight - currHeight;
|
||||
this._heights = this._sections.map((section) => this._sectionHeights[section.id]);
|
||||
const sections = this._sections.map((_, i) => i);
|
||||
this._applyOverflow(-offset, sections, true);
|
||||
this._applyHeights();
|
||||
this._commitHeights();
|
||||
}
|
||||
|
||||
_getSectionIndex(id) {
|
||||
return this._sections.findIndex((s) => s.id === id);
|
||||
}
|
||||
|
||||
_getMaxHeight(i) {
|
||||
const section = this._sections[i];
|
||||
const collapsed = this._collapsedState[section.id];
|
||||
|
||||
if (collapsed) {
|
||||
return this._sectionHeight(0);
|
||||
} else {
|
||||
return 100000;
|
||||
// return this._sectionHeight(section.count);
|
||||
}
|
||||
}
|
||||
|
||||
_sectionHeight(count) {
|
||||
return 36 + (count === 0 ? 0 : 4 + (count * 34));
|
||||
}
|
||||
|
||||
_getMinHeight(i) {
|
||||
const section = this._sections[i];
|
||||
const collapsed = this._collapsedState[section.id];
|
||||
const maxItems = collapsed ? 0 : 1;
|
||||
// log("_getMinHeight", i, section);
|
||||
return this._sectionHeight(Math.min(section.count, maxItems));
|
||||
}
|
||||
|
||||
_applyOverflow(overflow, sections, blend) {
|
||||
//log("applyOverflow", overflow, sections);
|
||||
// take the given overflow amount, and applies it to the given sections.
|
||||
// calls itself recursively until it has distributed all the overflow
|
||||
// or run out of unclamped sections.
|
||||
|
||||
const unclampedSections = [];
|
||||
|
||||
let overflowPerSection = blend ? (overflow / sections.length) : overflow;
|
||||
for (const i of sections) {
|
||||
const newHeight = clamp(
|
||||
this._heights[i] - overflowPerSection,
|
||||
this._getMinHeight(i),
|
||||
this._getMaxHeight(i),
|
||||
);
|
||||
if (newHeight == this._heights[i] - overflowPerSection) {
|
||||
unclampedSections.push(i);
|
||||
}
|
||||
// when section is growing, overflow increases?
|
||||
// 100 -= 200 - 300
|
||||
// 100 -= -100
|
||||
// 200
|
||||
overflow -= this._heights[i] - newHeight;
|
||||
// console.log(`this._heights[${i}] (${this._heights[i]}) - newHeight (${newHeight}) = ${this._heights[i] - newHeight}`);
|
||||
// console.log(`changing ${this._heights[i]} to ${newHeight}`);
|
||||
this._heights[i] = newHeight;
|
||||
// console.log(`for section ${i} overflow is ${overflow}`);
|
||||
if (!blend) {
|
||||
overflowPerSection = overflow;
|
||||
if (Math.abs(overflow) < 1.0) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.abs(overflow) > 1.0 && unclampedSections.length > 0) {
|
||||
// we weren't able to distribute all the overflow so recurse and try again
|
||||
// log("recursing with", overflow, unclampedSections);
|
||||
overflow = this._applyOverflow(overflow, unclampedSections, blend);
|
||||
}
|
||||
|
||||
return overflow;
|
||||
}
|
||||
|
||||
_rebalanceAbove(anchor, overflowAbove) {
|
||||
if (Math.abs(overflowAbove) > 1.0) {
|
||||
// log(`trying to rebalance upstream with ${overflowAbove}`);
|
||||
const sections = [];
|
||||
for (let i = anchor - 1; i >= 0; i--) {
|
||||
sections.push(i);
|
||||
}
|
||||
overflowAbove = this._applyOverflow(overflowAbove, sections);
|
||||
}
|
||||
return overflowAbove;
|
||||
}
|
||||
|
||||
_rebalanceBelow(anchor, overflowBelow) {
|
||||
if (Math.abs(overflowBelow) > 1.0) {
|
||||
// log(`trying to rebalance downstream with ${overflowBelow}`);
|
||||
const sections = [];
|
||||
for (let i = anchor + 1; i < this._sections.length; i++) {
|
||||
sections.push(i);
|
||||
}
|
||||
overflowBelow = this._applyOverflow(overflowBelow, sections);
|
||||
//log(`rebalanced downstream with ${overflowBelow}`);
|
||||
}
|
||||
return overflowBelow;
|
||||
}
|
||||
|
||||
// @param offset the amount the anchor is moved from what is stored in _sectionHeights, positive if downwards
|
||||
// if we're clamped, return the offset we should be clamped at.
|
||||
_relayout(anchor = 0, offset = 0, clamped = false) {
|
||||
this._heights = this._sections.map((section) => this._sectionHeights[section.id]);
|
||||
// are these the amounts the items above/below shrank/grew and need to be relayouted?
|
||||
let overflowAbove;
|
||||
let overflowBelow;
|
||||
const maxHeight = this._getMaxHeight(anchor);
|
||||
const minHeight = this._getMinHeight(anchor);
|
||||
// new height > max ?
|
||||
if (this._heights[anchor] + offset > maxHeight) {
|
||||
// we're pulling downwards and clamped
|
||||
// overflowAbove = minus how much are we above max height?
|
||||
overflowAbove = (maxHeight - this._heights[anchor]) - offset;
|
||||
overflowBelow = offset;
|
||||
// log(`pulling downwards clamped at max: ${overflowAbove} ${overflowBelow}`);
|
||||
} else if (this._heights[anchor] + offset < minHeight) { // new height < min?
|
||||
// we're pulling upwards and clamped
|
||||
// overflowAbove = ??? (offset is negative here, so - offset will add)
|
||||
overflowAbove = (minHeight - this._heights[anchor]) - offset;
|
||||
overflowBelow = offset;
|
||||
// log(`pulling upwards clamped at min: ${overflowAbove} ${overflowBelow}`);
|
||||
} else {
|
||||
overflowAbove = 0;
|
||||
overflowBelow = offset;
|
||||
// log(`resizing the anchor: ${overflowAbove} ${overflowBelow}`);
|
||||
}
|
||||
this._heights[anchor] = clamp(this._heights[anchor] + offset, minHeight, maxHeight);
|
||||
|
||||
// these are reassigned the amount of overflow that could not be rebalanced
|
||||
// meaning we dragged the handle too far and it can't follow the cursor anymore
|
||||
overflowAbove = this._rebalanceAbove(anchor, overflowAbove);
|
||||
overflowBelow = this._rebalanceBelow(anchor, overflowBelow);
|
||||
|
||||
if (!clamped) { // to avoid risk of infinite recursion
|
||||
// clamp to avoid overflowing or underflowing the page
|
||||
if (Math.abs(overflowAbove) > 1.0) {
|
||||
// log(`clamping with overflowAbove ${overflowAbove}`);
|
||||
// here we do the layout again with offset - the amount of space we took too much
|
||||
this._relayout(anchor, offset + overflowAbove, true);
|
||||
return offset + overflowAbove;
|
||||
}
|
||||
|
||||
if (Math.abs(overflowBelow) > 1.0) {
|
||||
// here we do the layout again with offset - the amount of space we took too much
|
||||
// log(`clamping with overflowBelow ${overflowBelow}`);
|
||||
this._relayout(anchor, offset - overflowBelow, true);
|
||||
return offset - overflowBelow;
|
||||
}
|
||||
}
|
||||
|
||||
this._applyHeights();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
_applyHeights() {
|
||||
log("updating layout, heights are now", this._heights);
|
||||
// apply the heights
|
||||
for (let i = 0; i < this._sections.length; i++) {
|
||||
const section = this._sections[i];
|
||||
this._applyHeight(section.id, this._heights[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_commitHeights() {
|
||||
this._sections.forEach((section, i) => {
|
||||
this._sectionHeights[section.id] = this._heights[i];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class Handle {
|
||||
constructor(layout, anchor, height) {
|
||||
this._layout = layout;
|
||||
this._anchor = anchor;
|
||||
this._initialHeight = height;
|
||||
}
|
||||
|
||||
setHeight(height) {
|
||||
this._layout._relayout(this._anchor, height - this._initialHeight);
|
||||
return this;
|
||||
}
|
||||
|
||||
finish() {
|
||||
this._layout._commitHeights();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class Distributor extends FixedDistributor {
|
||||
constructor(item, cfg) {
|
||||
super(item);
|
||||
const layout = cfg.layout;
|
||||
this._handle = layout.openHandle(item.id);
|
||||
}
|
||||
|
||||
finish() {
|
||||
this._handle.finish();
|
||||
}
|
||||
|
||||
resize(height) {
|
||||
this._handle.setHeight(height);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue