From 313956dd9991a87333c8d825c6de6f5924a0e210 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 24 Sep 2018 16:06:57 +0100 Subject: [PATCH 01/27] make left panel adapt to width includes using flexbox in the room tile to avoid hardcoded width --- res/css/structures/_LeftPanel.scss | 27 ++++++++++--------- res/css/structures/_MatrixChat.scss | 14 ---------- res/css/structures/_RoomSubList.scss | 2 -- res/css/views/rooms/_RoomTile.scss | 39 ++++++---------------------- 4 files changed, 23 insertions(+), 59 deletions(-) diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index c0298a048a5..b94b78b546a 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -15,24 +15,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_LeftPanel { - position: relative; - - display: flex; - flex-direction: column; - - border-right: 1px solid $panel-divider-color; -} - .mx_LeftPanel_container { display: flex; /* LeftPanel 260px */ - flex: 0 0 260px; + min-width: 260px; + flex: 0 0 auto; } .mx_LeftPanel_container.mx_LeftPanel_container_hasTagPanel { /* TagPanel 70px + LeftPanel 260px */ - flex: 0 0 330px; + flex: 0 0 auto; } .mx_LeftPanel_container_collapsed { @@ -42,7 +34,7 @@ limitations under the License. .mx_LeftPanel_container_collapsed.mx_LeftPanel_container_hasTagPanel { /* TagPanel 70px + Collapsed LeftPanel 70px */ - flex: 0 0 140px; + flex: 0 0 auto; } .mx_LeftPanel_hideButton { @@ -57,6 +49,17 @@ limitations under the License. } +.mx_LeftPanel { + background-color: $secondary-accent-color; + flex: 1; + position: relative; + + display: flex; + flex-direction: column; + + border-right: 1px solid $panel-divider-color; +} + .mx_LeftPanel .mx_AppTile_mini { height: 132px; } diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index 9fdf972a4f5..ffde6f90952 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -68,19 +68,7 @@ limitations under the License. transform: translateX(-50%); } -.mx_MatrixChat .mx_LeftPanel { - order: 1; - background-color: $secondary-accent-color; - flex: 0 0 260px; -} - -.mx_MatrixChat .mx_LeftPanel.collapsed { - flex: 0 0 60px; -} - .mx_MatrixChat .mx_MatrixChat_middlePanel { - order: 2; - background-color: $primary-bg-color; flex: 1; @@ -102,8 +90,6 @@ limitations under the License. } .mx_MatrixChat .mx_RightPanel { - order: 3; - flex: 0 0 235px; } diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 3cebc0b75f8..961fd03d215 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -29,7 +29,6 @@ limitations under the License. .mx_RoomSubList_labelContainer { height: 31px; /* mx_RoomSubList_label height including border */ - width: 235px; /* LHS Panel width */ position: relative; } @@ -39,7 +38,6 @@ limitations under the License. color: $roomsublist-label-fg-color; font-weight: 700; font-size: 12px; - width: 203px; /* padding + width = LHS Panel width */ height: 19px; /* height + padding = 31px = mx_RoomSubList_label height */ margin-left: 16px; padding-left: 16px; /* gutter */ diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index a2ca96cda87..daa9b640581 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -15,9 +15,10 @@ limitations under the License. */ .mx_RoomTile { - position: relative; + display: flex; + flex-direction: row; + align-items: center; cursor: pointer; - display: block; height: 40px; margin: 0px 9px 0px 9px; @@ -31,26 +32,14 @@ limitations under the License. left: -12px; } - -.mx_RoomTile_nameContainer { - display: inline-block; - width: 180px; - height: 24px; -} - -.mx_RoomTile_avatar_container { - position: relative; -} - .mx_RoomTile_avatar { - display: inline-block; + flex: 0; padding-top: 4px; padding-bottom: 4px; padding-left: 14px; padding-right: 12px; width: 32px; height: 32px; - vertical-align: middle; } .mx_RoomTile_dm { @@ -62,19 +51,13 @@ limitations under the License. } .mx_RoomTile_name { - display: inline-block; + flex: 1 5 auto; font-size: 14px; font-weight: 600; - position: relative; - width: 165px; - vertical-align: middle; - padding-left: 6px; - padding-right: 6px; - padding-top: 2px; - padding-bottom: 3px; + padding: 6px; color: $roomtile-name-color; white-space: nowrap; - overflow: hidden; + overflow-x: hidden; text-overflow: ellipsis; } @@ -82,16 +65,11 @@ limitations under the License. /* color: rgba(69, 69, 69, 0.5); */ } -.collapsed .mx_RoomTile_nameContainer { - width: 60px; /* colapsed panel width */ -} - .collapsed .mx_RoomTile_name { display: none; } .collapsed .mx_RoomTile_badge { - top: 0px; min-width: 12px; border-radius: 16px; padding: 0px 4px 0px 4px; @@ -116,10 +94,9 @@ limitations under the License. } .mx_RoomTile_badge { - display: inline-block; + flex: 0 1 content; min-width: 15px; height: 15px; - position: absolute; right: 8px; /*gutter */ top: 9px; border-radius: 8px; From 928b6d47c8449b1b784e4ea04606085ab8dc446c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 24 Sep 2018 16:07:42 +0100 Subject: [PATCH 02/27] add resize handles between 3 main app columns --- res/css/_components.scss | 1 + res/css/views/elements/_ResizeHandle.scss | 40 ++++++++ src/components/structures/LoggedInView.js | 22 ++++- src/components/views/elements/ResizeHandle.js | 26 +++++ src/components/views/rooms/RoomTile.js | 7 +- src/resizer/distributors.js | 96 +++++++++++++++++++ src/resizer/event.js | 70 ++++++++++++++ src/resizer/index.js | 10 ++ src/resizer/room.js | 39 ++++++++ src/resizer/sizer.js | 70 ++++++++++++++ 10 files changed, 372 insertions(+), 9 deletions(-) create mode 100644 res/css/views/elements/_ResizeHandle.scss create mode 100644 src/components/views/elements/ResizeHandle.js create mode 100644 src/resizer/distributors.js create mode 100644 src/resizer/event.js create mode 100644 src/resizer/index.js create mode 100644 src/resizer/room.js create mode 100644 src/resizer/sizer.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 1e1d3e65960..c43d9edc169 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -57,6 +57,7 @@ @import "./views/elements/_MemberEventListSummary.scss"; @import "./views/elements/_ProgressBar.scss"; @import "./views/elements/_ReplyThread.scss"; +@import "./views/elements/_ResizeHandle.scss"; @import "./views/elements/_RichText.scss"; @import "./views/elements/_RoleButton.scss"; @import "./views/elements/_Spinner.scss"; diff --git a/res/css/views/elements/_ResizeHandle.scss b/res/css/views/elements/_ResizeHandle.scss new file mode 100644 index 00000000000..550dcff9116 --- /dev/null +++ b/res/css/views/elements/_ResizeHandle.scss @@ -0,0 +1,40 @@ +/* +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. +*/ + +.mx_ResizeHandle { + cursor: row-resize; + flex: 0 0 auto; + background: blue; + padding: 1px +} + +.mx_ResizeHandle.mx_ResizeHandle_horizontal { + width: 1px; + cursor: e-resize; +} + +.mx_ResizeHandle.mx_ResizeHandle_vertical { + height: 1px; + cursor: s-resize; +} + +.mx_ResizeHandle.mx_ResizeHandle_horizontal.mx_ResizeHandle_reverse { + cursor: w-resize; +} + +.mx_ResizeHandle.mx_ResizeHandle_vertical.mx_ResizeHandle_reverse { + cursor: n-resize; +} diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 0c4688a4111..174a742c44f 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -34,7 +34,8 @@ import RoomListStore from "../../stores/RoomListStore"; import TagOrderActions from '../../actions/TagOrderActions'; import RoomListActions from '../../actions/RoomListActions'; - +import ResizeHandle from '../views/elements/ResizeHandle'; +import {makeResizeable, FixedDistributor} from '../../resizer' // We need to fetch each pinned message individually (if we don't already have it) // so each pinned message may trigger a request. Limit the number per room for sanity. // NB. this is just for server notices rather than pinned messages in general. @@ -91,6 +92,15 @@ const LoggedInView = React.createClass({ }; }, + componentDidMount: function() { + const classNames = { + handle: "mx_ResizeHandle", + vertical: "mx_ResizeHandle_vertical", + reverse: "mx_ResizeHandle_reverse" + }; + makeResizeable(this.resizeContainer, classNames, FixedDistributor); + }, + componentWillMount: function() { // stash the MatrixClient in case we log out before we are unmounted this._matrixClient = this.props.matrixClient; @@ -186,13 +196,13 @@ const LoggedInView = React.createClass({ _updateServerNoticeEvents: async function() { const roomLists = RoomListStore.getRoomLists(); if (!roomLists['m.server_notice']) return []; - + const pinnedEvents = []; for (const room of roomLists['m.server_notice']) { const pinStateEvent = room.currentState.getStateEvents("m.room.pinned_events", ""); if (!pinStateEvent || !pinStateEvent.getContent().pinned) continue; - + const pinnedEventIds = pinStateEvent.getContent().pinned.slice(0, MAX_PINNED_NOTICES_PER_ROOM); for (const eventId of pinnedEventIds) { const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId, 0); @@ -204,7 +214,7 @@ const LoggedInView = React.createClass({ serverNoticeEvents: pinnedEvents, }); }, - + _onKeyDown: function(ev) { /* @@ -481,14 +491,16 @@ const LoggedInView = React.createClass({
{ topBar } -
+
this.resizeContainer = div} className={bodyClasses}> +
{ page_element }
+ { right_panel }
diff --git a/src/components/views/elements/ResizeHandle.js b/src/components/views/elements/ResizeHandle.js new file mode 100644 index 00000000000..ae324a752b1 --- /dev/null +++ b/src/components/views/elements/ResizeHandle.js @@ -0,0 +1,26 @@ + +import React from 'react'; // eslint-disable-line no-unused-vars +import PropTypes from 'prop-types'; + +//see src/resizer for the actual resizing code, this is just the DOM for the resize handle +const ResizeHandle = (props) => { + const classNames = ['mx_ResizeHandle']; + if (props.vertical) { + classNames.push('mx_ResizeHandle_vertical'); + } else { + classNames.push('mx_ResizeHandle_horizontal'); + } + if (props.reverse) { + classNames.push('mx_ResizeHandle_reverse'); + } + return ( +
+ ); +}; + +ResizeHandle.propTypes = { + vertical: PropTypes.bool, + reverse: PropTypes.bool, +}; + +export default ResizeHandle; diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index a8552aa1427..e70ea210f43 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -243,6 +243,7 @@ module.exports = React.createClass({ }, render: function() { + this.state.badgeHover = true; const isInvite = this.props.room.getMyMembership() === "invite"; const notificationCount = this.state.notificationCount; // var highlightCount = this.props.room.getUnreadNotificationCount("highlight"); @@ -337,10 +338,8 @@ module.exports = React.createClass({ { dmIndicator }
-
- { label } - { badge } -
+ { label } + { badge } { /* { incomingCallBox } */ } { tooltip } ; diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js new file mode 100644 index 00000000000..bef3377df24 --- /dev/null +++ b/src/resizer/distributors.js @@ -0,0 +1,96 @@ +class FixedDistributor { + constructor(container, items, handleIndex, direction, sizer) { + this.item = items[handleIndex + direction]; + this.beforeOffset = sizer.getItemOffset(this.item); + this.sizer = sizer; + } + + resize(offset) { + const itemSize = offset - this.beforeOffset; + this.sizer.setItemSize(this.item, itemSize); + return itemSize; + } + + finish(_offset) { + } +} + + +class CollapseDistributor extends FixedDistributor { + constructor(container, items, handleIndex, direction, sizer) { + super(container, items, handleIndex, direction, sizer); + const style = getComputedStyle(this.item); + this.minWidth = parseInt(style.minWidth, 10); //auto becomes NaN + } + + resize(offset) { + let newWidth = offset - this.sizer.getItemOffset(this.item); + if (this.minWidth > 0) { + if (offset < this.minWidth + 50) { + this.item.classList.add("collapsed"); + newWidth = this.minWidth; + } + else { + this.item.classList.remove("collapsed"); + } + } + super.resize(newWidth); + } +} + +class PercentageDistributor { + + constructor(container, items, handleIndex, direction, sizer) { + this.container = container; + this.totalSize = sizer.getTotalSize(); + this.sizer = sizer; + + this.beforeItems = items.slice(0, handleIndex); + this.afterItems = items.slice(handleIndex); + const percentages = PercentageDistributor._getPercentages(sizer, items); + this.beforePercentages = percentages.slice(0, handleIndex); + this.afterPercentages = percentages.slice(handleIndex); + } + + resize(offset) { + const percent = offset / this.totalSize; + const beforeSum = + this.beforePercentages.reduce((total, p) => total + p, 0); + const beforePercentages = + this.beforePercentages.map(p => (p / beforeSum) * percent); + const afterSum = + this.afterPercentages.reduce((total, p) => total + p, 0); + const afterPercentages = + this.afterPercentages.map(p => (p / afterSum) * (1 - percent)); + + this.beforeItems.forEach((item, index) => { + this.sizer.setItemPercentage(item, beforePercentages[index]); + }); + this.afterItems.forEach((item, index) => { + this.sizer.setItemPercentage(item, afterPercentages[index]); + }); + } + + finish(_offset) { + + } + + static _getPercentages(sizer, items) { + const percentages = items.map(i => sizer.getItemPercentage(i)); + const setPercentages = percentages.filter(p => p !== null); + const unsetCount = percentages.length - setPercentages.length; + const setTotal = setPercentages.reduce((total, p) => total + p, 0); + const implicitPercentage = (1 - setTotal) / unsetCount; + return percentages.map(p => p === null ? implicitPercentage : p); + } + + static setPercentage(el, percent) { + el.style.flexGrow = Math.round(percent * 1000); + } +} + +module.exports = { + FixedDistributor, + CollapseDistributor, + PercentageDistributor, +}; diff --git a/src/resizer/event.js b/src/resizer/event.js new file mode 100644 index 00000000000..3baa67e097f --- /dev/null +++ b/src/resizer/event.js @@ -0,0 +1,70 @@ +import {Sizer} from "./sizer"; + +/* +classNames: + // class on resize-handle + handle: string + // class on resize-handle + reverse: string + // class on resize-handle + vertical: string + // class on container + resizing: string +*/ + +function makeResizeable(container, classNames, distributorCtor, sizerCtor = Sizer) { + + function isResizeHandle(el) { + return el && el.classList.contains(classNames.handle); + } + + function handleMouseDown(event) { + const target = event.target; + if (!isResizeHandle(target) || target.parentElement !== container) { + return; + } + // prevent starting a drag operation + event.preventDefault(); + // mark as currently resizing + if (classNames.resizing) { + container.classList.add(classNames.resizing); + } + + const resizeHandle = event.target; + const vertical = resizeHandle.classList.contains(classNames.vertical); + const reverse = resizeHandle.classList.contains(classNames.reverse); + const direction = reverse ? 0 : -1; + + const sizer = new sizerCtor(container, vertical, reverse); + + const items = Array.from(container.children).filter(el => { + return !isResizeHandle(el) && ( + isResizeHandle(el.previousElementSibling) || + isResizeHandle(el.nextElementSibling)); + }); + const prevItem = resizeHandle.previousElementSibling; + const handleIndex = items.indexOf(prevItem) + 1; + const distributor = new distributorCtor(container, items, handleIndex, direction, sizer); + + const onMouseMove = (event) => { + const offset = sizer.offsetFromEvent(event); + distributor.resize(offset); + }; + + const body = document.body; + const onMouseUp = (event) => { + if (classNames.resizing) { + container.classList.remove(classNames.resizing); + } + const offset = sizer.offsetFromEvent(event); + distributor.finish(offset); + body.removeEventListener("mouseup", onMouseUp, false); + body.removeEventListener("mousemove", onMouseMove, false); + }; + body.addEventListener("mouseup", onMouseUp, false); + body.addEventListener("mousemove", onMouseMove, false); + } + container.addEventListener("mousedown", handleMouseDown, false); +} + +module.exports = {makeResizeable}; diff --git a/src/resizer/index.js b/src/resizer/index.js new file mode 100644 index 00000000000..923471b1f2f --- /dev/null +++ b/src/resizer/index.js @@ -0,0 +1,10 @@ +import {Sizer} from "./sizer"; +import {FixedDistributor, PercentageDistributor} from "./distributors"; +import {makeResizeable} from "./event"; + +module.exports = { + makeResizeable, + Sizer, + FixedDistributor, + PercentageDistributor, +}; diff --git a/src/resizer/room.js b/src/resizer/room.js new file mode 100644 index 00000000000..0080cca3eb8 --- /dev/null +++ b/src/resizer/room.js @@ -0,0 +1,39 @@ +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) { + item.style.flex = null; + if (size === "show-content") { + cl.add("show-content"); + cl.remove("show-available"); + item.style.maxHeight = null; + } + } else { + cl.add("show-available"); + //item.style.flex = `0 1 ${Math.round(size)}px`; + item.style.maxHeight = `${Math.round(size)}px`; + } + } + +} + +class RoomDistributor extends FixedDistributor { + resize(offset) { + const itemSize = offset - this.sizer.getItemOffset(this.item); + + if (itemSize > this.item.scrollHeight) { + this.sizer.setItemSize(this.item, "show-content"); + } else { + this.sizer.setItemSize(this.item, itemSize); + } + } +} + +module.exports = { + RoomSizer, + RoomDistributor, +}; diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js new file mode 100644 index 00000000000..2dc116714f2 --- /dev/null +++ b/src/resizer/sizer.js @@ -0,0 +1,70 @@ +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); + } + + /** returns how far the edge of the item is from the edge of the container */ + getItemOffset(item) { + const offset = (this.vertical ? item.offsetTop : item.offsetLeft) - this._getOffset(); + if (this.reverse) { + return this.getTotalSize() - (offset + this.getItemSize(item)); + } else { + return offset; + } + } + + /** returns the width/height of an item in the container */ + getItemSize(item) { + return this.vertical ? item.offsetHeight : item.offsetWidth; + } + + /** returns the width/height of the container */ + getTotalSize() { + return this.vertical ? this.container.offsetHeight : this.container.offsetWidth; + } + + /** container offset to offsetParent */ + _getOffset() { + return this.vertical ? this.container.offsetTop : this.container.offsetLeft; + } + + setItemSize(item, size) { + if (this.vertical) { + item.style.height = `${Math.round(size)}px`; + } else { + item.style.width = `${Math.round(size)}px`; + } + } + + /** returns the position of cursor at event relative to the edge of the container */ + offsetFromEvent(event) { + const pos = this.vertical ? event.pageY : event.pageX; + if (this.reverse) { + return (this._getOffset() + this.getTotalSize()) - pos; + } else { + return pos - this._getOffset(); + } + } +} + +module.exports = {Sizer}; From e5d1b3328c509ff86c7c023aa10d12ec521de13b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 11 Oct 2018 15:33:38 +0200 Subject: [PATCH 03/27] make resize handles have correct color + bidirectional cursor --- res/css/structures/_LeftPanel.scss | 2 -- res/css/views/elements/_ResizeHandle.scss | 14 +++----------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index b94b78b546a..75d37e250b3 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -56,8 +56,6 @@ limitations under the License. display: flex; flex-direction: column; - - border-right: 1px solid $panel-divider-color; } .mx_LeftPanel .mx_AppTile_mini { diff --git a/res/css/views/elements/_ResizeHandle.scss b/res/css/views/elements/_ResizeHandle.scss index 550dcff9116..e9aa91fe257 100644 --- a/res/css/views/elements/_ResizeHandle.scss +++ b/res/css/views/elements/_ResizeHandle.scss @@ -17,24 +17,16 @@ limitations under the License. .mx_ResizeHandle { cursor: row-resize; flex: 0 0 auto; - background: blue; + background: $panel-divider-color; padding: 1px } .mx_ResizeHandle.mx_ResizeHandle_horizontal { width: 1px; - cursor: e-resize; + cursor: col-resize; } .mx_ResizeHandle.mx_ResizeHandle_vertical { height: 1px; - cursor: s-resize; -} - -.mx_ResizeHandle.mx_ResizeHandle_horizontal.mx_ResizeHandle_reverse { - cursor: w-resize; -} - -.mx_ResizeHandle.mx_ResizeHandle_vertical.mx_ResizeHandle_reverse { - cursor: n-resize; + cursor: row-resize; } From d6774fd8ee397da9cfe10cf614e2f2d00d462bfe Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 11 Oct 2018 15:37:42 +0200 Subject: [PATCH 04/27] make the left panel collapse by only adding collapse class on container as the resize handle is a sibling of the mxLeftPanel_container, that class is the one that has to collapse if we don't want to complicate the logic. So change style rules to check .mxLeftPanel_container.collapsed, and make left panel not break out of the container when it gets narrow by hiding the overflow --- res/css/structures/_LeftPanel.scss | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index 75d37e250b3..ca4a5ea6f33 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -22,19 +22,15 @@ limitations under the License. flex: 0 0 auto; } -.mx_LeftPanel_container.mx_LeftPanel_container_hasTagPanel { - /* TagPanel 70px + LeftPanel 260px */ - flex: 0 0 auto; -} - -.mx_LeftPanel_container_collapsed { +.mx_LeftPanel_container.collapsed { + min-width: unset; /* Collapsed LeftPanel 70px */ flex: 0 0 70px; } -.mx_LeftPanel_container_collapsed.mx_LeftPanel_container_hasTagPanel { +.mx_LeftPanel_container.collapsed.mx_LeftPanel_container_hasTagPanel { /* TagPanel 70px + Collapsed LeftPanel 70px */ - flex: 0 0 auto; + flex: 0 0 140px; } .mx_LeftPanel_hideButton { @@ -53,7 +49,7 @@ limitations under the License. background-color: $secondary-accent-color; flex: 1; position: relative; - + overflow-x: hidden; display: flex; flex-direction: column; } @@ -71,7 +67,7 @@ limitations under the License. z-index: 6; } -.mx_LeftPanel.collapsed .mx_BottomLeftMenu { +.mx_LeftPanel_container.collapsed .mx_BottomLeftMenu { flex: 0 0 160px; margin-bottom: 9px; } @@ -94,7 +90,7 @@ limitations under the License. pointer-events: none; } -.collapsed .mx_RoleButton { +.mx_LeftPanel_container.collapsed .mx_RoleButton { margin-right: 0px ! important; padding-top: 3px ! important; padding-bottom: 3px ! important; @@ -118,7 +114,7 @@ limitations under the License. margin-right: 0px; } -.mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings { +.mx_LeftPanel_container.collapsed .mx_BottomLeftMenu_settings { float: none; } @@ -127,7 +123,7 @@ limitations under the License. flex: 0 0 50px; } - .mx_LeftPanel.collapsed .mx_BottomLeftMenu { + .mx_LeftPanel_container.collapsed .mx_BottomLeftMenu { flex: 0 0 160px; } From 4f006b033e1d6012226704dd538bca773f69673f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 11 Oct 2018 15:40:59 +0200 Subject: [PATCH 05/27] collapse left panel when 50px past min-width --- src/components/structures/LoggedInView.js | 4 ++-- src/resizer/distributors.js | 7 ++++++- src/resizer/index.js | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 174a742c44f..a3a88f1958a 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -35,7 +35,7 @@ import RoomListStore from "../../stores/RoomListStore"; import TagOrderActions from '../../actions/TagOrderActions'; import RoomListActions from '../../actions/RoomListActions'; import ResizeHandle from '../views/elements/ResizeHandle'; -import {makeResizeable, FixedDistributor} from '../../resizer' +import {makeResizeable, CollapseDistributor} from '../../resizer' // We need to fetch each pinned message individually (if we don't already have it) // so each pinned message may trigger a request. Limit the number per room for sanity. // NB. this is just for server notices rather than pinned messages in general. @@ -98,7 +98,7 @@ const LoggedInView = React.createClass({ vertical: "mx_ResizeHandle_vertical", reverse: "mx_ResizeHandle_reverse" }; - makeResizeable(this.resizeContainer, classNames, FixedDistributor); + makeResizeable(this.resizeContainer, classNames, CollapseDistributor); }, componentWillMount: function() { diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index bef3377df24..eda60c6fe3c 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -26,7 +26,12 @@ class CollapseDistributor extends FixedDistributor { resize(offset) { let newWidth = offset - this.sizer.getItemOffset(this.item); if (this.minWidth > 0) { - if (offset < this.minWidth + 50) { + // -50 this is to not collapse immediately + // when moving the cursor past the minWidth + // to give some visual feedback you are about + // to collapse + // TODO: should 50 be configurable? minWidth/2 maybe? + if (offset < (this.minWidth - 50)) { this.item.classList.add("collapsed"); newWidth = this.minWidth; } diff --git a/src/resizer/index.js b/src/resizer/index.js index 923471b1f2f..fba384ebb91 100644 --- a/src/resizer/index.js +++ b/src/resizer/index.js @@ -1,10 +1,11 @@ import {Sizer} from "./sizer"; -import {FixedDistributor, PercentageDistributor} from "./distributors"; +import {FixedDistributor, CollapseDistributor, PercentageDistributor} from "./distributors"; import {makeResizeable} from "./event"; module.exports = { makeResizeable, Sizer, FixedDistributor, + CollapseDistributor, PercentageDistributor, }; From 3331a29ac5fe32b138c0208a33f953b746c04cdb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 11 Oct 2018 15:42:45 +0200 Subject: [PATCH 06/27] put sizing of right panel in RightPanel style file, plus min-width --- res/css/structures/_MatrixChat.scss | 8 -------- res/css/structures/_RightPanel.scss | 4 +++- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index ffde6f90952..4f817eef44a 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -88,11 +88,3 @@ limitations under the License. */ height: 100%; } - -.mx_MatrixChat .mx_RightPanel { - flex: 0 0 235px; -} - -.mx_MatrixChat .mx_RightPanel.collapsed { - flex: 0 0 122px; -} diff --git a/res/css/structures/_RightPanel.scss b/res/css/structures/_RightPanel.scss index b4dff612ed0..e0fb95e99cd 100644 --- a/res/css/structures/_RightPanel.scss +++ b/res/css/structures/_RightPanel.scss @@ -15,8 +15,10 @@ limitations under the License. */ .mx_RightPanel { + overflow-x: hidden; + flex: 0 0 auto; position: relative; - + min-width: 250px; display: flex; flex-direction: column; } From c56975d93dcc0f625cdadce360e61bca35774937 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 12:26:08 +0200 Subject: [PATCH 07/27] dont base collapse toggle size on min-width, as it's not available in collapsed state --- src/components/structures/LoggedInView.js | 7 +++++- src/resizer/distributors.js | 27 ++++++++--------------- src/resizer/event.js | 6 +++-- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 844221c9526..cc15df4edcf 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -98,7 +98,12 @@ const LoggedInView = React.createClass({ vertical: "mx_ResizeHandle_vertical", reverse: "mx_ResizeHandle_reverse" }; - makeResizeable(this.resizeContainer, classNames, CollapseDistributor); + const collapseToggleSize = 260 - 50; + makeResizeable( + this.resizeContainer, + classNames, + CollapseDistributor, + collapseToggleSize); }, componentWillMount: function() { diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index eda60c6fe3c..5a6e0f924a5 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -17,29 +17,20 @@ class FixedDistributor { class CollapseDistributor extends FixedDistributor { - constructor(container, items, handleIndex, direction, sizer) { + constructor(container, items, handleIndex, direction, sizer, toggleSize) { super(container, items, handleIndex, direction, sizer); - const style = getComputedStyle(this.item); - this.minWidth = parseInt(style.minWidth, 10); //auto becomes NaN + this.toggleSize = toggleSize; } resize(offset) { - let newWidth = offset - this.sizer.getItemOffset(this.item); - if (this.minWidth > 0) { - // -50 this is to not collapse immediately - // when moving the cursor past the minWidth - // to give some visual feedback you are about - // to collapse - // TODO: should 50 be configurable? minWidth/2 maybe? - if (offset < (this.minWidth - 50)) { - this.item.classList.add("collapsed"); - newWidth = this.minWidth; - } - else { - this.item.classList.remove("collapsed"); - } + let newSize = offset - this.sizer.getItemOffset(this.item); + if (newSize < this.toggleSize) { + this.item.classList.add("collapsed"); + } + else { + this.item.classList.remove("collapsed"); } - super.resize(newWidth); + super.resize(newSize); } } diff --git a/src/resizer/event.js b/src/resizer/event.js index 3baa67e097f..7619a3e91de 100644 --- a/src/resizer/event.js +++ b/src/resizer/event.js @@ -12,7 +12,7 @@ classNames: resizing: string */ -function makeResizeable(container, classNames, distributorCtor, sizerCtor = Sizer) { +function makeResizeable(container, classNames, distributorCtor, distributorCfg = undefined, sizerCtor = Sizer) { function isResizeHandle(el) { return el && el.classList.contains(classNames.handle); @@ -44,7 +44,9 @@ function makeResizeable(container, classNames, distributorCtor, sizerCtor = Size }); const prevItem = resizeHandle.previousElementSibling; const handleIndex = items.indexOf(prevItem) + 1; - const distributor = new distributorCtor(container, items, handleIndex, direction, sizer); + const distributor = new distributorCtor( + container, items, handleIndex, + direction, sizer, distributorCfg); const onMouseMove = (event) => { const offset = sizer.offsetFromEvent(event); From 99bf6b0e32b2d2fac2dd9baea0588e5c64c88d24 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 14:53:44 +0200 Subject: [PATCH 08/27] put dm icon back in it's correct location --- res/css/views/rooms/_RoomTile.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index daa9b640581..fd4f6565968 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -42,6 +42,10 @@ limitations under the License. height: 32px; } +.mx_RoomTile_avatar_container { + position: relative; +} + .mx_RoomTile_dm { display: block; position: absolute; From cc29dd08daff241839862072aa48dec7b5266133 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 14:54:14 +0200 Subject: [PATCH 09/27] don't always show badge (leftover) --- src/components/views/rooms/RoomTile.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index e70ea210f43..1afff783a1a 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -243,7 +243,6 @@ module.exports = React.createClass({ }, render: function() { - this.state.badgeHover = true; const isInvite = this.props.room.getMyMembership() === "invite"; const notificationCount = this.state.notificationCount; // var highlightCount = this.props.room.getUnreadNotificationCount("highlight"); From 8fa22d620a5e35506e2d7b858a8169c56248fee1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 14:54:30 +0200 Subject: [PATCH 10/27] align badge and make it non-flex when collapsed --- res/css/views/rooms/_RoomTile.scss | 41 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index fd4f6565968..4ad057e3d64 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -20,8 +20,8 @@ limitations under the License. align-items: center; cursor: pointer; height: 40px; - margin: 0px 9px 0px 9px; - + margin: 0px 3px; + position: relative; background-color: $secondary-accent-color; } @@ -69,20 +69,30 @@ limitations under the License. /* color: rgba(69, 69, 69, 0.5); */ } -.collapsed .mx_RoomTile_name { - display: none; -} +.collapsed { + .mx_RoomTile_name { + display: none; + } -.collapsed .mx_RoomTile_badge { - min-width: 12px; - border-radius: 16px; - padding: 0px 4px 0px 4px; - z-index: 3; -} + .mx_RoomTile_badge { + min-width: 12px; + border-radius: 16px; + padding: 0px 4px 0px 4px; + z-index: 3; + } + + /* Hide the bottom of speech bubble */ + .mx_RoomTile_highlight .mx_RoomTile_badge:after { + display: none; + } -/* Hide the bottom of speech bubble */ -.collapsed .mx_RoomTile_highlight .mx_RoomTile_badge:after { - display: none; + .mx_RoomTile_badge { + display: block; + position: absolute; + height: 15px; + right: 5px; + top: 2px; + } } /* This is the bottom of the speech bubble */ @@ -100,9 +110,6 @@ limitations under the License. .mx_RoomTile_badge { flex: 0 1 content; min-width: 15px; - height: 15px; - right: 8px; /*gutter */ - top: 9px; border-radius: 8px; color: $accent-fg-color; font-weight: 600; From 529845d8fc770e2a11a46727b8a712fe6af5f5ad Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 14:55:35 +0200 Subject: [PATCH 11/27] group collapsed styles --- res/css/structures/_RoomSubList.scss | 79 +++++++++++++--------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 961fd03d215..2ddf383fde3 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -55,15 +55,6 @@ limitations under the License. /* pointer-events: none; */ } -.collapsed .mx_RoomSubList_label { - height: 17px; - width: 28px; /* collapsed LHS Panel width */ -} - -.collapsed .mx_RoomSubList_labelContainer { - width: 28px; /* collapsed LHS Panel width */ -} - .mx_RoomSubList_roomCount { display: inline-block; font-size: 12px; @@ -73,10 +64,6 @@ limitations under the License. text-transform: none; } -.collapsed .mx_RoomSubList_roomCount { - display: none; -} - .mx_RoomSubList_badge { display: inline-block; min-width: 15px; @@ -99,12 +86,6 @@ limitations under the License. filter: brightness($focus-brightness); } -/* -.collapsed .mx_RoomSubList_badge { - display: none; -} -*/ - .mx_RoomSubList_badgeHighlight { background-color: $warning-color; } @@ -121,11 +102,6 @@ limitations under the License. border-right: 7px solid transparent; } -/* Hide the bottom of speech bubble */ -.collapsed .mx_RoomSubList_badgeHighlight:after { - display: none; -} - .mx_RoomSubList_chevron { left: 0px; pointer-events: none; @@ -163,10 +139,6 @@ limitations under the License. background-color: $secondary-accent-color; } -.collapsed .mx_RoomSubList_ellipsis { - height: 20px; -} - .mx_RoomSubList_line { display: inline-block; width: 159px; @@ -174,10 +146,6 @@ limitations under the License. vertical-align: middle; } -.collapsed .mx_RoomSubList_line { - display: none; -} - .mx_RoomSubList_more { display: inline-block; text-transform: uppercase; @@ -191,10 +159,6 @@ limitations under the License. vertical-align: middle; } -.collapsed .mx_RoomSubList_more { - display: none; -} - .mx_RoomSubList_moreBadge { display: inline-block; min-width: 15px; @@ -231,12 +195,6 @@ limitations under the License. padding-right: 4px; } -.collapsed .mx_RoomSubList_moreBadge { - position: static; - margin-left: 16px; - margin-top: 2px; -} - .mx_RoomSubList_ellipsis .mx_RoomSubList_chevronDown { position: relative; top: 4px; @@ -244,3 +202,40 @@ limitations under the License. } +.collapsed { + .mx_RoomSubList_label { + height: 17px; + width: 28px; /* collapsed LHS Panel width */ + } + + .mx_RoomSubList_labelContainer { + width: 28px; /* collapsed LHS Panel width */ + } + + .mx_RoomSubList_roomCount { + display: none; + } + + /* Hide the bottom of speech bubble */ + .mx_RoomSubList_badgeHighlight:after { + display: none; + } + + .mx_RoomSubList_line { + display: none; + } + + .mx_RoomSubList_moreBadge { + position: static; + margin-left: 16px; + margin-top: 2px; + } + + .mx_RoomSubList_ellipsis { + height: 20px; + } + + .mx_RoomSubList_more { + display: none; + } +} From c095e30ae430a10b84889d23652473895a24ce95 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 14:56:49 +0200 Subject: [PATCH 12/27] provide collapsed callback to also collapse on react side of things --- src/components/structures/LoggedInView.js | 11 ++++++++--- src/resizer/distributors.js | 11 +++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index cc15df4edcf..d6b374aac83 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -98,12 +98,17 @@ const LoggedInView = React.createClass({ vertical: "mx_ResizeHandle_vertical", reverse: "mx_ResizeHandle_reverse" }; - const collapseToggleSize = 260 - 50; + const config = { + toggleSize: 260 - 50, + onCollapsed: (collapsed) => { + this.setState({collapseLhs: collapsed}); + } + }; makeResizeable( this.resizeContainer, classNames, CollapseDistributor, - collapseToggleSize); + config); }, componentWillMount: function() { @@ -524,7 +529,7 @@ const LoggedInView = React.createClass({
this.resizeContainer = div} className={bodyClasses}> diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index 5a6e0f924a5..0d13360ef4e 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -17,18 +17,25 @@ class FixedDistributor { class CollapseDistributor extends FixedDistributor { - constructor(container, items, handleIndex, direction, sizer, toggleSize) { + constructor(container, items, handleIndex, direction, sizer, config) { super(container, items, handleIndex, direction, sizer); - this.toggleSize = toggleSize; + this.toggleSize = config && config.toggleSize; + this.onCollapsed = config && config.onCollapsed; } resize(offset) { let newSize = offset - this.sizer.getItemOffset(this.item); if (newSize < this.toggleSize) { this.item.classList.add("collapsed"); + if (this.onCollapsed) { + this.onCollapsed(true, this.item); + } } else { this.item.classList.remove("collapsed"); + if (this.onCollapsed) { + this.onCollapsed(false, this.item); + } } super.resize(newSize); } From 30003d8f91916d97bb04cedf3aaa057c58167a06 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 15:16:10 +0200 Subject: [PATCH 13/27] turn resizer into class to make programmatic interaction/cleanup easier --- src/components/structures/LoggedInView.js | 11 +-- src/resizer/event.js | 72 ----------------- src/resizer/index.js | 4 +- src/resizer/resizer.js | 94 +++++++++++++++++++++++ 4 files changed, 102 insertions(+), 79 deletions(-) delete mode 100644 src/resizer/event.js create mode 100644 src/resizer/resizer.js diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index d6b374aac83..11acb942b6a 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -35,7 +35,7 @@ import RoomListStore from "../../stores/RoomListStore"; import TagOrderActions from '../../actions/TagOrderActions'; import RoomListActions from '../../actions/RoomListActions'; import ResizeHandle from '../views/elements/ResizeHandle'; -import {makeResizeable, CollapseDistributor} from '../../resizer' +import {Resizer, CollapseDistributor} from '../../resizer' // We need to fetch each pinned message individually (if we don't already have it) // so each pinned message may trigger a request. Limit the number per room for sanity. // NB. this is just for server notices rather than pinned messages in general. @@ -98,17 +98,18 @@ const LoggedInView = React.createClass({ vertical: "mx_ResizeHandle_vertical", reverse: "mx_ResizeHandle_reverse" }; - const config = { + const collapseConfig = { toggleSize: 260 - 50, onCollapsed: (collapsed) => { this.setState({collapseLhs: collapsed}); } }; - makeResizeable( + const resizer = new Resizer( this.resizeContainer, - classNames, CollapseDistributor, - config); + collapseConfig); + resizer.setClassNames(classNames); + resizer.attach(); }, componentWillMount: function() { diff --git a/src/resizer/event.js b/src/resizer/event.js deleted file mode 100644 index 7619a3e91de..00000000000 --- a/src/resizer/event.js +++ /dev/null @@ -1,72 +0,0 @@ -import {Sizer} from "./sizer"; - -/* -classNames: - // class on resize-handle - handle: string - // class on resize-handle - reverse: string - // class on resize-handle - vertical: string - // class on container - resizing: string -*/ - -function makeResizeable(container, classNames, distributorCtor, distributorCfg = undefined, sizerCtor = Sizer) { - - function isResizeHandle(el) { - return el && el.classList.contains(classNames.handle); - } - - function handleMouseDown(event) { - const target = event.target; - if (!isResizeHandle(target) || target.parentElement !== container) { - return; - } - // prevent starting a drag operation - event.preventDefault(); - // mark as currently resizing - if (classNames.resizing) { - container.classList.add(classNames.resizing); - } - - const resizeHandle = event.target; - const vertical = resizeHandle.classList.contains(classNames.vertical); - const reverse = resizeHandle.classList.contains(classNames.reverse); - const direction = reverse ? 0 : -1; - - const sizer = new sizerCtor(container, vertical, reverse); - - const items = Array.from(container.children).filter(el => { - return !isResizeHandle(el) && ( - isResizeHandle(el.previousElementSibling) || - isResizeHandle(el.nextElementSibling)); - }); - const prevItem = resizeHandle.previousElementSibling; - const handleIndex = items.indexOf(prevItem) + 1; - const distributor = new distributorCtor( - container, items, handleIndex, - direction, sizer, distributorCfg); - - const onMouseMove = (event) => { - const offset = sizer.offsetFromEvent(event); - distributor.resize(offset); - }; - - const body = document.body; - const onMouseUp = (event) => { - if (classNames.resizing) { - container.classList.remove(classNames.resizing); - } - const offset = sizer.offsetFromEvent(event); - distributor.finish(offset); - body.removeEventListener("mouseup", onMouseUp, false); - body.removeEventListener("mousemove", onMouseMove, false); - }; - body.addEventListener("mouseup", onMouseUp, false); - body.addEventListener("mousemove", onMouseMove, false); - } - container.addEventListener("mousedown", handleMouseDown, false); -} - -module.exports = {makeResizeable}; diff --git a/src/resizer/index.js b/src/resizer/index.js index fba384ebb91..4b335ce4a47 100644 --- a/src/resizer/index.js +++ b/src/resizer/index.js @@ -1,9 +1,9 @@ import {Sizer} from "./sizer"; import {FixedDistributor, CollapseDistributor, PercentageDistributor} from "./distributors"; -import {makeResizeable} from "./event"; +import {Resizer} from "./resizer"; module.exports = { - makeResizeable, + Resizer, Sizer, FixedDistributor, CollapseDistributor, diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js new file mode 100644 index 00000000000..a2affa53acd --- /dev/null +++ b/src/resizer/resizer.js @@ -0,0 +1,94 @@ +import {Sizer} from "./sizer"; + +/* +classNames: + // class on resize-handle + handle: string + // class on resize-handle + reverse: string + // class on resize-handle + vertical: string + // class on container + resizing: string +*/ + +export class Resizer { + constructor(container, distributorCtor, distributorCfg, sizerCtor = Sizer) { + this.container = container; + this.distributorCtor = distributorCtor; + this.distributorCfg = distributorCfg; + this.sizerCtor = sizerCtor; + this.classNames = { + handle: "resizer-handle", + reverse: "resizer-reverse", + vertical: "resizer-vertical", + resizing: "resizer-resizing", + }; + this.mouseDownHandler = (event) => this._onMouseDown(event); + } + + setClassNames(classNames) { + this.classNames = classNames; + } + + attach() { + this.container.addEventListener("mousedown", this.mouseDownHandler, false); + } + + detach() { + this.container.removeEventListener("mousedown", this.mouseDownHandler, false); + } + + _isResizeHandle(el) { + return el && el.classList.contains(this.classNames.handle); + } + + _onMouseDown(event) { + const target = event.target; + if (!this._isResizeHandle(target) || target.parentElement !== this.container) { + return; + } + // prevent starting a drag operation + event.preventDefault(); + // mark as currently resizing + if (this.classNames.resizing) { + this.container.classList.add(this.classNames.resizing); + } + + const resizeHandle = event.target; + const vertical = resizeHandle.classList.contains(this.classNames.vertical); + const reverse = resizeHandle.classList.contains(this.classNames.reverse); + const direction = reverse ? 0 : -1; + + const sizer = new this.sizerCtor(this.container, vertical, reverse); + + const items = Array.from(this.container.children).filter(el => { + return !this._isResizeHandle(el) && ( + this._isResizeHandle(el.previousElementSibling) || + this._isResizeHandle(el.nextElementSibling)); + }); + const prevItem = resizeHandle.previousElementSibling; + const handleIndex = items.indexOf(prevItem) + 1; + const distributor = new this.distributorCtor( + this.container, items, handleIndex, + direction, sizer, this.distributorCfg); + + const onMouseMove = (event) => { + const offset = sizer.offsetFromEvent(event); + distributor.resize(offset); + }; + + const body = document.body; + const onMouseUp = (event) => { + if (this.classNames.resizing) { + this.container.classList.remove(this.classNames.resizing); + } + const offset = sizer.offsetFromEvent(event); + distributor.finish(offset); + body.removeEventListener("mouseup", onMouseUp, false); + body.removeEventListener("mousemove", onMouseMove, false); + }; + body.addEventListener("mouseup", onMouseUp, false); + body.addEventListener("mousemove", onMouseMove, false); + } +} From 650e19ff7732dba842743c3878d4517ff0180c38 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 16:25:00 +0200 Subject: [PATCH 14/27] don't expose direction, handleIndex to distributor ctor --- src/resizer/distributors.js | 21 +++++++++++---------- src/resizer/resizer.js | 23 ++++++++++++++--------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index 0d13360ef4e..884402b1b03 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -1,8 +1,8 @@ class FixedDistributor { - constructor(container, items, handleIndex, direction, sizer) { - this.item = items[handleIndex + direction]; - this.beforeOffset = sizer.getItemOffset(this.item); + constructor(sizer, item) { this.sizer = sizer; + this.item = item; + this.beforeOffset = sizer.getItemOffset(this.item); } resize(offset) { @@ -17,8 +17,8 @@ class FixedDistributor { class CollapseDistributor extends FixedDistributor { - constructor(container, items, handleIndex, direction, sizer, config) { - super(container, items, handleIndex, direction, sizer); + constructor(sizer, item, config) { + super(sizer, item); this.toggleSize = config && config.toggleSize; this.onCollapsed = config && config.onCollapsed; } @@ -43,16 +43,17 @@ class CollapseDistributor extends FixedDistributor { class PercentageDistributor { - constructor(container, items, handleIndex, direction, sizer) { + constructor(sizer, item, _config, items, container) { this.container = container; this.totalSize = sizer.getTotalSize(); this.sizer = sizer; - this.beforeItems = items.slice(0, handleIndex); - this.afterItems = items.slice(handleIndex); + const itemIndex = items.indexOf(item); + this.beforeItems = items.slice(0, itemIndex); + this.afterItems = items.slice(itemIndex); const percentages = PercentageDistributor._getPercentages(sizer, items); - this.beforePercentages = percentages.slice(0, handleIndex); - this.afterPercentages = percentages.slice(handleIndex); + this.beforePercentages = percentages.slice(0, itemIndex); + this.afterPercentages = percentages.slice(itemIndex); } resize(offset) { diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index a2affa53acd..e2581e982bb 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -58,20 +58,17 @@ export class Resizer { const resizeHandle = event.target; const vertical = resizeHandle.classList.contains(this.classNames.vertical); const reverse = resizeHandle.classList.contains(this.classNames.reverse); - const direction = reverse ? 0 : -1; const sizer = new this.sizerCtor(this.container, vertical, reverse); - const items = Array.from(this.container.children).filter(el => { - return !this._isResizeHandle(el) && ( - this._isResizeHandle(el.previousElementSibling) || - this._isResizeHandle(el.nextElementSibling)); - }); + const items = this._getResizableItems(); const prevItem = resizeHandle.previousElementSibling; - const handleIndex = items.indexOf(prevItem) + 1; + // if reverse, resize the item after the handle, so + 1 + const itemIndex = items.indexOf(prevItem) + (reverse ? 1 : 0); + const item = items[itemIndex]; const distributor = new this.distributorCtor( - this.container, items, handleIndex, - direction, sizer, this.distributorCfg); + sizer, item, this.distributorCfg, + items, this.container); const onMouseMove = (event) => { const offset = sizer.offsetFromEvent(event); @@ -91,4 +88,12 @@ export class Resizer { body.addEventListener("mouseup", onMouseUp, false); body.addEventListener("mousemove", onMouseMove, false); } + + _getResizableItems() { + return Array.from(this.container.children).filter(el => { + return !this._isResizeHandle(el) && ( + this._isResizeHandle(el.previousElementSibling) || + this._isResizeHandle(el.nextElementSibling)); + }); + } } From bb184a4ae06614c549ad11e950771261202b1e47 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 17:22:12 +0200 Subject: [PATCH 15/27] support programmatic access to a distributor (to set size from storage) --- src/resizer/distributors.js | 11 ++++----- src/resizer/resizer.js | 47 ++++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index 884402b1b03..bd0b1221034 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -11,7 +11,8 @@ class FixedDistributor { return itemSize; } - finish(_offset) { + sizeFromOffset(offset) { + return offset - this.beforeOffset; } } @@ -24,7 +25,7 @@ class CollapseDistributor extends FixedDistributor { } resize(offset) { - let newSize = offset - this.sizer.getItemOffset(this.item); + let newSize = this.sizeFromOffset(offset); if (newSize < this.toggleSize) { this.item.classList.add("collapsed"); if (this.onCollapsed) { @@ -37,7 +38,7 @@ class CollapseDistributor extends FixedDistributor { this.onCollapsed(false, this.item); } } - super.resize(newSize); + super.resize(offset); } } @@ -75,10 +76,6 @@ class PercentageDistributor { }); } - finish(_offset) { - - } - static _getPercentages(sizer, items) { const percentages = items.map(i => sizer.getItemPercentage(i)); const setPercentages = percentages.filter(p => p !== null); diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index e2581e982bb..dc74b5b699b 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -39,6 +39,13 @@ export class Resizer { this.container.removeEventListener("mousedown", this.mouseDownHandler, false); } + forHandleAt(handleIndex) { + const handles = this._getResizeHandles(); + const handle = handles[handleIndex]; + const {distributor} = this._createSizerAndDistributor(handle); + return distributor; + } + _isResizeHandle(el) { return el && el.classList.contains(this.classNames.handle); } @@ -55,20 +62,7 @@ export class Resizer { this.container.classList.add(this.classNames.resizing); } - const resizeHandle = event.target; - const vertical = resizeHandle.classList.contains(this.classNames.vertical); - const reverse = resizeHandle.classList.contains(this.classNames.reverse); - - 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, so + 1 - const itemIndex = items.indexOf(prevItem) + (reverse ? 1 : 0); - const item = items[itemIndex]; - const distributor = new this.distributorCtor( - sizer, item, this.distributorCfg, - items, this.container); + const {sizer, distributor} = this._createSizerAndDistributor(target); const onMouseMove = (event) => { const offset = sizer.offsetFromEvent(event); @@ -80,8 +74,6 @@ export class Resizer { if (this.classNames.resizing) { this.container.classList.remove(this.classNames.resizing); } - const offset = sizer.offsetFromEvent(event); - distributor.finish(offset); body.removeEventListener("mouseup", onMouseUp, false); body.removeEventListener("mousemove", onMouseMove, false); }; @@ -89,6 +81,23 @@ export class Resizer { body.addEventListener("mousemove", onMouseMove, false); } + _createSizerAndDistributor(resizeHandle) { + const vertical = resizeHandle.classList.contains(this.classNames.vertical); + const reverse = resizeHandle.classList.contains(this.classNames.reverse); + + 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 distributor = new this.distributorCtor( + sizer, item, this.distributorCfg, + items, this.container); + return {sizer, distributor}; + } + _getResizableItems() { return Array.from(this.container.children).filter(el => { return !this._isResizeHandle(el) && ( @@ -96,4 +105,10 @@ export class Resizer { this._isResizeHandle(el.nextElementSibling)); }); } + + _getResizeHandles() { + return Array.from(this.container.children).filter(el => { + return this._isResizeHandle(el); + }); + } } From 1d2e1d4b6bb90d8abe25379993853ccf70fecb45 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 17:38:34 +0200 Subject: [PATCH 16/27] make it work for now, probably want to rename this back later on --- src/components/structures/LeftPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index a1814828140..d36907c2110 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -205,7 +205,7 @@ var LeftPanel = React.createClass({ const containerClasses = classNames( "mx_LeftPanel_container", "mx_fadable", { - "mx_LeftPanel_container_collapsed": this.props.collapsed, + "collapsed": this.props.collapsed, "mx_LeftPanel_container_hasTagPanel": tagPanelEnabled, "mx_fadable_faded": this.props.disabled, }, From 28ec0f7462a379063d03e321be3000c231fac60e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 18:42:56 +0200 Subject: [PATCH 17/27] onResized callback --- src/resizer/distributors.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index bd0b1221034..8b33ccabbab 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -1,13 +1,17 @@ class FixedDistributor { - constructor(sizer, item) { + constructor(sizer, item, config) { this.sizer = sizer; this.item = item; this.beforeOffset = sizer.getItemOffset(this.item); + this.onResized = config.onResized; } resize(offset) { const itemSize = offset - this.beforeOffset; this.sizer.setItemSize(this.item, itemSize); + if (this.onResized) { + this.onResized(itemSize, this.item); + } return itemSize; } @@ -19,7 +23,7 @@ class FixedDistributor { class CollapseDistributor extends FixedDistributor { constructor(sizer, item, config) { - super(sizer, item); + super(sizer, item, config); this.toggleSize = config && config.toggleSize; this.onCollapsed = config && config.onCollapsed; } From 3a26f0fa12bdb8384cd89eb6009efb8d96ff580a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 18:43:13 +0200 Subject: [PATCH 18/27] only fire onCollapsed once when changing --- src/resizer/distributors.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index 8b33ccabbab..dbc35fc6c90 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -26,23 +26,27 @@ class CollapseDistributor extends FixedDistributor { super(sizer, item, config); this.toggleSize = config && config.toggleSize; this.onCollapsed = config && config.onCollapsed; + this.isCollapsed = false; } resize(offset) { let newSize = this.sizeFromOffset(offset); - if (newSize < this.toggleSize) { - this.item.classList.add("collapsed"); + const isCollapsedSize = newSize < this.toggleSize; + if (isCollapsedSize && !this.isCollapsed) { + this.isCollapsed = true; if (this.onCollapsed) { this.onCollapsed(true, this.item); } } - else { - this.item.classList.remove("collapsed"); + else if (!isCollapsedSize && this.isCollapsed) { if (this.onCollapsed) { this.onCollapsed(false, this.item); } + this.isCollapsed = false; + } + if (!isCollapsedSize) { + super.resize(offset); } - super.resize(offset); } } From 110e4526b856e9df93c10fe8e2243650d489d9f6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 16 Oct 2018 18:43:40 +0200 Subject: [PATCH 19/27] store/load lhs & rhs sizes to/from localStorage --- src/components/structures/LoggedInView.js | 64 +++++++++++++++++------ 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 11acb942b6a..db600abbf2e 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -93,23 +93,9 @@ const LoggedInView = React.createClass({ }, componentDidMount: function() { - const classNames = { - handle: "mx_ResizeHandle", - vertical: "mx_ResizeHandle_vertical", - reverse: "mx_ResizeHandle_reverse" - }; - const collapseConfig = { - toggleSize: 260 - 50, - onCollapsed: (collapsed) => { - this.setState({collapseLhs: collapsed}); - } - }; - const resizer = new Resizer( - this.resizeContainer, - CollapseDistributor, - collapseConfig); - resizer.setClassNames(classNames); - resizer.attach(); + this.resizer = this._createResizer(); + this.resizer.attach(); + this._loadResizerPreferences(); }, componentWillMount: function() { @@ -141,6 +127,7 @@ const LoggedInView = React.createClass({ if (this._sessionStoreToken) { this._sessionStoreToken.remove(); } + this.resizer.detach(); }, // Child components assume that the client peg will not be null, so give them some @@ -166,6 +153,49 @@ const LoggedInView = React.createClass({ }); }, + _createResizer() { + const classNames = { + handle: "mx_ResizeHandle", + vertical: "mx_ResizeHandle_vertical", + reverse: "mx_ResizeHandle_reverse" + }; + const collapseConfig = { + toggleSize: 260 - 50, + onCollapsed: (collapsed, item) => { + if (item.classList.contains("mx_LeftPanel_container")) { + this.setState({collapseLhs: collapsed}); + if (collapsed) { + window.localStorage.setItem("mx_lhs_size", '0'); + } + } + }, + onResized: (size, item) => { + if (item.classList.contains("mx_LeftPanel_container")) { + window.localStorage.setItem("mx_lhs_size", '' + size); + } else if(item.classList.contains("mx_RightPanel")) { + window.localStorage.setItem("mx_rhs_size", '' + size); + } + }, + }; + const resizer = new Resizer( + this.resizeContainer, + CollapseDistributor, + collapseConfig); + resizer.setClassNames(classNames); + return resizer; + }, + + _loadResizerPreferences() { + const lhsSize = window.localStorage.getItem("mx_lhs_size"); + if (lhsSize !== null) { + this.resizer.forHandleAt(0).resize(parseInt(lhsSize, 10)); + } + const rhsSize = window.localStorage.getItem("mx_rhs_size"); + if (rhsSize !== null) { + this.resizer.forHandleAt(1).resize(parseInt(rhsSize, 10)); + } + }, + onAccountData: function(event) { if (event.getType() === "im.vector.web.settings") { this.setState({ From 6fdcebb876a90dc6f8186cc3f99ac23af77c972a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Oct 2018 11:38:25 +0200 Subject: [PATCH 20/27] add copyright headers --- src/resizer/distributors.js | 16 ++++++++++++++++ src/resizer/index.js | 16 ++++++++++++++++ src/resizer/resizer.js | 16 ++++++++++++++++ src/resizer/room.js | 16 ++++++++++++++++ src/resizer/sizer.js | 16 ++++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index dbc35fc6c90..93a75d474e3 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -1,3 +1,19 @@ +/* +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. +*/ + class FixedDistributor { constructor(sizer, item, config) { this.sizer = sizer; diff --git a/src/resizer/index.js b/src/resizer/index.js index 4b335ce4a47..f0c5878a1d7 100644 --- a/src/resizer/index.js +++ b/src/resizer/index.js @@ -1,3 +1,19 @@ +/* +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 {Sizer} from "./sizer"; import {FixedDistributor, CollapseDistributor, PercentageDistributor} from "./distributors"; import {Resizer} from "./resizer"; diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index dc74b5b699b..8888287b86d 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -1,3 +1,19 @@ +/* +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 {Sizer} from "./sizer"; /* diff --git a/src/resizer/room.js b/src/resizer/room.js index 0080cca3eb8..a6ad0b5dc25 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -1,3 +1,19 @@ +/* +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 {Sizer} from "./sizer"; import {FixedDistributor} from "./distributors"; diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index 2dc116714f2..b39aaea2861 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -1,3 +1,19 @@ +/* +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. +*/ + class Sizer { constructor(container, vertical, reverse) { this.container = container; From 8d3347bcfbcdd1d307cfeba81af438c7f263e72f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Oct 2018 13:36:15 +0200 Subject: [PATCH 21/27] fix lint --- src/components/views/elements/ResizeHandle.js | 2 +- src/resizer/distributors.js | 5 ++--- src/resizer/resizer.js | 2 ++ src/resizer/sizer.js | 20 ++++++++++++++----- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/components/views/elements/ResizeHandle.js b/src/components/views/elements/ResizeHandle.js index ae324a752b1..4c09278f84f 100644 --- a/src/components/views/elements/ResizeHandle.js +++ b/src/components/views/elements/ResizeHandle.js @@ -14,7 +14,7 @@ const ResizeHandle = (props) => { classNames.push('mx_ResizeHandle_reverse'); } return ( -
+
); }; diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index 93a75d474e3..a5ef48e5719 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -46,15 +46,14 @@ class CollapseDistributor extends FixedDistributor { } resize(offset) { - let newSize = this.sizeFromOffset(offset); + const newSize = this.sizeFromOffset(offset); const isCollapsedSize = newSize < this.toggleSize; if (isCollapsedSize && !this.isCollapsed) { this.isCollapsed = true; if (this.onCollapsed) { this.onCollapsed(true, this.item); } - } - else if (!isCollapsedSize && this.isCollapsed) { + } else if (!isCollapsedSize && this.isCollapsed) { if (this.onCollapsed) { this.onCollapsed(false, this.item); } diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 8888287b86d..10f08aa5464 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -101,6 +101,7 @@ export class Resizer { const vertical = resizeHandle.classList.contains(this.classNames.vertical); const reverse = resizeHandle.classList.contains(this.classNames.reverse); + // eslint-disable-next-line new-cap const sizer = new this.sizerCtor(this.container, vertical, reverse); const items = this._getResizableItems(); @@ -108,6 +109,7 @@ export class Resizer { // 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]; + // eslint-disable-next-line new-cap const distributor = new this.distributorCtor( sizer, item, this.distributorCfg, items, this.container); diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index b39aaea2861..674ea1823c3 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -39,7 +39,10 @@ class Sizer { item.style.flexGrow = Math.round(percent * 1000); } - /** returns how far the edge of the item is from the edge of the container */ + /** + @param {Element} item the dom element being resized + @return {number} how far the edge of the item is from the edge of the container + */ getItemOffset(item) { const offset = (this.vertical ? item.offsetTop : item.offsetLeft) - this._getOffset(); if (this.reverse) { @@ -49,17 +52,20 @@ class Sizer { } } - /** returns the width/height of an item in the container */ + /** + @param {Element} item the dom element being resized + @return {number} the width/height of an item in the container + */ getItemSize(item) { return this.vertical ? item.offsetHeight : item.offsetWidth; } - /** returns the width/height of the container */ + /** @return {number} the width/height of the container */ getTotalSize() { return this.vertical ? this.container.offsetHeight : this.container.offsetWidth; } - /** container offset to offsetParent */ + /** @return {number} container offset to offsetParent */ _getOffset() { return this.vertical ? this.container.offsetTop : this.container.offsetLeft; } @@ -72,7 +78,11 @@ class Sizer { } } - /** returns the position of cursor at event relative to the edge of the container */ + /** + @param {MouseEvent} event the mouse event + @return {number} the distance between the cursor and the edge of the container, + along the applicable axis (vertical or horizontal) + */ offsetFromEvent(event) { const pos = this.vertical ? event.pageY : event.pageX; if (this.reverse) { From d8ead8a8bb69a382bdacb29f1cc51ff0f8f16a27 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Oct 2018 13:42:30 +0200 Subject: [PATCH 22/27] add some description to some classes --- src/resizer/distributors.js | 8 ++++++++ src/resizer/sizer.js | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index a5ef48e5719..a4dfd9b8716 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -14,6 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ +/** +distributors translate a moving cursor into +CSS/DOM changes by calling the sizer + +they have one method, `resize` that receives +the offset from the container edge of where +the mouse cursor is. +*/ class FixedDistributor { constructor(sizer, item, config) { this.sizer = sizer; diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index 674ea1823c3..b8d1c55dd07 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -14,6 +14,10 @@ See the License for the specific language governing permissions and 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 { constructor(container, vertical, reverse) { this.container = container; From 8d414d098683df107264ee2b686d6e68e4d2c7b5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Oct 2018 13:45:56 +0200 Subject: [PATCH 23/27] more docs --- src/resizer/resizer.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 10f08aa5464..f207f4a2153 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -55,6 +55,12 @@ export class Resizer { this.container.removeEventListener("mousedown", this.mouseDownHandler, false); } + /** + Gives the distributor for a specific resize handle, as if you would have started + to drag that handle. Can be used to manipulate the size of an item programmatically. + @param {number} handleIndex the index of the resize handle in the container + @return {Distributor} a new distributor for the given handle + */ forHandleAt(handleIndex) { const handles = this._getResizeHandles(); const handle = handles[handleIndex]; From c926aa2bfe64d6fd1cb7351ec86e2169335e46cb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 17 Oct 2018 14:01:45 +0200 Subject: [PATCH 24/27] remove .collapsed class on mx_LeftPanel as the container already has it --- src/components/structures/LeftPanel.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index d36907c2110..ab491cc65eb 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -192,13 +192,6 @@ var LeftPanel = React.createClass({ topBox = ; } */ - const classes = classNames( - "mx_LeftPanel", - { - "collapsed": this.props.collapsed, - }, - ); - const tagPanelEnabled = !SettingsStore.getValue("TagPanel.disableTagPanel"); const tagPanel = tagPanelEnabled ? :
; @@ -214,7 +207,7 @@ var LeftPanel = React.createClass({ return (
{ tagPanel } -