From d558ea1dbf8af83fffc488b75d7d973031f54f06 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 19 Dec 2018 23:51:19 +0100 Subject: [PATCH 01/25] WIP --- src/resizer/distributors.js | 19 ++----- src/resizer/item.js | 78 ++++++++++++++++++++++++++ src/resizer/resizer.js | 38 +++++++------ src/resizer/room.js | 107 +++++++++++++++++++++++++++--------- src/resizer/sizer.js | 24 +------- 5 files changed, 188 insertions(+), 78 deletions(-) create mode 100644 src/resizer/item.js diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index caf677a18ff..cb876bf98c4 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -27,20 +27,13 @@ the offset from the container edge of where the mouse cursor is. */ class FixedDistributor { - constructor(sizer, item, id, config) { - this.sizer = sizer; + constructor(item) { this.item = item; - this.id = id; - this.beforeOffset = sizer.getItemOffset(this.item); - this.onResized = config && config.onResized; + this.beforeOffset = item.offset(); } - resize(itemSize) { - this.sizer.setItemSize(this.item, itemSize); - if (this.onResized) { - this.onResized(itemSize, this.id, this.item); - } - return itemSize; + resize(size) { + this.item.setSize(size); } resizeFromContainerOffset(offset) { @@ -50,8 +43,8 @@ class FixedDistributor { class CollapseDistributor extends FixedDistributor { - constructor(sizer, item, id, config) { - super(sizer, item, id, config); + constructor(item, sizer, _container, config) { + super(item); this.toggleSize = config && config.toggleSize; this.onCollapsed = config && config.onCollapsed; this.isCollapsed = false; diff --git a/src/resizer/item.js b/src/resizer/item.js new file mode 100644 index 00000000000..ad508150a5a --- /dev/null +++ b/src/resizer/item.js @@ -0,0 +1,78 @@ +/* +Copyright 2018 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. +*/ + +export default class ResizeItem { + constructor(domNode, id, reverse, resizer, sizer) { + this.domNode = domNode; + this.id = id; + this.reverse = reverse; + this.resizer = resizer; + this.sizer = sizer; + } + + static fromResizeHandle(handle, resizer, sizer) { + const id = handle.getAttribute("data-id"); + const reverse = resizer.isReverseResizeHandle(handle); + const domNode = reverse ? handle.nextElementSibling : handle.previousElementSibling; + return new ResizeItem(domNode, id, reverse, resizer, sizer); + } + + _advance(forwards) { + // opposite direction from fromResizeHandle to get back to handle + let handle = this.reverse ? + this.domNode.previousElementSibling : + this.domNode.nextElementSibling; + const moveNext = forwards !== this.reverse; // xor + // iterate at least once to avoid infinite loop + do { + if (moveNext) { + handle = handle.nextElementSibling; + } else { + handle = handle.previousElementSibling; + } + } while(handle && !this.resizer.isResizeHandle(handle)); + if (handle) { + const nextHandle = ResizeItem.fromResizeHandle(handle, this.resizer, this.sizer); + nextHandle.reverse = this.reverse; + return nextHandle; + } + } + + next() { + return this._advance(true); + } + + previous() { + return this._advance(false); + } + + size() { + return this.sizer.getItemSize(this.domNode); + } + + offset() { + return this.sizer.getItemOffset(this.domNode); + } + + setSize(size) { + this.sizer.setItemSize(this.domNode, size); + console.log("resizing", this.domNode, "to", size, this.size()); + const callback = this.resizer.distributorCtor.onResized; + if (callback) { + callback(size, this.id, this.domNode); + } + } +} diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 0e113b36642..8bdbc6cffea 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -15,6 +15,7 @@ limitations under the License. */ import {Sizer} from "./sizer"; +import ResizeItem from "./item"; /* classNames: @@ -28,7 +29,10 @@ classNames: resizing: string */ + export class Resizer { + // TODO move vertical/horizontal to config option/container class + // as it doesn't make sense to mix them within one container/Resizer constructor(container, distributorCtor, distributorCfg, sizerCtor = Sizer) { this.container = container; this.distributorCtor = distributorCtor; @@ -79,7 +83,11 @@ export class Resizer { } } - _isResizeHandle(el) { + isReverseResizeHandle(el) { + return el && el.classList.contains(this.classNames.reverse); + } + + isResizeHandle(el) { return el && el.classList.contains(this.classNames.handle); } @@ -119,35 +127,29 @@ export class Resizer { _createSizerAndDistributor(resizeHandle) { const vertical = resizeHandle.classList.contains(this.classNames.vertical); - const reverse = resizeHandle.classList.contains(this.classNames.reverse); - + const reverse = this.isReverseResizeHandle(resizeHandle); // eslint-disable-next-line new-cap const sizer = new this.sizerCtor(this.container, vertical, reverse); - - const items = this._getResizableItems(); - const prevItem = resizeHandle.previousElementSibling; - // if reverse, resize the item after the handle instead of before, so + 1 - const itemIndex = items.indexOf(prevItem) + (reverse ? 1 : 0); - const item = items[itemIndex]; - const id = resizeHandle.getAttribute("data-id"); + const item = ResizeItem.fromResizeHandle(resizeHandle, this, sizer); // eslint-disable-next-line new-cap const distributor = new this.distributorCtor( - sizer, item, id, this.distributorCfg, - items, this.container); + item, + sizer, + this.container, + this.distributorCfg + ); return {sizer, distributor}; } - _getResizableItems() { - return Array.from(this.container.children).filter(el => { - return !this._isResizeHandle(el) && ( - this._isResizeHandle(el.previousElementSibling) || - this._isResizeHandle(el.nextElementSibling)); + _getResizableItems(reverse) { + return this._getResizeHandles().map((handle) => { + return ResizeItem.fromResizeHandle(handle); }); } _getResizeHandles() { return Array.from(this.container.children).filter(el => { - return this._isResizeHandle(el); + return this.isResizeHandle(el); }); } } diff --git a/src/resizer/room.js b/src/resizer/room.js index def12d49eb7..fda09940b1d 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -15,42 +15,99 @@ limitations under the License. */ import {Sizer} from "./sizer"; -import {FixedDistributor} from "./distributors"; class RoomSizer extends Sizer { setItemSize(item, size) { - const isString = typeof size === "string"; - const cl = item.classList; - if (isString) { - if (size === "resized-all") { - cl.add("resized-all"); - cl.remove("resized-sized"); - item.style.maxHeight = null; - } + item.style.maxHeight = `${Math.round(size)}px`; + } +} + +/* +class RoomSubList extends ResizeItem { + collapsed() { + + } + + scrollSizes() { + return {offsetHeight, scrollHeight}; + } + + id() { + + } +} +*/ + +const MIN_SIZE = 70; +// would be good to have a way in here to know if the item can be resized +// - collapsed items can't be resized (.mx_RoomSubList_hidden) +// - items at MIN_SIZE can't be resized smaller +// - items at maxContentHeight can't be resized larger + +// if you shrink the predecesor, and start dragging down again afterwards, which item has to grow? + +class RoomDistributor { + constructor(item) { + this.item = item; + } + + _handleSize() { + return 1; + } + + // returns the remainder of size it didn't consume for this item + _sizeItem(item, size) { + // if collapsed, do nothing and subtract own height + if (item.domNode.classList.contains("mx_RoomSubList_hidden")) { + return; + } else if (size < MIN_SIZE) { + item.setSize(MIN_SIZE); } else { - cl.add("resized-sized"); - cl.remove("resized-all"); - item.style.maxHeight = `${Math.round(size)}px`; + const scrollItem = item.domNode.querySelector(".mx_RoomSubList_scroll"); + const headerHeight = item.size() - scrollItem.offsetHeight; + const maxContentHeight = headerHeight + scrollItem.scrollHeight; + // avoid flexbox growing larger than the content height + if (size > maxContentHeight) { + item.setSize(maxContentHeight); + } else { + item.setSize(size); + } } } -} -class RoomDistributor extends FixedDistributor { - resize(itemSize) { - const scrollItem = this.item.querySelector(".mx_RoomSubList_scroll"); - if (!scrollItem) { - return; //FIXME: happens when starting the page on a community url, taking the safe way out for now + resize(size) { + if (size < 0) { + console.log("NEGATIVE SIZE RESIZE RESIZE RESIZE!!!", size); } - const fixedHeight = this.item.offsetHeight - scrollItem.offsetHeight; - if (itemSize > (fixedHeight + scrollItem.scrollHeight)) { - super.resize("resized-all"); - } else { - super.resize(itemSize); + let item = this.item; + // move to item that is at position of cursor + // this would happen if the cursor goes beyond the min-height + while (item && size < 0) { + item = item.previous(); + if (item) { + size = item.size() - size - this._handleSize(); + } + } + // change size of item and previous items from here + while(item && size > 0) { + const itemSize = item.size(); + this._sizeItem(item, size); + const delta = item.size() - itemSize; + const remainder = size - delta; + // pass remainder to previous item + if (remainder !== 0) { + item = item.previous(); + if (item) { + size = item.size() - remainder - this._handleSize(); + } + } else { + item = null; + } } } - resizeFromContainerOffset(offset) { - return this.resize(offset - this.sizer.getItemOffset(this.item)); + resizeFromContainerOffset(containerOffset) { + this.resize(containerOffset - this.item.offset()); } } diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index 303214854be..1cb212e20ac 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -18,31 +18,13 @@ limitations under the License. implements DOM/CSS operations for resizing. The sizer determines what CSS mechanism is used for sizing items, like flexbox, ... */ -class Sizer { +export class Sizer { constructor(container, vertical, reverse) { this.container = container; this.reverse = reverse; this.vertical = vertical; } - getItemPercentage(item) { - /* - const flexGrow = window.getComputedStyle(item).flexGrow; - if (flexGrow === "") { - return null; - } - return parseInt(flexGrow) / 1000; - */ - const style = window.getComputedStyle(item); - const sizeStr = this.vertical ? style.height : style.width; - const size = parseInt(sizeStr, 10); - return size / this.getTotalSize(); - } - - setItemPercentage(item, percent) { - item.style.flexGrow = Math.round(percent * 1000); - } - /** @param {Element} item the dom element being resized @return {number} how far the edge of the item is from the edge of the container @@ -97,11 +79,9 @@ class Sizer { } } -class FlexSizer extends Sizer { +export class FlexSizer extends Sizer { setItemSize(item, size) { item.style.flexGrow = `0`; item.style.flexBasis = `${Math.round(size)}px`; } } - -module.exports = {Sizer, FlexSizer}; From 4bd6ce8e2c2512882cb0c8946f4267543d5a0b71 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 16:47:47 +0100 Subject: [PATCH 02/25] WIP2 for making smart resizer work, sort of works now but shows big scrollbar --- res/css/structures/_RoomSubList.scss | 10 ++-- src/resizer/item.js | 1 - src/resizer/room.js | 72 ++++++++++++++-------------- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 2d471ee198c..04587491a7f 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -33,7 +33,7 @@ limitations under the License. .mx_RoomSubList { min-height: 31px; - flex: 0 100000000 auto; + flex: 0 1 auto; display: flex; flex-direction: column; } @@ -50,15 +50,15 @@ limitations under the License. flex: none !important; } -.mx_RoomSubList.resized-all { - flex: 0 1 auto; -} +// .mx_RoomSubList.resized-all { +// flex: 0 1 auto; +// } .mx_RoomSubList.resized-sized { /* resizer set max-height on resized-sized, so that limits the height and hence needs a very small flex-shrink */ - flex: 0 10000 auto; + flex: 1 0 auto; } .mx_RoomSubList_labelContainer { diff --git a/src/resizer/item.js b/src/resizer/item.js index ad508150a5a..5bee473292c 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -69,7 +69,6 @@ export default class ResizeItem { setSize(size) { this.sizer.setItemSize(this.domNode, size); - console.log("resizing", this.domNode, "to", size, this.size()); const callback = this.resizer.distributorCtor.onResized; if (callback) { callback(size, this.id, this.domNode); diff --git a/src/resizer/room.js b/src/resizer/room.js index fda09940b1d..5f3d8c1e6fb 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -19,6 +19,7 @@ import {Sizer} from "./sizer"; class RoomSizer extends Sizer { setItemSize(item, size) { item.style.maxHeight = `${Math.round(size)}px`; + item.classList.add("resized-sized"); } } @@ -45,7 +46,10 @@ const MIN_SIZE = 70; // - items at maxContentHeight can't be resized larger // if you shrink the predecesor, and start dragging down again afterwards, which item has to grow? - +/* + either items before (starting from first or last) + or +*/ class RoomDistributor { constructor(item) { this.item = item; @@ -55,24 +59,14 @@ class RoomDistributor { return 1; } - // returns the remainder of size it didn't consume for this item - _sizeItem(item, size) { - // if collapsed, do nothing and subtract own height - if (item.domNode.classList.contains("mx_RoomSubList_hidden")) { - return; - } else if (size < MIN_SIZE) { - item.setSize(MIN_SIZE); - } else { - const scrollItem = item.domNode.querySelector(".mx_RoomSubList_scroll"); - const headerHeight = item.size() - scrollItem.offsetHeight; - const maxContentHeight = headerHeight + scrollItem.scrollHeight; - // avoid flexbox growing larger than the content height - if (size > maxContentHeight) { - item.setSize(maxContentHeight); - } else { - item.setSize(size); - } - } + _isCollapsed(item) { + return item.domNode.classList.contains("mx_RoomSubList_hidden"); + } + + _contentSize(item) { + const scrollItem = item.domNode.querySelector(".mx_RoomSubList_scroll"); + const headerHeight = item.size() - scrollItem.offsetHeight; + return headerHeight + scrollItem.scrollHeight; } resize(size) { @@ -80,28 +74,36 @@ class RoomDistributor { console.log("NEGATIVE SIZE RESIZE RESIZE RESIZE!!!", size); } let item = this.item; + + // cache result of this loop? + // move to item that is at position of cursor // this would happen if the cursor goes beyond the min-height - while (item && size < 0) { - item = item.previous(); - if (item) { - size = item.size() - size - this._handleSize(); - } - } - // change size of item and previous items from here - while(item && size > 0) { - const itemSize = item.size(); - this._sizeItem(item, size); - const delta = item.size() - itemSize; - const remainder = size - delta; - // pass remainder to previous item - if (remainder !== 0) { + while (item) { + // TODO: collapsed + if (size <= MIN_SIZE) { + item.setSize(MIN_SIZE); + const remainder = MIN_SIZE - size; item = item.previous(); if (item) { size = item.size() - remainder - this._handleSize(); } - } else { - item = null; + } + else { + const contentSize = this._contentSize(item); + if (size > contentSize) { + item.setSize(contentSize); + const remainder = size - contentSize; + item = item.previous(); + if (item) { + size = item.size() + remainder; // todo: handle size here? + } + } + else { + item.setSize(size); + item = null; + size = 0; + } } } } From b4197059a0103ea34d1f091ceaa82ce3a31bb71e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 18:16:09 +0100 Subject: [PATCH 03/25] change min size to exactly one room tile + header --- res/css/structures/_RoomSubList.scss | 2 +- src/resizer/room.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 04587491a7f..2c44954a535 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -39,7 +39,7 @@ limitations under the License. } .mx_RoomSubList_nonEmpty { - min-height: 70px; + min-height: 74px; .mx_AutoHideScrollbar_offset { padding-bottom: 4px; diff --git a/src/resizer/room.js b/src/resizer/room.js index 5f3d8c1e6fb..c93a2ec3341 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -39,7 +39,7 @@ class RoomSubList extends ResizeItem { } */ -const MIN_SIZE = 70; +const MIN_SIZE = 74; // would be good to have a way in here to know if the item can be resized // - collapsed items can't be resized (.mx_RoomSubList_hidden) // - items at MIN_SIZE can't be resized smaller From 0c364510efa49b41b81ee9e20c1f7bcc6fc813c1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 18:16:37 +0100 Subject: [PATCH 04/25] trying to make the left panel not grow taller than available space --- res/css/structures/_RoomSubList.scss | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 2c44954a535..0d82a7e3da0 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -33,11 +33,15 @@ limitations under the License. .mx_RoomSubList { min-height: 31px; - flex: 0 1 auto; + flex: 0 10000 auto; display: flex; flex-direction: column; } +.mx_RoomSubList.resized-sized { + flex: 1 1 auto; +} + .mx_RoomSubList_nonEmpty { min-height: 74px; @@ -50,17 +54,6 @@ limitations under the License. flex: none !important; } -// .mx_RoomSubList.resized-all { -// flex: 0 1 auto; -// } - -.mx_RoomSubList.resized-sized { - /* resizer set max-height on resized-sized, - so that limits the height and hence - needs a very small flex-shrink */ - flex: 1 0 auto; -} - .mx_RoomSubList_labelContainer { display: flex; flex-direction: row; From 8352d8c6bd63b952e266157beccb117276d5f333 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 18:17:00 +0100 Subject: [PATCH 05/25] not sure we need this, but adding the padding in _offset container --- src/resizer/room.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/room.js b/src/resizer/room.js index c93a2ec3341..c8bc8a26284 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -66,7 +66,7 @@ class RoomDistributor { _contentSize(item) { const scrollItem = item.domNode.querySelector(".mx_RoomSubList_scroll"); const headerHeight = item.size() - scrollItem.offsetHeight; - return headerHeight + scrollItem.scrollHeight; + return headerHeight + scrollItem.scrollHeight + 4; } resize(size) { From 0803ea9158641813e1ec1bc00553af42f58aa20d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 18:17:34 +0100 Subject: [PATCH 06/25] support collapsed items --- src/resizer/room.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/resizer/room.js b/src/resizer/room.js index c8bc8a26284..94c8a114845 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -81,7 +81,10 @@ class RoomDistributor { // this would happen if the cursor goes beyond the min-height while (item) { // TODO: collapsed - if (size <= MIN_SIZE) { + if (this._isCollapsed(item)) { + item = item.previous(); + } + else if (size <= MIN_SIZE) { item.setSize(MIN_SIZE); const remainder = MIN_SIZE - size; item = item.previous(); From b82e19b1f763eb93441ea96c6c5b3e6d8cb83b7b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 9 Jan 2019 15:45:47 +0100 Subject: [PATCH 07/25] size header explicitly for content size otherwise it just grows with max-height --- src/resizer/room.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/resizer/room.js b/src/resizer/room.js index 94c8a114845..51bd0d82d87 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -65,8 +65,9 @@ class RoomDistributor { _contentSize(item) { const scrollItem = item.domNode.querySelector(".mx_RoomSubList_scroll"); - const headerHeight = item.size() - scrollItem.offsetHeight; - return headerHeight + scrollItem.scrollHeight + 4; + const header = item.domNode.querySelector(".mx_RoomSubList_labelContainer"); + const headerHeight = item.sizer.getItemSize(header); + return headerHeight + scrollItem.scrollHeight; } resize(size) { From 51376c5c075199aa2cad74aeaef32e6be77703da Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 9 Jan 2019 15:53:04 +0100 Subject: [PATCH 08/25] draft room sub list item api --- src/resizer/room.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/resizer/room.js b/src/resizer/room.js index 51bd0d82d87..1de59d6be7e 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -29,11 +29,15 @@ class RoomSubList extends ResizeItem { } - scrollSizes() { - return {offsetHeight, scrollHeight}; + id() { + } - id() { + maxSize() { + + } + + minSize() { } } From 68afadd83bc1627cc1c958480c8e0473c496c4d6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 10 Jan 2019 14:03:17 +0100 Subject: [PATCH 09/25] try flex-basis for resizing --- src/resizer/room.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/room.js b/src/resizer/room.js index 1de59d6be7e..692354530c0 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -18,7 +18,7 @@ import {Sizer} from "./sizer"; class RoomSizer extends Sizer { setItemSize(item, size) { - item.style.maxHeight = `${Math.round(size)}px`; + item.style.flexBasis = `${Math.round(size)}px`; item.classList.add("resized-sized"); } } From 1a2727f0afffa96571664ba59ac6a963176a9ee6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 10 Jan 2019 14:03:55 +0100 Subject: [PATCH 10/25] sized items cannot grow, unsized items start with their content size and shrink from there --- res/css/structures/_RoomSubList.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 0d82a7e3da0..8225e1208ca 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -33,13 +33,13 @@ limitations under the License. .mx_RoomSubList { min-height: 31px; - flex: 0 10000 auto; + flex: 0 10000 content; display: flex; flex-direction: column; } .mx_RoomSubList.resized-sized { - flex: 1 1 auto; + flex: 0 1 0; } .mx_RoomSubList_nonEmpty { From a130c448036e13c5c0068d37fa2b0039e1e119c6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 10 Jan 2019 14:05:00 +0100 Subject: [PATCH 11/25] try clear next item size when resizing so there is always one unsized item --- src/resizer/item.js | 4 ++++ src/resizer/room.js | 52 ++++++++++++++++++++++++++++++++++++-------- src/resizer/sizer.js | 8 +++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/resizer/item.js b/src/resizer/item.js index 5bee473292c..8b5b7ead444 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -74,4 +74,8 @@ export default class ResizeItem { callback(size, this.id, this.domNode); } } + + clearSize() { + this.sizer.clearItemSize(this.domNode); + } } diff --git a/src/resizer/room.js b/src/resizer/room.js index 692354530c0..d56816e711d 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -20,6 +20,15 @@ class RoomSizer extends Sizer { setItemSize(item, size) { item.style.flexBasis = `${Math.round(size)}px`; item.classList.add("resized-sized"); + // const total = this.getTotalSize(); + // const percent = size / total; + // const growFactor = Math.round(1 + (percent * 100)); + // item.style.flexGrow = `${growFactor}`; + } + + clearItemSize(item) { + item.style.flexBasis = null; + item.classList.remove("resized-sized"); } } @@ -74,16 +83,41 @@ class RoomDistributor { return headerHeight + scrollItem.scrollHeight; } - resize(size) { - if (size < 0) { - console.log("NEGATIVE SIZE RESIZE RESIZE RESIZE!!!", size); - } - let item = this.item; + _isSized(item) { + return item.domNode.classList.contains("resized-sized"); + } - // cache result of this loop? + resize(size, interactive = false) { + // console.log("*** starting resize session with size", size); + + // grow/shrink items after first? + // const itemSize = this.item.size(); + // // + // if (size < itemSize) { + // let nextItem = this.item.next(); + // while (nextItem) + // } + + if (false && interactive) { + const nextItem = this.item.next(); + if (nextItem) { + // let item = nextItem; + // let hasUnsizedProceedingItem = false; + // while (item) { + // if (this._isSized(item)) { + // hasUnsizedProceedingItem = true; + // item = null; + // } else { + // item = item.next(); + // } + // } + // if (!hasUnsizedProceedingItem) { + nextItem.clearSize(); + // } + } + } - // move to item that is at position of cursor - // this would happen if the cursor goes beyond the min-height + let item = this.item; while (item) { // TODO: collapsed if (this._isCollapsed(item)) { @@ -117,7 +151,7 @@ class RoomDistributor { } resizeFromContainerOffset(containerOffset) { - this.resize(containerOffset - this.item.offset()); + this.resize(containerOffset - this.item.offset(), true); } } diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index 1cb212e20ac..cdb11f32704 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -64,6 +64,14 @@ export class Sizer { } } + clearItemSize(item) { + if (this.vertical) { + item.style.height = null; + } else { + item.style.width = null; + } + } + /** @param {MouseEvent} event the mouse event @return {number} the distance between the cursor and the edge of the container, From 92b9a8cc1f5610b82bfd05a699dbc1802ef82af1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 10 Jan 2019 18:40:26 +0100 Subject: [PATCH 12/25] persist cleared size sublists --- src/components/views/rooms/RoomList.js | 8 ++++++-- src/resizer/item.js | 4 ++++ src/resizer/room.js | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index dbfe95dadf6..636000c1754 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -152,7 +152,11 @@ module.exports = React.createClass({ if (typeof newSize === "string") { newSize = Number.MAX_SAFE_INTEGER; } - this.subListSizes[id] = newSize; + 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(); @@ -716,4 +720,4 @@ module.exports = React.createClass({ ); }, -}); \ No newline at end of file +}); diff --git a/src/resizer/item.js b/src/resizer/item.js index 8b5b7ead444..13932f91708 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -77,5 +77,9 @@ export default class ResizeItem { clearSize() { this.sizer.clearItemSize(this.domNode); + const callback = this.resizer.distributorCtor.onResized; + if (callback) { + callback(null, this.id, this.domNode); + } } } diff --git a/src/resizer/room.js b/src/resizer/room.js index d56816e711d..59f47f31fce 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -98,7 +98,7 @@ class RoomDistributor { // while (nextItem) // } - if (false && interactive) { + if (interactive) { const nextItem = this.item.next(); if (nextItem) { // let item = nextItem; @@ -124,6 +124,7 @@ class RoomDistributor { item = item.previous(); } else if (size <= MIN_SIZE) { + // console.log(" - resizing", item.id, "to min size", MIN_SIZE); item.setSize(MIN_SIZE); const remainder = MIN_SIZE - size; item = item.previous(); @@ -134,6 +135,7 @@ class RoomDistributor { else { const contentSize = this._contentSize(item); if (size > contentSize) { + // console.log(" - resizing", item.id, "to contentSize", contentSize); item.setSize(contentSize); const remainder = size - contentSize; item = item.previous(); @@ -142,12 +144,14 @@ class RoomDistributor { } } else { + // console.log(" - resizing", item.id, "to size", size); item.setSize(size); item = null; size = 0; } } } + // console.log("*** ending resize session"); } resizeFromContainerOffset(containerOffset) { From 9456fc040d132d1b567e9b115ddbcd6e3308f41e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 11 Jan 2019 16:10:35 +0100 Subject: [PATCH 13/25] fix typo --- src/resizer/item.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resizer/item.js b/src/resizer/item.js index 13932f91708..e0e1ff809cc 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -69,7 +69,7 @@ export default class ResizeItem { setSize(size) { this.sizer.setItemSize(this.domNode, size); - const callback = this.resizer.distributorCtor.onResized; + const callback = this.resizer.distributorCfg.onResized; if (callback) { callback(size, this.id, this.domNode); } @@ -77,7 +77,7 @@ export default class ResizeItem { clearSize() { this.sizer.clearItemSize(this.domNode); - const callback = this.resizer.distributorCtor.onResized; + const callback = this.resizer.distributorCfg.onResized; if (callback) { callback(null, this.id, this.domNode); } From a413f358f70cc3692a793c8ef45027a1ed829e1d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 11 Jan 2019 17:17:58 +0100 Subject: [PATCH 14/25] normalize sizes when starting drag operation --- res/css/structures/_RoomSubList.scss | 4 +- src/resizer/distributors.js | 4 ++ src/resizer/item.js | 19 +++++++++ src/resizer/resizer.js | 3 ++ src/resizer/room.js | 60 +++++++++++----------------- 5 files changed, 51 insertions(+), 39 deletions(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 8225e1208ca..08e7eec6d7f 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -33,13 +33,13 @@ limitations under the License. .mx_RoomSubList { min-height: 31px; - flex: 0 10000 content; + flex: 0 10000 auto; display: flex; flex-direction: column; } .mx_RoomSubList.resized-sized { - flex: 0 1 0; + flex: 0 1 auto; } .mx_RoomSubList_nonEmpty { diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index cb876bf98c4..f19b864a099 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -39,6 +39,10 @@ class FixedDistributor { resizeFromContainerOffset(offset) { this.resize(offset - this.beforeOffset); } + + start() {} + + finish() {} } diff --git a/src/resizer/item.js b/src/resizer/item.js index e0e1ff809cc..ac47e3aea60 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -82,4 +82,23 @@ export default class ResizeItem { callback(null, this.id, this.domNode); } } + + + first() { + const firstHandle = Array.from(this.domNode.parentElement.children).find(el => { + return this.resizer.isResizeHandle(el); + }); + if (firstHandle) { + return ResizeItem.fromResizeHandle(firstHandle, this.resizer, this.sizer); + } + } + + last() { + const lastHandle = Array.from(this.domNode.parentElement.children).reverse().find(el => { + return this.resizer.isResizeHandle(el); + }); + if (lastHandle) { + return ResizeItem.fromResizeHandle(lastHandle, this.resizer, this.sizer); + } + } } diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 8bdbc6cffea..16440bcc48d 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -107,6 +107,7 @@ export class Resizer { } const {sizer, distributor} = this._createSizerAndDistributor(resizeHandle); + distributor.start(); const onMouseMove = (event) => { const offset = sizer.offsetFromEvent(event); @@ -118,9 +119,11 @@ export class Resizer { if (this.classNames.resizing) { this.container.classList.remove(this.classNames.resizing); } + distributor.finish(); body.removeEventListener("mouseup", onMouseUp, false); body.removeEventListener("mousemove", onMouseMove, false); }; + // TODO: listen for mouseout on document here as well body.addEventListener("mouseup", onMouseUp, false); body.addEventListener("mousemove", onMouseMove, false); } diff --git a/src/resizer/room.js b/src/resizer/room.js index 59f47f31fce..6b2951a6054 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -18,7 +18,7 @@ import {Sizer} from "./sizer"; class RoomSizer extends Sizer { setItemSize(item, size) { - item.style.flexBasis = `${Math.round(size)}px`; + item.style.maxHeight = `${Math.round(size)}px`; item.classList.add("resized-sized"); // const total = this.getTotalSize(); // const percent = size / total; @@ -27,7 +27,7 @@ class RoomSizer extends Sizer { } clearItemSize(item) { - item.style.flexBasis = null; + item.style.maxHeight = null; item.classList.remove("resized-sized"); } } @@ -87,44 +87,15 @@ class RoomDistributor { return item.domNode.classList.contains("resized-sized"); } - resize(size, interactive = false) { - // console.log("*** starting resize session with size", size); - - // grow/shrink items after first? - // const itemSize = this.item.size(); - // // - // if (size < itemSize) { - // let nextItem = this.item.next(); - // while (nextItem) - // } - - if (interactive) { - const nextItem = this.item.next(); - if (nextItem) { - // let item = nextItem; - // let hasUnsizedProceedingItem = false; - // while (item) { - // if (this._isSized(item)) { - // hasUnsizedProceedingItem = true; - // item = null; - // } else { - // item = item.next(); - // } - // } - // if (!hasUnsizedProceedingItem) { - nextItem.clearSize(); - // } - } - } - + resize(size) { + console.log("*** starting resize session with size", size); let item = this.item; while (item) { - // TODO: collapsed if (this._isCollapsed(item)) { item = item.previous(); } else if (size <= MIN_SIZE) { - // console.log(" - resizing", item.id, "to min size", MIN_SIZE); + console.log(" - resizing", item.id, "to min size", MIN_SIZE); item.setSize(MIN_SIZE); const remainder = MIN_SIZE - size; item = item.previous(); @@ -144,18 +115,33 @@ class RoomDistributor { } } else { - // console.log(" - resizing", item.id, "to size", size); + console.log(" - resizing", item.id, "to size", size); item.setSize(size); item = null; size = 0; } } } - // console.log("*** ending resize session"); + console.log("*** ending resize session"); } resizeFromContainerOffset(containerOffset) { - this.resize(containerOffset - this.item.offset(), true); + this.resize(containerOffset - this.item.offset()); + } + + start() { + console.log("RoomDistributor::start: setting all items to their actual size in pixels"); + let item = this.item.first(); + while(item) { + if (!this._isCollapsed(item)) { + item.setSize(item.size()); + } + item = item.next(); + } + } + + finish() { + } } From 136dd4a556ee7691ac8e64fb41821c10faa3361a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 11 Jan 2019 18:20:34 +0100 Subject: [PATCH 15/25] stop resize operation when cursor leaves viewport as mouseup can't be detected outside of viewport --- src/resizer/resizer.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 16440bcc48d..5d63073da93 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -115,16 +115,17 @@ export class Resizer { }; const body = document.body; - const onMouseUp = (event) => { + const finishResize = () => { if (this.classNames.resizing) { this.container.classList.remove(this.classNames.resizing); } distributor.finish(); - body.removeEventListener("mouseup", onMouseUp, false); + body.removeEventListener("mouseup", finishResize, false); + document.removeEventListener("mouseleave", finishResize, false); body.removeEventListener("mousemove", onMouseMove, false); }; - // TODO: listen for mouseout on document here as well - body.addEventListener("mouseup", onMouseUp, false); + body.addEventListener("mouseup", finishResize, false); + document.addEventListener("mouseleave", finishResize, false); body.addEventListener("mousemove", onMouseMove, false); } From 961e0d24dfe05101469b741857fa341fa5b97c8f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 14 Jan 2019 14:41:31 +0100 Subject: [PATCH 16/25] flex-basis to 0 so sublists shrink/grow not-relative to their content --- res/css/structures/_RoomSubList.scss | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 08e7eec6d7f..b7fe19ca899 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -39,7 +39,15 @@ limitations under the License. } .mx_RoomSubList.resized-sized { - flex: 0 1 auto; + /* + 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 { From 9ecb23ce71103ec7316799b895ba280e03fd09f9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 14 Jan 2019 20:24:54 +0100 Subject: [PATCH 17/25] cleanup - move some methods to ResizeItem subclass - allow distributor to instanciate sizer and resizeitem it needs through static factory methods, instead of passing in another ctor a distributor can only function with the right item and sizer anyways. - use consistent import/export style - remove obsolete code --- src/components/views/rooms/RoomList.js | 2 +- src/resizer/distributors.js | 43 ++++++---- src/resizer/index.js | 8 +- src/resizer/item.js | 27 ++++--- src/resizer/resizer.js | 30 ++----- src/resizer/room.js | 108 +++++++++---------------- src/resizer/sizer.js | 9 +-- 7 files changed, 94 insertions(+), 133 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 636000c1754..79b608ac95a 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -167,7 +167,7 @@ module.exports = React.createClass({ const cfg = { onResized: this._onSubListResize, }; - this.resizer = new Resizer(this.resizeContainer, RoomDistributor, cfg, RoomSizer); + this.resizer = new Resizer(this.resizeContainer, RoomDistributor, cfg); this.resizer.setClassNames({ handle: "mx_ResizeHandle", vertical: "mx_ResizeHandle_vertical", diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index f19b864a099..d273f2782ba 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -14,6 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +import ResizeItem from "./item"; +import Sizer from "./sizer"; + /** distributors translate a moving cursor into CSS/DOM changes by calling the sizer @@ -26,7 +29,15 @@ they have two methods: the offset from the container edge of where the mouse cursor is. */ -class FixedDistributor { +export class FixedDistributor { + static createItem(resizeHandle, resizer, sizer) { + return new ResizeItem(resizeHandle, resizer, sizer); + } + + static createSizer(containerElement, vertical, reverse) { + return new Sizer(containerElement, vertical, reverse); + } + constructor(item) { this.item = item; this.beforeOffset = item.offset(); @@ -45,12 +56,23 @@ class FixedDistributor { finish() {} } +class CollapseItem extends ResizeItem { + notifyCollapsed(collapsed) { + const callback = this.resizer.config.onCollapsed; + if (callback) { + callback(collapsed, this.id, this.domNode); + } + } +} -class CollapseDistributor extends FixedDistributor { - constructor(item, sizer, _container, config) { +export class CollapseDistributor extends FixedDistributor { + static createItem(resizeHandle, resizer, sizer) { + return new CollapseItem(resizeHandle, resizer, sizer); + } + + constructor(item, config) { super(item); this.toggleSize = config && config.toggleSize; - this.onCollapsed = config && config.onCollapsed; this.isCollapsed = false; } @@ -58,13 +80,9 @@ class CollapseDistributor extends FixedDistributor { const isCollapsedSize = newSize < this.toggleSize; if (isCollapsedSize && !this.isCollapsed) { this.isCollapsed = true; - if (this.onCollapsed) { - this.onCollapsed(true, this.item); - } + this.item.notifyCollapsed(true); } else if (!isCollapsedSize && this.isCollapsed) { - if (this.onCollapsed) { - this.onCollapsed(false, this.item); - } + this.item.notifyCollapsed(false); this.isCollapsed = false; } if (!isCollapsedSize) { @@ -72,8 +90,3 @@ class CollapseDistributor extends FixedDistributor { } } } - -module.exports = { - FixedDistributor, - CollapseDistributor, -}; diff --git a/src/resizer/index.js b/src/resizer/index.js index 0720fa36ce2..364d0770377 100644 --- a/src/resizer/index.js +++ b/src/resizer/index.js @@ -14,17 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Sizer, FlexSizer} from "./sizer"; import {FixedDistributor, CollapseDistributor} from "./distributors"; -import {Resizer} from "./resizer"; -import {RoomSizer, RoomDistributor} from "./room"; +import Resizer from "./resizer"; +import RoomDistributor from "./room"; module.exports = { Resizer, - Sizer, - FlexSizer, FixedDistributor, CollapseDistributor, - RoomSizer, RoomDistributor, }; diff --git a/src/resizer/item.js b/src/resizer/item.js index ac47e3aea60..6192c6eebb4 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -15,7 +15,11 @@ limitations under the License. */ export default class ResizeItem { - constructor(domNode, id, reverse, resizer, sizer) { + constructor(handle, resizer, sizer) { + const id = handle.getAttribute("data-id"); + const reverse = resizer.isReverseResizeHandle(handle); + const domNode = reverse ? handle.nextElementSibling : handle.previousElementSibling; + this.domNode = domNode; this.id = id; this.reverse = reverse; @@ -23,11 +27,9 @@ export default class ResizeItem { this.sizer = sizer; } - static fromResizeHandle(handle, resizer, sizer) { - const id = handle.getAttribute("data-id"); - const reverse = resizer.isReverseResizeHandle(handle); - const domNode = reverse ? handle.nextElementSibling : handle.previousElementSibling; - return new ResizeItem(domNode, id, reverse, resizer, sizer); + _copyWith(handle, resizer, sizer) { + const Ctor = this.constructor; + return new Ctor(handle, resizer, sizer); } _advance(forwards) { @@ -43,9 +45,10 @@ export default class ResizeItem { } else { handle = handle.previousElementSibling; } - } while(handle && !this.resizer.isResizeHandle(handle)); + } while (handle && !this.resizer.isResizeHandle(handle)); + if (handle) { - const nextHandle = ResizeItem.fromResizeHandle(handle, this.resizer, this.sizer); + const nextHandle = this._copyWith(handle, this.resizer, this.sizer); nextHandle.reverse = this.reverse; return nextHandle; } @@ -69,7 +72,7 @@ export default class ResizeItem { setSize(size) { this.sizer.setItemSize(this.domNode, size); - const callback = this.resizer.distributorCfg.onResized; + const callback = this.resizer.config.onResized; if (callback) { callback(size, this.id, this.domNode); } @@ -77,7 +80,7 @@ export default class ResizeItem { clearSize() { this.sizer.clearItemSize(this.domNode); - const callback = this.resizer.distributorCfg.onResized; + const callback = this.resizer.config.onResized; if (callback) { callback(null, this.id, this.domNode); } @@ -89,7 +92,7 @@ export default class ResizeItem { return this.resizer.isResizeHandle(el); }); if (firstHandle) { - return ResizeItem.fromResizeHandle(firstHandle, this.resizer, this.sizer); + return this._copyWith(firstHandle, this.resizer, this.sizer); } } @@ -98,7 +101,7 @@ export default class ResizeItem { return this.resizer.isResizeHandle(el); }); if (lastHandle) { - return ResizeItem.fromResizeHandle(lastHandle, this.resizer, this.sizer); + return this._copyWith(lastHandle, this.resizer, this.sizer); } } } diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 5d63073da93..4d999652a63 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -14,9 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Sizer} from "./sizer"; -import ResizeItem from "./item"; - /* classNames: // class on resize-handle @@ -30,14 +27,13 @@ classNames: */ -export class Resizer { +export default class Resizer { // TODO move vertical/horizontal to config option/container class // as it doesn't make sense to mix them within one container/Resizer - constructor(container, distributorCtor, distributorCfg, sizerCtor = Sizer) { + constructor(container, distributorCtor, config) { this.container = container; this.distributorCtor = distributorCtor; - this.distributorCfg = distributorCfg; - this.sizerCtor = sizerCtor; + this.config = config; this.classNames = { handle: "resizer-handle", reverse: "resizer-reverse", @@ -132,25 +128,13 @@ export class Resizer { _createSizerAndDistributor(resizeHandle) { const vertical = resizeHandle.classList.contains(this.classNames.vertical); const reverse = this.isReverseResizeHandle(resizeHandle); - // eslint-disable-next-line new-cap - const sizer = new this.sizerCtor(this.container, vertical, reverse); - const item = ResizeItem.fromResizeHandle(resizeHandle, this, sizer); - // eslint-disable-next-line new-cap - const distributor = new this.distributorCtor( - item, - sizer, - this.container, - this.distributorCfg - ); + const Distributor = this.distributorCtor; + const sizer = Distributor.createSizer(this.container, vertical, reverse); + const item = Distributor.createItem(resizeHandle, this, sizer); + const distributor = new Distributor(item, this.config); return {sizer, distributor}; } - _getResizableItems(reverse) { - return this._getResizeHandles().map((handle) => { - return ResizeItem.fromResizeHandle(handle); - }); - } - _getResizeHandles() { return Array.from(this.container.children).filter(el => { return this.isResizeHandle(el); diff --git a/src/resizer/room.js b/src/resizer/room.js index 6b2951a6054..e8c57b0450d 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -14,16 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Sizer} from "./sizer"; +import Sizer from "./sizer"; +import ResizeItem from "./item"; class RoomSizer extends Sizer { setItemSize(item, size) { item.style.maxHeight = `${Math.round(size)}px`; item.classList.add("resized-sized"); - // const total = this.getTotalSize(); - // const percent = size / total; - // const growFactor = Math.round(1 + (percent * 100)); - // item.style.flexGrow = `${growFactor}`; } clearItemSize(item) { @@ -32,38 +29,36 @@ class RoomSizer extends Sizer { } } -/* -class RoomSubList extends ResizeItem { - collapsed() { - - } - - id() { - +class RoomSubListItem extends ResizeItem { + isCollapsed() { + return this.domNode.classList.contains("mx_RoomSubList_hidden"); } maxSize() { - + const scrollItem = this.domNode.querySelector(".mx_RoomSubList_scroll"); + const header = this.domNode.querySelector(".mx_RoomSubList_labelContainer"); + const headerHeight = this.sizer.getItemSize(header); + return headerHeight + scrollItem.scrollHeight; } minSize() { + return 74; //size of header + 1 room tile + } + isSized() { + return this.domNode.classList.contains("resized-sized"); } } -*/ -const MIN_SIZE = 74; -// would be good to have a way in here to know if the item can be resized -// - collapsed items can't be resized (.mx_RoomSubList_hidden) -// - items at MIN_SIZE can't be resized smaller -// - items at maxContentHeight can't be resized larger +export default class RoomDistributor { + static createItem(resizeHandle, resizer, sizer) { + return new RoomSubListItem(resizeHandle, resizer, sizer); + } + + static createSizer(containerElement, vertical, reverse) { + return new RoomSizer(containerElement, vertical, reverse); + } -// if you shrink the predecesor, and start dragging down again afterwards, which item has to grow? -/* - either items before (starting from first or last) - or -*/ -class RoomDistributor { constructor(item) { this.item = item; } @@ -72,57 +67,40 @@ class RoomDistributor { return 1; } - _isCollapsed(item) { - return item.domNode.classList.contains("mx_RoomSubList_hidden"); - } - - _contentSize(item) { - const scrollItem = item.domNode.querySelector(".mx_RoomSubList_scroll"); - const header = item.domNode.querySelector(".mx_RoomSubList_labelContainer"); - const headerHeight = item.sizer.getItemSize(header); - return headerHeight + scrollItem.scrollHeight; - } - - _isSized(item) { - return item.domNode.classList.contains("resized-sized"); - } - resize(size) { - console.log("*** starting resize session with size", size); + //console.log("*** starting resize session with size", size); let item = this.item; while (item) { - if (this._isCollapsed(item)) { + const minSize = item.minSize(); + if (item.isCollapsed()) { item = item.previous(); - } - else if (size <= MIN_SIZE) { - console.log(" - resizing", item.id, "to min size", MIN_SIZE); - item.setSize(MIN_SIZE); - const remainder = MIN_SIZE - size; + } else if (size <= minSize) { + //console.log(" - resizing", item.id, "to min size", minSize); + item.setSize(minSize); + const remainder = minSize - size; item = item.previous(); if (item) { size = item.size() - remainder - this._handleSize(); } - } - else { - const contentSize = this._contentSize(item); - if (size > contentSize) { - // console.log(" - resizing", item.id, "to contentSize", contentSize); - item.setSize(contentSize); - const remainder = size - contentSize; + } else { + const maxSize = item.maxSize(); + if (size > maxSize) { + // console.log(" - resizing", item.id, "to maxSize", maxSize); + item.setSize(maxSize); + const remainder = size - maxSize; item = item.previous(); if (item) { size = item.size() + remainder; // todo: handle size here? } - } - else { - console.log(" - resizing", item.id, "to size", size); + } else { + //console.log(" - resizing", item.id, "to size", size); item.setSize(size); item = null; size = 0; } } } - console.log("*** ending resize session"); + //console.log("*** ending resize session"); } resizeFromContainerOffset(containerOffset) { @@ -130,10 +108,10 @@ class RoomDistributor { } start() { - console.log("RoomDistributor::start: setting all items to their actual size in pixels"); + // set all max-height props to the actual height. let item = this.item.first(); - while(item) { - if (!this._isCollapsed(item)) { + while (item) { + if (!item.isCollapsed() && item.isSized()) { item.setSize(item.size()); } item = item.next(); @@ -141,11 +119,5 @@ class RoomDistributor { } finish() { - } } - -module.exports = { - RoomSizer, - RoomDistributor, -}; diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index cdb11f32704..50861d34d51 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -18,7 +18,7 @@ limitations under the License. implements DOM/CSS operations for resizing. The sizer determines what CSS mechanism is used for sizing items, like flexbox, ... */ -export class Sizer { +export default class Sizer { constructor(container, vertical, reverse) { this.container = container; this.reverse = reverse; @@ -86,10 +86,3 @@ export class Sizer { } } } - -export class FlexSizer extends Sizer { - setItemSize(item, size) { - item.style.flexGrow = `0`; - item.style.flexBasis = `${Math.round(size)}px`; - } -} From 7e395f0fb6a06cd82b356213285866b2694dbff3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 14 Jan 2019 20:33:33 +0100 Subject: [PATCH 18/25] cleanup - part II reshuffle file structure to make more sense --- src/components/views/rooms/RoomList.js | 4 +- src/resizer/distributors/collapse.js | 53 +++++++++++++++++++ .../fixed.js} | 41 ++------------ .../{room.js => distributors/roomsublist.js} | 6 +-- src/resizer/index.js | 7 +-- 5 files changed, 65 insertions(+), 46 deletions(-) create mode 100644 src/resizer/distributors/collapse.js rename src/resizer/{distributors.js => distributors/fixed.js} (58%) rename src/resizer/{room.js => distributors/roomsublist.js} (97%) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 79b608ac95a..cb3cb49cd45 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -36,7 +36,7 @@ import GroupStore from '../../../stores/GroupStore'; import RoomSubList from '../../structures/RoomSubList'; import ResizeHandle from '../elements/ResizeHandle'; -import {Resizer, RoomDistributor, RoomSizer} from '../../../resizer' +import {Resizer, RoomSubListDistributor} from '../../../resizer' const HIDE_CONFERENCE_CHANS = true; const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/; @@ -167,7 +167,7 @@ module.exports = React.createClass({ const cfg = { onResized: this._onSubListResize, }; - this.resizer = new Resizer(this.resizeContainer, RoomDistributor, cfg); + this.resizer = new Resizer(this.resizeContainer, RoomSubListDistributor, cfg); this.resizer.setClassNames({ handle: "mx_ResizeHandle", vertical: "mx_ResizeHandle_vertical", diff --git a/src/resizer/distributors/collapse.js b/src/resizer/distributors/collapse.js new file mode 100644 index 00000000000..d9d596299d3 --- /dev/null +++ b/src/resizer/distributors/collapse.js @@ -0,0 +1,53 @@ +/* +Copyright 2018 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"; +import ResizeItem from "../item"; + +class CollapseItem extends ResizeItem { + notifyCollapsed(collapsed) { + const callback = this.resizer.config.onCollapsed; + if (callback) { + callback(collapsed, this.id, this.domNode); + } + } +} + +export default class CollapseDistributor extends FixedDistributor { + static createItem(resizeHandle, resizer, sizer) { + return new CollapseItem(resizeHandle, resizer, sizer); + } + + constructor(item, config) { + super(item); + this.toggleSize = config && config.toggleSize; + this.isCollapsed = false; + } + + resize(newSize) { + const isCollapsedSize = newSize < this.toggleSize; + if (isCollapsedSize && !this.isCollapsed) { + this.isCollapsed = true; + this.item.notifyCollapsed(true); + } else if (!isCollapsedSize && this.isCollapsed) { + this.item.notifyCollapsed(false); + this.isCollapsed = false; + } + if (!isCollapsedSize) { + super.resize(newSize); + } + } +} diff --git a/src/resizer/distributors.js b/src/resizer/distributors/fixed.js similarity index 58% rename from src/resizer/distributors.js rename to src/resizer/distributors/fixed.js index d273f2782ba..843d8367e0e 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors/fixed.js @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import ResizeItem from "./item"; -import Sizer from "./sizer"; +import ResizeItem from "../item"; +import Sizer from "../sizer"; /** distributors translate a moving cursor into @@ -29,7 +29,7 @@ they have two methods: the offset from the container edge of where the mouse cursor is. */ -export class FixedDistributor { +export default class FixedDistributor { static createItem(resizeHandle, resizer, sizer) { return new ResizeItem(resizeHandle, resizer, sizer); } @@ -55,38 +55,3 @@ export class FixedDistributor { finish() {} } - -class CollapseItem extends ResizeItem { - notifyCollapsed(collapsed) { - const callback = this.resizer.config.onCollapsed; - if (callback) { - callback(collapsed, this.id, this.domNode); - } - } -} - -export class CollapseDistributor extends FixedDistributor { - static createItem(resizeHandle, resizer, sizer) { - return new CollapseItem(resizeHandle, resizer, sizer); - } - - constructor(item, config) { - super(item); - this.toggleSize = config && config.toggleSize; - this.isCollapsed = false; - } - - resize(newSize) { - const isCollapsedSize = newSize < this.toggleSize; - if (isCollapsedSize && !this.isCollapsed) { - this.isCollapsed = true; - this.item.notifyCollapsed(true); - } else if (!isCollapsedSize && this.isCollapsed) { - this.item.notifyCollapsed(false); - this.isCollapsed = false; - } - if (!isCollapsedSize) { - super.resize(newSize); - } - } -} diff --git a/src/resizer/room.js b/src/resizer/distributors/roomsublist.js similarity index 97% rename from src/resizer/room.js rename to src/resizer/distributors/roomsublist.js index e8c57b0450d..1e5ce0fc92e 100644 --- a/src/resizer/room.js +++ b/src/resizer/distributors/roomsublist.js @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import Sizer from "./sizer"; -import ResizeItem from "./item"; +import Sizer from "../sizer"; +import ResizeItem from "../item"; class RoomSizer extends Sizer { setItemSize(item, size) { @@ -50,7 +50,7 @@ class RoomSubListItem extends ResizeItem { } } -export default class RoomDistributor { +export default class RoomSubListDistributor { static createItem(resizeHandle, resizer, sizer) { return new RoomSubListItem(resizeHandle, resizer, sizer); } diff --git a/src/resizer/index.js b/src/resizer/index.js index 364d0770377..bc4c8f388c5 100644 --- a/src/resizer/index.js +++ b/src/resizer/index.js @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {FixedDistributor, CollapseDistributor} from "./distributors"; +import FixedDistributor from "./distributors/fixed"; +import CollapseDistributor from "./distributors/collapse"; +import RoomSubListDistributor from "./distributors/roomsublist"; import Resizer from "./resizer"; -import RoomDistributor from "./room"; module.exports = { Resizer, FixedDistributor, CollapseDistributor, - RoomDistributor, + RoomSubListDistributor, }; From aa90e9591ade9eb1f8edffedce2ce0f8d1a29b97 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Jan 2019 12:56:33 +0100 Subject: [PATCH 19/25] fix min & max size for empty sublists --- src/resizer/distributors/roomsublist.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/resizer/distributors/roomsublist.js b/src/resizer/distributors/roomsublist.js index 1e5ce0fc92e..516c4da3e24 100644 --- a/src/resizer/distributors/roomsublist.js +++ b/src/resizer/distributors/roomsublist.js @@ -35,14 +35,15 @@ class RoomSubListItem extends ResizeItem { } maxSize() { - const scrollItem = this.domNode.querySelector(".mx_RoomSubList_scroll"); const header = this.domNode.querySelector(".mx_RoomSubList_labelContainer"); + const scrollItem = this.domNode.querySelector(".mx_RoomSubList_scroll"); const headerHeight = this.sizer.getItemSize(header); - return headerHeight + scrollItem.scrollHeight; + return headerHeight + (scrollItem ? scrollItem.scrollHeight : 0); } minSize() { - return 74; //size of header + 1 room tile + const isNotEmpty = this.domNode.classList.contains("mx_RoomSubList_nonEmpty"); + return isNotEmpty ? 74 : 31; //size of header + 1? room tile (see room sub list css) } isSized() { From 3c7bed97ac8c5f2c06ca77d9ce13f29be364ca60 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Jan 2019 12:56:48 +0100 Subject: [PATCH 20/25] size all items to rendered height when starting drag operation before, we'd only normalize the sublists that had already been sized manually. As non-sized items still have flex-basis: auto, they would claim all the space, and mixing sized and unsized items would be badly broken. Now, on the first click, all items are sized to their rendered size which means they won't flex anymore, but at least the resizing works this way Another downside is that when resizing while a sublist is collapsed, it's reverted to 100px and if a size had been set before, it's forgotten. No way around this with this approach I'm afraid. --- src/resizer/distributors/roomsublist.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/resizer/distributors/roomsublist.js b/src/resizer/distributors/roomsublist.js index 516c4da3e24..e6f07a648d5 100644 --- a/src/resizer/distributors/roomsublist.js +++ b/src/resizer/distributors/roomsublist.js @@ -111,12 +111,20 @@ export default class RoomSubListDistributor { start() { // set all max-height props to the actual height. let item = this.item.first(); + const sizes = []; while (item) { - if (!item.isCollapsed() && item.isSized()) { - item.setSize(item.size()); + if (!item.isCollapsed()) { + sizes.push(item.size()); + } else { + sizes.push(100); } item = item.next(); } + item = this.item.first(); + sizes.forEach((size) => { + item.setSize(size); + item = item.next(); + }); } finish() { From a5424f32a510b6212ecec46f9eac75e55d7a89f2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Jan 2019 10:29:05 +0000 Subject: [PATCH 21/25] Update src/resizer/item.js Co-Authored-By: bwindels --- src/resizer/item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/item.js b/src/resizer/item.js index 6192c6eebb4..2e06ad217ca 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +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. From 2bd65e14b770d92d950b21b726dc070c1ba551fc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Jan 2019 10:29:15 +0000 Subject: [PATCH 22/25] Update src/resizer/distributors/fixed.js Co-Authored-By: bwindels --- src/resizer/distributors/fixed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/distributors/fixed.js b/src/resizer/distributors/fixed.js index 843d8367e0e..584d0c1894a 100644 --- a/src/resizer/distributors/fixed.js +++ b/src/resizer/distributors/fixed.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +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. From 98aa657052df0f374870ab0e3dd5e51a7941cb58 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Jan 2019 10:29:22 +0000 Subject: [PATCH 23/25] Update src/resizer/distributors/collapse.js Co-Authored-By: bwindels --- src/resizer/distributors/collapse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/distributors/collapse.js b/src/resizer/distributors/collapse.js index d9d596299d3..784532a0eb8 100644 --- a/src/resizer/distributors/collapse.js +++ b/src/resizer/distributors/collapse.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +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. From fed256cbaa60acf52ebac5c6978616296f0698bb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Jan 2019 10:29:30 +0000 Subject: [PATCH 24/25] Update src/resizer/distributors/roomsublist.js Co-Authored-By: bwindels --- src/resizer/distributors/roomsublist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/distributors/roomsublist.js b/src/resizer/distributors/roomsublist.js index e6f07a648d5..cc7875bfb07 100644 --- a/src/resizer/distributors/roomsublist.js +++ b/src/resizer/distributors/roomsublist.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +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. From 313bbaaeaac981bd35fbb14c5e38cc449587f8a3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Jan 2019 11:33:41 +0100 Subject: [PATCH 25/25] remove obsolete comments --- src/resizer/distributors/fixed.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/resizer/distributors/fixed.js b/src/resizer/distributors/fixed.js index 584d0c1894a..e93c6fbcee1 100644 --- a/src/resizer/distributors/fixed.js +++ b/src/resizer/distributors/fixed.js @@ -26,8 +26,6 @@ they have two methods: `resizeFromContainerOffset` receives resize handle location within the container bounding box. For internal use. This method usually ends up calling `resize` once the start offset is subtracted. -the offset from the container edge of where -the mouse cursor is. */ export default class FixedDistributor { static createItem(resizeHandle, resizer, sizer) {