sacrifice a small mountainside of goats to make placeholder-based work correctly

This commit is contained in:
Matthew Hodgson 2015-11-07 02:57:56 +00:00
parent fe442f5c24
commit 4a195dd3f0
5 changed files with 88 additions and 21 deletions

View File

@ -26,6 +26,11 @@ limitations under the License.
border-radius: 4px; border-radius: 4px;
} }
.mx_RoomDropTarget_placeholder {
padding-top: 1px;
padding-bottom: 1px;
}
.mx_RoomDropTarget_avatar { .mx_RoomDropTarget_avatar {
background-color: #fff; background-color: #fff;
border-radius: 24px; border-radius: 24px;

View File

@ -16,7 +16,8 @@ limitations under the License.
.mx_RoomTile { .mx_RoomTile {
cursor: pointer; cursor: pointer;
display: table-row; /* This fixes wrapping of long room names, but breaks drag & drop previews */
/* display: table-row; */
font-size: 14px; font-size: 14px;
} }
@ -38,6 +39,7 @@ limitations under the License.
.mx_RoomTile_name { .mx_RoomTile_name {
display: table-cell; display: table-cell;
width: 100%;
vertical-align: middle; vertical-align: middle;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;

View File

@ -22,13 +22,21 @@ module.exports = React.createClass({
displayName: 'RoomDropTarget', displayName: 'RoomDropTarget',
render: function() { render: function() {
return ( if (this.props.placeholder) {
<div className="mx_RoomDropTarget"> return (
<div className="mx_RoomDropTarget_avatar"></div> <div className="mx_RoomDropTarget mx_RoomDropTarget_placeholder">
<div className="mx_RoomDropTarget_label">
{ this.props.label }
</div> </div>
</div> );
); }
else {
return (
<div className="mx_RoomDropTarget">
<div className="mx_RoomDropTarget_avatar"></div>
<div className="mx_RoomDropTarget_label">
{ this.props.label }
</div>
</div>
);
}
} }
}); });

View File

@ -43,10 +43,16 @@ var roomTileSource = {
originalList: props.roomSubList, originalList: props.roomSubList,
originalIndex: props.roomSubList.findRoomTile(props.room).index, originalIndex: props.roomSubList.findRoomTile(props.room).index,
targetList: props.roomSubList, // at first target is same as original targetList: props.roomSubList, // at first target is same as original
lastTargetRoom: null,
lastYOffset: null,
lastYDelta: null,
}; };
console.log("roomTile beginDrag for " + item.room.roomId); 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; return item;
}, },
@ -56,6 +62,11 @@ var roomTileSource = {
console.log("roomTile endDrag for " + item.room.roomId + " with didDrop=" + monitor.didDrop()); 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 (monitor.didDrop() && item.targetList.props.editable) {
// if we moved lists, remove the old tag // if we moved lists, remove the old tag
if (item.targetList !== item.originalList) { if (item.targetList !== item.originalList) {
@ -112,7 +123,8 @@ var roomTileTarget = {
hover: function(props, monitor) { hover: function(props, monitor) {
var item = monitor.getItem(); 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); //console.log("item.targetList=" + item.targetList + ", roomSubList=" + props.roomSubList);
@ -120,7 +132,7 @@ var roomTileTarget = {
if (item.targetList !== props.roomSubList) { if (item.targetList !== props.roomSubList) {
// we've switched target, so remove the tile from the previous target. // we've switched target, so remove the tile from the previous target.
// n.b. the previous target might actually be the source list. // n.b. the previous target might actually be the source list.
console.log("switched target"); console.log("switched target sublist");
switchedTarget = true; switchedTarget = true;
item.targetList.removeRoomTile(item.room); item.targetList.removeRoomTile(item.room);
item.targetList = props.roomSubList; item.targetList = props.roomSubList;
@ -129,10 +141,35 @@ var roomTileTarget = {
if (!item.targetList.props.editable) return; if (!item.targetList.props.editable) return;
if (item.targetList.props.order === 'manual') { 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); var roomTile = props.roomSubList.findRoomTile(props.room);
// shuffle the list to add our tile to that position.
props.roomSubList.moveRoomTile(item.room, roomTile.index); 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) { else if (switchedTarget) {
if (!props.roomSubList.findRoomTile(item.room).room) { if (!props.roomSubList.findRoomTile(item.room).room) {
@ -175,6 +212,15 @@ var RoomTile = React.createClass({
}, },
render: function() { 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 <RoomDropTarget placeholder={true}/>;
}
var myUserId = MatrixClientPeg.get().credentials.userId; var myUserId = MatrixClientPeg.get().credentials.userId;
var me = this.props.room.currentState.members[myUserId]; var me = this.props.room.currentState.members[myUserId];
var classes = classNames({ var classes = classNames({
@ -247,11 +293,12 @@ var RoomTile = React.createClass({
// Export the wrapped version, inlining the 'collect' functions // Export the wrapped version, inlining the 'collect' functions
// to more closely resemble the ES7 // to more closely resemble the ES7
module.exports = module.exports =
DropTarget('RoomTile', roomTileTarget, function(connect) { DropTarget('RoomTile', roomTileTarget, function(connect, monitor) {
return { return {
// Call this function inside render() // Call this function inside render()
// to let React DnD handle the drag events: // to let React DnD handle the drag events:
connectDropTarget: connect.dropTarget(), connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
} }
})( })(
DragSource('RoomTile', roomTileSource, function(connect, monitor) { DragSource('RoomTile', roomTileSource, function(connect, monitor) {

View File

@ -26,6 +26,11 @@ var roomListTarget = {
return true; return true;
}, },
drop: function(props, monitor, component) {
console.log("dropped on sublist")
return { component: component };
},
hover: function(props, monitor, component) { hover: function(props, monitor, component) {
var item = monitor.getItem(); var item = monitor.getItem();
@ -147,7 +152,7 @@ var RoomSubList = React.createClass({
findRoomTile: function(room) { findRoomTile: function(room) {
var index = this.state.sortedList.indexOf(room); var index = this.state.sortedList.indexOf(room);
if (index >= 0) { if (index >= 0) {
//console.log("found: room: " + room + " with id " + room.roomId); // console.log("found: room: " + room.roomId + " with index " + index);
} }
else { else {
console.log("didn't find room"); 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? // XXX: is it evil to pass in self as a prop to RoomTile?
return ( return (
<RoomTile <RoomTile
room={room} room={ room }
roomSubList={self} roomSubList={ self }
key={room.roomId} key={ room.roomId }
collapsed={self.props.collapsed} collapsed={ self.props.collapsed }
selected={selected} selected={ selected }
unread={self.props.activityMap[room.roomId] === 1} unread={ self.props.activityMap[room.roomId] === 1 }
highlight={self.props.activityMap[room.roomId] === 2} highlight={ self.props.activityMap[room.roomId] === 2 }
isInvite={self.props.label === 'Invites'} /> isInvite={ self.props.label === 'Invites' } />
); );
}); });
}, },