kopia lustrzana https://github.com/OpenDroneMap/WebODM
Tag component drag reorder
rodzic
e6c423f240
commit
de79e1b606
|
@ -621,8 +621,8 @@ class EditTaskForm extends React.Component {
|
|||
placeholder={this.state.namePlaceholder}
|
||||
value={this.state.name}
|
||||
/>
|
||||
<button type="button" title={_("Add tags")} onClick={this.toggleTagsField} class="btn btn-sm btn-secondary toggle-tags">
|
||||
<i class="fa fa-tag"></i>
|
||||
<button type="button" title={_("Add tags")} onClick={this.toggleTagsField} className="btn btn-sm btn-secondary toggle-tags">
|
||||
<i className="fa fa-tag"></i>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { _ } from '../classes/gettext';
|
|||
|
||||
class TagsField extends React.Component {
|
||||
static defaultProps = {
|
||||
tags: ["abc"]
|
||||
tags: ["abc", "123", "xyz", "aaaaaaaaaaaaaaaa", "bbbbbbbbbbbb", "ccccccccccc", "dddddddddddd"]
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
|
@ -19,6 +19,36 @@ class TagsField extends React.Component {
|
|||
this.state = {
|
||||
tags: props.tags
|
||||
}
|
||||
|
||||
this.dzList = [];
|
||||
this.domTags = [];
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
this.restoreDropzones();
|
||||
}
|
||||
|
||||
disableDropzones(){
|
||||
if (this.disabledDz) return;
|
||||
let parent = this.domNode.parentElement;
|
||||
while(parent){
|
||||
if (parent.dropzone){
|
||||
parent.dropzone.removeListeners();
|
||||
this.dzList.push(parent.dropzone);
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
this.disabledDz = true;
|
||||
}
|
||||
|
||||
restoreDropzones(){
|
||||
if (!this.disabledDz) return;
|
||||
|
||||
this.dzList.forEach(dz => {
|
||||
dz.restoreListeners();
|
||||
});
|
||||
this.dzList = [];
|
||||
this.disabledDz = false;
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
|
@ -58,15 +88,115 @@ class TagsField extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleDragStart = tag => {
|
||||
return e => {
|
||||
this.disableDropzones();
|
||||
e.stopPropagation();
|
||||
e.dataTransfer.setData("application/tag", tag);
|
||||
e.dataTransfer.dropEffect = "move";
|
||||
}
|
||||
}
|
||||
|
||||
handleDrop = e => {
|
||||
e.preventDefault();
|
||||
const dragTag = e.dataTransfer.getData("application/tag");
|
||||
const [moveTag, side] = this.findClosestTag(e.clientX, e.clientY);
|
||||
|
||||
const { tags } = this.state;
|
||||
if (moveTag){
|
||||
const dragIdx = tags.indexOf(dragTag);
|
||||
const moveIdx = tags.indexOf(moveTag);
|
||||
if (dragIdx !== -1 && moveIdx !== -1){
|
||||
if (dragIdx === moveIdx) return;
|
||||
else{
|
||||
// Put drag tag in front of move tag
|
||||
let insertIdx = side === "right" ? moveIdx + 1 : moveIdx;
|
||||
tags.splice(insertIdx, 0, dragTag);
|
||||
for (let i = 0; i < tags.length; i++){
|
||||
if (tags[i] === dragTag && i !== insertIdx){
|
||||
tags.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.setState({tags});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
handleDragOver = e => {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = "move";
|
||||
}
|
||||
handleDragEnter = e => {
|
||||
e.preventDefault();
|
||||
}
|
||||
handleDragEnd = () => {
|
||||
this.restoreDropzones();
|
||||
}
|
||||
|
||||
findClosestTag = (clientX, clientY) => {
|
||||
let closestTag = null;
|
||||
let minDistX = Infinity, minDistY = Infinity;
|
||||
let rowTagY = null;
|
||||
const { tags } = this.state;
|
||||
const row = [];
|
||||
|
||||
// Find tags in closest row
|
||||
this.domTags.forEach((domTag, i) => {
|
||||
const b = domTag.getBoundingClientRect();
|
||||
const tagY = b.y + (b.height / 2);
|
||||
let dy = clientY - tagY,
|
||||
sqDistY = dy*dy;
|
||||
|
||||
if (sqDistY < minDistY){
|
||||
minDistY = sqDistY;
|
||||
rowTagY = tagY;
|
||||
}
|
||||
});
|
||||
|
||||
if (!rowTagY) return [null, ""];
|
||||
|
||||
// From row, find closest in X
|
||||
this.domTags.forEach((domTag, i) => {
|
||||
const b = domTag.getBoundingClientRect();
|
||||
const tagY = b.y + (b.height / 2);
|
||||
if (Math.abs(tagY - rowTagY) < 0.001){
|
||||
const tagX = b.x + b.width;
|
||||
let dx = clientX - tagX,
|
||||
sqDistX = dx*dx;
|
||||
if (sqDistX < minDistX){
|
||||
closestTag = tags[i];
|
||||
minDistX = sqDistX;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let side = "right";
|
||||
if (closestTag){
|
||||
const b = this.domTags[this.state.tags.indexOf(closestTag)].getBoundingClientRect();
|
||||
const centerX = b.x + b.width / 2.0;
|
||||
if (clientX < centerX) side = "left";
|
||||
}
|
||||
|
||||
return [closestTag, side];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div
|
||||
spellcheck="false"
|
||||
autocomplete="off"
|
||||
ref={domNode => this.domNode = domNode}
|
||||
spellCheck="false"
|
||||
autoComplete="off"
|
||||
onClick={this.focus}
|
||||
onDrop={this.handleDrop}
|
||||
onDragOver={this.handleDragOver}
|
||||
onDragEnter={this.handleDragEnter}
|
||||
className="form-control tags-field">{this.state.tags.map((tag, i) =>
|
||||
<div className="tag-badge" key={i} onClick={this.stop}>{tag} <a href="javascript:void(0)" onClick={this.removeTag(i)}>×</a> </div>
|
||||
<div draggable="true" className="tag-badge" key={i} ref={domNode => this.domTags[i] = domNode}
|
||||
onClick={this.stop}
|
||||
onDragStart={this.handleDragStart(tag)}
|
||||
onDragEnd={this.handleDragEnd}>{tag} <a href="javascript:void(0)" onClick={this.removeTag(i)}>×</a> </div>
|
||||
)}
|
||||
<div className="inputText" contenteditable="true" ref={(domNode) => this.inputText = domNode}
|
||||
<div className="inputText" contentEditable="true" ref={(domNode) => this.inputText = domNode}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onBlur={this.addTag}></div>
|
||||
</div>);
|
||||
|
|
|
@ -90,8 +90,6 @@ class TaskList extends React.Component {
|
|||
|
||||
return (
|
||||
<div className="task-list">
|
||||
{message}
|
||||
|
||||
{this.state.tasks.map(task => (
|
||||
<TaskListItem
|
||||
data={task}
|
||||
|
@ -103,6 +101,8 @@ class TaskList extends React.Component {
|
|||
hasPermission={this.props.hasPermission}
|
||||
history={this.props.history} />
|
||||
))}
|
||||
|
||||
{message}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
.name-loading{
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
right: 60px;
|
||||
top: 15px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
}
|
||||
.tag-badge{
|
||||
&:hover{
|
||||
cursor: default;
|
||||
cursor: grab;
|
||||
}
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
|
|
|
@ -1555,6 +1555,22 @@ var Dropzone = function (_Emitter) {
|
|||
return _this4.cancelUpload(file);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "removeListeners",
|
||||
value: function disable() {
|
||||
this.clickableElements.forEach(function (element) {
|
||||
return element.classList.remove("dz-clickable");
|
||||
});
|
||||
this.removeEventListeners();
|
||||
}
|
||||
}, {
|
||||
key: "restoreListeners",
|
||||
value: function disable() {
|
||||
this.clickableElements.forEach(function (element) {
|
||||
return element.classList.add("dz-clickable");
|
||||
});
|
||||
return this.setupEventListeners();
|
||||
}
|
||||
}, {
|
||||
key: "enable",
|
||||
value: function enable() {
|
||||
|
|
Ładowanie…
Reference in New Issue