From 4a195dd3f065fdd2e75a1c8b1538f3e36100a5ea Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 7 Nov 2015 02:57:56 +0000 Subject: [PATCH] sacrifice a small mountainside of goats to make placeholder-based work correctly --- .../vector/css/molecules/RoomDropTarget.css | 5 ++ src/skins/vector/css/molecules/RoomTile.css | 4 +- .../vector/views/molecules/RoomDropTarget.js | 22 +++++--- src/skins/vector/views/molecules/RoomTile.js | 55 +++++++++++++++++-- .../vector/views/organisms/RoomSubList.js | 23 +++++--- 5 files changed, 88 insertions(+), 21 deletions(-) diff --git a/src/skins/vector/css/molecules/RoomDropTarget.css b/src/skins/vector/css/molecules/RoomDropTarget.css index 549fa609ec..5e3facc4e2 100644 --- a/src/skins/vector/css/molecules/RoomDropTarget.css +++ b/src/skins/vector/css/molecules/RoomDropTarget.css @@ -26,6 +26,11 @@ limitations under the License. border-radius: 4px; } +.mx_RoomDropTarget_placeholder { + padding-top: 1px; + padding-bottom: 1px; +} + .mx_RoomDropTarget_avatar { background-color: #fff; border-radius: 24px; diff --git a/src/skins/vector/css/molecules/RoomTile.css b/src/skins/vector/css/molecules/RoomTile.css index b62552252b..4bc71cb801 100644 --- a/src/skins/vector/css/molecules/RoomTile.css +++ b/src/skins/vector/css/molecules/RoomTile.css @@ -16,7 +16,8 @@ limitations under the License. .mx_RoomTile { cursor: pointer; - display: table-row; + /* This fixes wrapping of long room names, but breaks drag & drop previews */ + /* display: table-row; */ font-size: 14px; } @@ -38,6 +39,7 @@ limitations under the License. .mx_RoomTile_name { display: table-cell; + width: 100%; vertical-align: middle; overflow: hidden; text-overflow: ellipsis; diff --git a/src/skins/vector/views/molecules/RoomDropTarget.js b/src/skins/vector/views/molecules/RoomDropTarget.js index c1a2a9548f..00d0546c90 100644 --- a/src/skins/vector/views/molecules/RoomDropTarget.js +++ b/src/skins/vector/views/molecules/RoomDropTarget.js @@ -22,13 +22,21 @@ module.exports = React.createClass({ displayName: 'RoomDropTarget', render: function() { - return ( -
-
-
- { this.props.label } + if (this.props.placeholder) { + return ( +
-
- ); + ); + } + else { + return ( +
+
+
+ { this.props.label } +
+
+ ); + } } }); diff --git a/src/skins/vector/views/molecules/RoomTile.js b/src/skins/vector/views/molecules/RoomTile.js index a8f646aeab..28e76a7034 100644 --- a/src/skins/vector/views/molecules/RoomTile.js +++ b/src/skins/vector/views/molecules/RoomTile.js @@ -43,10 +43,16 @@ var roomTileSource = { originalList: props.roomSubList, originalIndex: props.roomSubList.findRoomTile(props.room).index, targetList: props.roomSubList, // at first target is same as original + lastTargetRoom: null, + lastYOffset: null, + lastYDelta: null, }; console.log("roomTile beginDrag for " + item.room.roomId); + // doing this 'correctly' with state causes react-dnd to break seemingly due to the state transitions + props.room._dragging = true; + return item; }, @@ -56,6 +62,11 @@ var roomTileSource = { console.log("roomTile endDrag for " + item.room.roomId + " with didDrop=" + monitor.didDrop()); + props.room._dragging = false; + if (monitor.didDrop()) { + monitor.getDropResult().component.forceUpdate(); // as we're not using state + } + if (monitor.didDrop() && item.targetList.props.editable) { // if we moved lists, remove the old tag if (item.targetList !== item.originalList) { @@ -112,7 +123,8 @@ var roomTileTarget = { hover: function(props, monitor) { var item = monitor.getItem(); - //console.log("hovering on room " + props.room.roomId + ", isOver=" + monitor.isOver()); + var off = monitor.getClientOffset(); + // console.log("hovering on room " + props.room.roomId + ", isOver=" + monitor.isOver()); //console.log("item.targetList=" + item.targetList + ", roomSubList=" + props.roomSubList); @@ -120,7 +132,7 @@ var roomTileTarget = { if (item.targetList !== props.roomSubList) { // we've switched target, so remove the tile from the previous target. // n.b. the previous target might actually be the source list. - console.log("switched target"); + console.log("switched target sublist"); switchedTarget = true; item.targetList.removeRoomTile(item.room); item.targetList = props.roomSubList; @@ -129,10 +141,35 @@ var roomTileTarget = { if (!item.targetList.props.editable) return; if (item.targetList.props.order === 'manual') { - if (item.room.roomId !== props.room.roomId) { + if (item.room.roomId !== props.room.roomId && props.room !== item.lastTargetRoom) { + // find the offset of the target tile in the list. var roomTile = props.roomSubList.findRoomTile(props.room); + // shuffle the list to add our tile to that position. props.roomSubList.moveRoomTile(item.room, roomTile.index); } + + // stop us from flickering between our droptarget and the previous room. + // whenever the cursor changes direction we have to reset the flicker-damping. + + var yDelta = off.y - item.lastYOffset; + + if ((yDelta > 0 && item.lastYDelta < 0) || + (yDelta < 0 && item.lastYDelta > 0)) + { + // the cursor changed direction - forget our previous room + item.lastTargetRoom = null; + } + else { + // track the last room we were hovering over so we can stop + // bouncing back and forth if the droptarget is narrower than + // the other list items. The other way to do this would be + // to reduce the size of the hittarget on the list items, but + // can't see an easy way to do that. + item.lastTargetRoom = props.room; + } + + if (yDelta) item.lastYDelta = yDelta; + item.lastYOffset = off.y; } else if (switchedTarget) { if (!props.roomSubList.findRoomTile(item.room).room) { @@ -175,6 +212,15 @@ var RoomTile = React.createClass({ }, render: function() { + // if (this.props.clientOffset) { + // //console.log("room " + this.props.room.roomId + " has dropTarget clientOffset " + this.props.clientOffset.x + "," + this.props.clientOffset.y); + // } + + if (this.props.room._dragging) { + var RoomDropTarget = sdk.getComponent("molecules.RoomDropTarget"); + return ; + } + var myUserId = MatrixClientPeg.get().credentials.userId; var me = this.props.room.currentState.members[myUserId]; var classes = classNames({ @@ -247,11 +293,12 @@ var RoomTile = React.createClass({ // Export the wrapped version, inlining the 'collect' functions // to more closely resemble the ES7 module.exports = -DropTarget('RoomTile', roomTileTarget, function(connect) { +DropTarget('RoomTile', roomTileTarget, function(connect, monitor) { return { // Call this function inside render() // to let React DnD handle the drag events: connectDropTarget: connect.dropTarget(), + isOver: monitor.isOver(), } })( DragSource('RoomTile', roomTileSource, function(connect, monitor) { diff --git a/src/skins/vector/views/organisms/RoomSubList.js b/src/skins/vector/views/organisms/RoomSubList.js index b88bc3c70a..8dcccc733a 100644 --- a/src/skins/vector/views/organisms/RoomSubList.js +++ b/src/skins/vector/views/organisms/RoomSubList.js @@ -26,6 +26,11 @@ var roomListTarget = { return true; }, + drop: function(props, monitor, component) { + console.log("dropped on sublist") + return { component: component }; + }, + hover: function(props, monitor, component) { var item = monitor.getItem(); @@ -147,7 +152,7 @@ var RoomSubList = React.createClass({ findRoomTile: function(room) { var index = this.state.sortedList.indexOf(room); if (index >= 0) { - //console.log("found: room: " + room + " with id " + room.roomId); + // console.log("found: room: " + room.roomId + " with index " + index); } else { console.log("didn't find room"); @@ -210,14 +215,14 @@ var RoomSubList = React.createClass({ // XXX: is it evil to pass in self as a prop to RoomTile? return ( + room={ room } + roomSubList={ self } + key={ room.roomId } + collapsed={ self.props.collapsed } + selected={ selected } + unread={ self.props.activityMap[room.roomId] === 1 } + highlight={ self.props.activityMap[room.roomId] === 2 } + isInvite={ self.props.label === 'Invites' } /> ); }); },