mirror of
				https://github.com/vector-im/element-web.git
				synced 2025-11-04 10:11:03 +01:00 
			
		
		
		
	implement most of drag & drop.
This commit is contained in:
		
							parent
							
								
									7fe7af6026
								
							
						
					
					
						commit
						61e55b3ca3
					
				@ -17,6 +17,8 @@ limitations under the License.
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var React = require('react');
 | 
					var React = require('react');
 | 
				
			||||||
 | 
					var DragSource = require('react-dnd').DragSource;
 | 
				
			||||||
 | 
					var DropTarget = require('react-dnd').DropTarget;
 | 
				
			||||||
var classNames = require('classnames');
 | 
					var classNames = require('classnames');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var RoomTileController = require('matrix-react-sdk/lib/controllers/molecules/RoomTile')
 | 
					var RoomTileController = require('matrix-react-sdk/lib/controllers/molecules/RoomTile')
 | 
				
			||||||
@ -25,10 +27,89 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var sdk = require('matrix-react-sdk')
 | 
					var sdk = require('matrix-react-sdk')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = React.createClass({
 | 
					/**
 | 
				
			||||||
 | 
					 * Specifies the drag source contract.
 | 
				
			||||||
 | 
					 * Only `beginDrag` function is required.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var roomTileSource = {
 | 
				
			||||||
 | 
					    beginDrag: function (props) {
 | 
				
			||||||
 | 
					        // Return the data describing the dragged item
 | 
				
			||||||
 | 
					        var item = {
 | 
				
			||||||
 | 
					            room: props.room,
 | 
				
			||||||
 | 
					            originalList: props.roomSubList,            
 | 
				
			||||||
 | 
					            originalIndex: props.roomSubList.findRoomTile(props.room).index,
 | 
				
			||||||
 | 
					            targetList: props.roomSubList, // at first target is same as original
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        console.log("roomTile beginDrag for " + item.room.roomId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return item;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    endDrag: function (props, monitor, component) {
 | 
				
			||||||
 | 
					        var item = monitor.getItem();
 | 
				
			||||||
 | 
					        var dropResult = monitor.getDropResult();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        console.log("roomTile endDrag for " + item.room.roomId + " with didDrop=" + monitor.didDrop());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!monitor.didDrop() || !item.targetList.props.editable) {
 | 
				
			||||||
 | 
					            props.roomSubList.moveRoomTile(item.room, item.originalIndex);
 | 
				
			||||||
 | 
					            if (item.targetList && item.targetList !== item.originalList) {
 | 
				
			||||||
 | 
					                item.targetList.removeRoomTile(item.room);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            // if it's not manual ordering, we'll need to position the tile correctly here according to the right ordering
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // When dropped on a compatible target, actually set the right tags for the new ordering
 | 
				
			||||||
 | 
					            // persistNewOrder(item.room, dropResult.listId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var roomTileTarget = {
 | 
				
			||||||
 | 
					    canDrop: function() {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hover: function(props, monitor) {
 | 
				
			||||||
 | 
					        var item = monitor.getItem();
 | 
				
			||||||
 | 
					        console.log("hovering on room " + props.room.roomId + ", isOver=" + monitor.isOver());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //console.log("item.targetList=" + item.targetList + ", roomSubList=" + props.roomSubList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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.
 | 
				
			||||||
 | 
					            item.targetList.removeRoomTile(item.room);
 | 
				
			||||||
 | 
					            item.targetList = props.roomSubList;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (item.targetList.props.order === 'manual' && item.room.roomId !== props.room.roomId) {
 | 
				
			||||||
 | 
					            var roomTile = props.roomSubList.findRoomTile(props.room);
 | 
				
			||||||
 | 
					            props.roomSubList.moveRoomTile(item.room, roomTile.index);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var RoomTile = React.createClass({
 | 
				
			||||||
    displayName: 'RoomTile',
 | 
					    displayName: 'RoomTile',
 | 
				
			||||||
    mixins: [RoomTileController],
 | 
					    mixins: [RoomTileController],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    propTypes: {
 | 
				
			||||||
 | 
					        connectDragSource: React.PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					        connectDropTarget: React.PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					        isDragging: React.PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					        room: React.PropTypes.object.isRequired,
 | 
				
			||||||
 | 
					        collapsed: React.PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					        selected: React.PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					        unread: React.PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					        highlight: React.PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					        isInvite: React.PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					        roomSubList: React.PropTypes.object.isRequired,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getInitialState: function() {
 | 
					    getInitialState: function() {
 | 
				
			||||||
        return( { hover : false });
 | 
					        return( { hover : false });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -92,7 +173,14 @@ module.exports = React.createClass({
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var RoomAvatar = sdk.getComponent('atoms.RoomAvatar');
 | 
					        var RoomAvatar = sdk.getComponent('atoms.RoomAvatar');
 | 
				
			||||||
        return (
 | 
					
 | 
				
			||||||
 | 
					        // These props are injected by React DnD,
 | 
				
			||||||
 | 
					        // as defined by your `collect` function above:
 | 
				
			||||||
 | 
					        var isDragging = this.props.isDragging;
 | 
				
			||||||
 | 
					        var connectDragSource = this.props.connectDragSource;
 | 
				
			||||||
 | 
					        var connectDropTarget = this.props.connectDropTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return connectDragSource(connectDropTarget(
 | 
				
			||||||
            <div className={classes} onClick={this.onClick} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
 | 
					            <div className={classes} onClick={this.onClick} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
 | 
				
			||||||
                <div className="mx_RoomTile_avatar">
 | 
					                <div className="mx_RoomTile_avatar">
 | 
				
			||||||
                    <RoomAvatar room={this.props.room} width="24" height="24" />
 | 
					                    <RoomAvatar room={this.props.room} width="24" height="24" />
 | 
				
			||||||
@ -100,6 +188,26 @@ module.exports = React.createClass({
 | 
				
			|||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                { label }
 | 
					                { label }
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        );
 | 
					        ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Export the wrapped version, inlining the 'collect' functions
 | 
				
			||||||
 | 
					// to more closely resemble the ES7
 | 
				
			||||||
 | 
					module.exports = 
 | 
				
			||||||
 | 
					DropTarget('RoomTile', roomTileTarget, function(connect) {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        // Call this function inside render()
 | 
				
			||||||
 | 
					        // to let React DnD handle the drag events:
 | 
				
			||||||
 | 
					        connectDropTarget: connect.dropTarget(),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					})(
 | 
				
			||||||
 | 
					DragSource('RoomTile', roomTileSource, function(connect, monitor) {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        // Call this function inside render()
 | 
				
			||||||
 | 
					        // to let React DnD handle the drag events:
 | 
				
			||||||
 | 
					        connectDragSource: connect.dragSource(),
 | 
				
			||||||
 | 
					        // You can ask the monitor about the current drag state:
 | 
				
			||||||
 | 
					        isDragging: monitor.isDragging()
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					})(RoomTile));
 | 
				
			||||||
@ -17,10 +17,32 @@ limitations under the License.
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var React = require('react');
 | 
					var React = require('react');
 | 
				
			||||||
 | 
					var DropTarget = require('react-dnd').DropTarget;
 | 
				
			||||||
var sdk = require('matrix-react-sdk')
 | 
					var sdk = require('matrix-react-sdk')
 | 
				
			||||||
var dis = require('matrix-react-sdk/lib/dispatcher');
 | 
					var dis = require('matrix-react-sdk/lib/dispatcher');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = React.createClass({
 | 
					var roomListTarget = {
 | 
				
			||||||
 | 
					    canDrop: function() {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hover: function(props, monitor, component) {
 | 
				
			||||||
 | 
					        var item = monitor.getItem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (component.state.sortedList.length == 0 && props.editable) {
 | 
				
			||||||
 | 
					            console.log("hovering on sublist " + props.label + ", isOver=" + monitor.isOver());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (item.targetList !== component) {
 | 
				
			||||||
 | 
					                 item.targetList.removeRoomTile(item.room);
 | 
				
			||||||
 | 
					                 item.targetList = component;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            component.moveRoomTile(item.room, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var RoomSubList = React.createClass({
 | 
				
			||||||
    displayName: 'RoomSubList',
 | 
					    displayName: 'RoomSubList',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    propTypes: {
 | 
					    propTypes: {
 | 
				
			||||||
@ -80,14 +102,64 @@ module.exports = React.createClass({
 | 
				
			|||||||
        this.setState({ sortedList: list.sort(comparator) });
 | 
					        this.setState({ sortedList: list.sort(comparator) });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    moveRoomTile: function(room, atIndex) {
 | 
				
			||||||
 | 
					        console.log("moveRoomTile: id " + room.roomId + ", atIndex " + atIndex);
 | 
				
			||||||
 | 
					        //console.log("moveRoomTile before: " + JSON.stringify(this.state.rooms));
 | 
				
			||||||
 | 
					        var found = this.findRoomTile(room);
 | 
				
			||||||
 | 
					        var rooms = this.state.sortedList;
 | 
				
			||||||
 | 
					        if (found.room) {
 | 
				
			||||||
 | 
					            console.log("removing at index " + found.index + " and adding at index " + atIndex);
 | 
				
			||||||
 | 
					            rooms.splice(found.index, 1);
 | 
				
			||||||
 | 
					            rooms.splice(atIndex, 0, found.room);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            console.log("Adding at index " + atIndex);
 | 
				
			||||||
 | 
					            rooms.splice(atIndex, 0, room);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.setState({ sortedList: rooms });
 | 
				
			||||||
 | 
					        // console.log("moveRoomTile after: " + JSON.stringify(this.state.rooms));
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // XXX: this isn't invoked via a property method but indirectly via
 | 
				
			||||||
 | 
					    // the roomList property method.  Unsure how evil this is.
 | 
				
			||||||
 | 
					    removeRoomTile: function(room) {
 | 
				
			||||||
 | 
					        console.log("remove room " + room.roomId);
 | 
				
			||||||
 | 
					        var found = this.findRoomTile(room);
 | 
				
			||||||
 | 
					        var rooms = this.state.sortedList;
 | 
				
			||||||
 | 
					        if (found.room) {
 | 
				
			||||||
 | 
					            rooms.splice(found.index, 1);
 | 
				
			||||||
 | 
					        }        
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            console.log*("Can't remove room " + room.roomId + " - can't find it");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.setState({ sortedList: rooms });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    findRoomTile: function(room) {        
 | 
				
			||||||
 | 
					        var index = this.state.sortedList.indexOf(room); 
 | 
				
			||||||
 | 
					        if (index >= 0) {
 | 
				
			||||||
 | 
					            console.log("found: room: " + room + " with id " + room.roomId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            console.log("didn't find room");
 | 
				
			||||||
 | 
					            room = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ({
 | 
				
			||||||
 | 
					            room: room,
 | 
				
			||||||
 | 
					            index: index,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    },    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    makeRoomTiles: function() {
 | 
					    makeRoomTiles: function() {
 | 
				
			||||||
        var self = this;
 | 
					        var self = this;
 | 
				
			||||||
        var RoomTile = sdk.getComponent("molecules.RoomTile");
 | 
					        var RoomTile = sdk.getComponent("molecules.RoomTile");
 | 
				
			||||||
        return this.state.sortedList.map(function(room) {
 | 
					        return this.state.sortedList.map(function(room) {
 | 
				
			||||||
            var selected = room.roomId == self.props.selectedRoom;
 | 
					            var selected = room.roomId == self.props.selectedRoom;
 | 
				
			||||||
 | 
					            // XXX: is it evil to pass in self as a prop to RoomTile?
 | 
				
			||||||
            return (
 | 
					            return (
 | 
				
			||||||
                <RoomTile
 | 
					                <RoomTile
 | 
				
			||||||
                    room={room}
 | 
					                    room={room}
 | 
				
			||||||
 | 
					                    roomSubList={self}
 | 
				
			||||||
                    key={room.roomId}
 | 
					                    key={room.roomId}
 | 
				
			||||||
                    collapsed={self.props.collapsed}
 | 
					                    collapsed={self.props.collapsed}
 | 
				
			||||||
                    selected={selected}
 | 
					                    selected={selected}
 | 
				
			||||||
@ -99,14 +171,17 @@ module.exports = React.createClass({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render: function() {
 | 
					    render: function() {
 | 
				
			||||||
 | 
					        var connectDropTarget = this.props.connectDropTarget;
 | 
				
			||||||
        var RoomDropTarget = sdk.getComponent('molecules.RoomDropTarget');
 | 
					        var RoomDropTarget = sdk.getComponent('molecules.RoomDropTarget');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var label = this.props.collapsed ? null : this.props.label;
 | 
					        var label = this.props.collapsed ? null : this.props.label;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //console.log("render: " + JSON.stringify(this.state.sortedList));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.state.sortedList.length > 0 || this.props.editable) {
 | 
					        if (this.state.sortedList.length > 0 || this.props.editable) {
 | 
				
			||||||
            return (
 | 
					            return connectDropTarget(
 | 
				
			||||||
                <div>
 | 
					                <div>
 | 
				
			||||||
                    <h2 className="mx_RoomSubList_label">{ this.props.label }</h2>
 | 
					                    <h2 className="mx_RoomSubList_label">{ this.props.collapsed ? '' : this.props.label }</h2>
 | 
				
			||||||
                    <div className="mx_RoomSubList">
 | 
					                    <div className="mx_RoomSubList">
 | 
				
			||||||
                        { this.makeRoomTiles() }
 | 
					                        { this.makeRoomTiles() }
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
@ -122,3 +197,11 @@ module.exports = React.createClass({
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Export the wrapped version, inlining the 'collect' functions
 | 
				
			||||||
 | 
					// to more closely resemble the ES7
 | 
				
			||||||
 | 
					module.exports = 
 | 
				
			||||||
 | 
					DropTarget('RoomTile', roomListTarget, function(connect) {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        connectDropTarget: connect.dropTarget(),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					})(RoomSubList);
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,8 @@ limitations under the License.
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var React = require('react');
 | 
					var React = require('react');
 | 
				
			||||||
 | 
					var DragDropContext = require('react-dnd').DragDropContext;
 | 
				
			||||||
 | 
					var HTML5Backend = require('react-dnd/modules/backends/HTML5');
 | 
				
			||||||
var sdk = require('matrix-react-sdk')
 | 
					var sdk = require('matrix-react-sdk')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var MatrixChatController = require('matrix-react-sdk/lib/controllers/pages/MatrixChat')
 | 
					var MatrixChatController = require('matrix-react-sdk/lib/controllers/pages/MatrixChat')
 | 
				
			||||||
@ -28,7 +30,7 @@ var dis = require('matrix-react-sdk/lib/dispatcher');
 | 
				
			|||||||
var Matrix = require("matrix-js-sdk");
 | 
					var Matrix = require("matrix-js-sdk");
 | 
				
			||||||
var ContextualMenu = require("../../../../ContextualMenu");
 | 
					var ContextualMenu = require("../../../../ContextualMenu");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = React.createClass({
 | 
					var MatrixChat = React.createClass({
 | 
				
			||||||
    displayName: 'MatrixChat',
 | 
					    displayName: 'MatrixChat',
 | 
				
			||||||
    mixins: [MatrixChatController],
 | 
					    mixins: [MatrixChatController],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -172,3 +174,5 @@ module.exports = React.createClass({
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = DragDropContext(HTML5Backend)(MatrixChat);
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user