Add drag and drop support for reordering the attributes manually in the Attribute Manager
This commit is contained in:
parent
fec638cb22
commit
b4ec9745e7
4 changed files with 123 additions and 5 deletions
|
|
@ -1,9 +1,11 @@
|
|||
import { __ID__, filePath } from "../consts.mjs";
|
||||
import { attributeSorter } from "../utils/attributeSort.mjs";
|
||||
import { Logger } from "../utils/Logger.mjs";
|
||||
import { toID } from "../utils/toID.mjs";
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
const { deepClone, diffObject, randomID, setProperty } = foundry.utils;
|
||||
const { deepClone, diffObject, mergeObject, performIntegerSort, randomID, setProperty } = foundry.utils;
|
||||
const { DragDrop, TextEditor } = foundry.applications.ux;
|
||||
|
||||
export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
|
||||
|
|
@ -16,7 +18,7 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
],
|
||||
position: {
|
||||
width: 400,
|
||||
height: 350,
|
||||
height: `auto`,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
|
|
@ -68,6 +70,18 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
for (const input of elements) {
|
||||
input.addEventListener(`change`, this.#bindListener.bind(this));
|
||||
};
|
||||
|
||||
new DragDrop.implementation({
|
||||
dragSelector: `[data-attribute]`,
|
||||
permissions: {
|
||||
dragstart: this._canDragStart.bind(this),
|
||||
drop: this._canDragDrop.bind(this),
|
||||
},
|
||||
callbacks: {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
},
|
||||
}).bind(this.element);
|
||||
};
|
||||
// #endregion Lifecycle
|
||||
|
||||
|
|
@ -93,11 +107,13 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
attrs.push({
|
||||
id,
|
||||
name: data.name,
|
||||
displayName: data.isNew ? `New Attribute` : data.name,
|
||||
sort: data.sort,
|
||||
isRange: data.isRange,
|
||||
isNew: data.isNew ?? false,
|
||||
});
|
||||
};
|
||||
ctx.attrs = attrs;
|
||||
ctx.attrs = attrs.sort(attributeSorter);
|
||||
};
|
||||
// #endregion Data Prep
|
||||
|
||||
|
|
@ -119,7 +135,7 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
|
||||
Logger.debug(`Updating ${binding} value to ${value}`);
|
||||
setProperty(this.#attributes, binding, value);
|
||||
await this.render();
|
||||
await this.render({ parts: [ `attributes` ]});
|
||||
};
|
||||
|
||||
/** @this {AttributeManager} */
|
||||
|
|
@ -127,6 +143,7 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
const id = randomID();
|
||||
this.#attributes[id] = {
|
||||
name: ``,
|
||||
sort: Number.POSITIVE_INFINITY,
|
||||
isRange: false,
|
||||
isNew: true,
|
||||
};
|
||||
|
|
@ -168,4 +185,87 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
await this.#doc.update({ "system.attr": diff });
|
||||
};
|
||||
// #endregion Actions
|
||||
|
||||
// #region Drag & Drop
|
||||
_canDragStart() {
|
||||
return this.#doc.isOwner;
|
||||
};
|
||||
|
||||
_canDragDrop() {
|
||||
return this.#doc.isOwner;
|
||||
};
|
||||
|
||||
_onDragStart(event) {
|
||||
const target = event.currentTarget;
|
||||
if (`link` in event.target.dataset) { return };
|
||||
let dragData;
|
||||
|
||||
if (target.dataset.attribute) {
|
||||
const attributeID = target.dataset.attribute;
|
||||
const attribute = this.#attributes[attributeID];
|
||||
dragData = {
|
||||
_id: attributeID,
|
||||
sort: attribute.sort,
|
||||
};
|
||||
};
|
||||
|
||||
if (!dragData) { return };
|
||||
event.dataTransfer.setData(`text/plain`, JSON.stringify(dragData));
|
||||
};
|
||||
|
||||
_onDrop(event) {
|
||||
const dropped = TextEditor.implementation.getDragEventData(event);
|
||||
|
||||
const dropTarget = event.target.closest(`[data-attribute]`);
|
||||
if (!dropTarget) { return };
|
||||
const targetID = dropTarget.dataset.attribute;
|
||||
let target;
|
||||
|
||||
// Not moving location, ignore drop event
|
||||
if (targetID === dropped._id) { return };
|
||||
|
||||
// Determine all of the siblings and create sort data
|
||||
const siblings = [];
|
||||
for (const element of dropTarget.parentElement.children) {
|
||||
const siblingID = element.dataset.attribute;
|
||||
const attr = this.#attributes[siblingID];
|
||||
const sibling = {
|
||||
_id: siblingID,
|
||||
sort: attr.sort,
|
||||
};
|
||||
if (siblingID && siblingID !== dropped._id) {
|
||||
siblings.push(sibling);
|
||||
};
|
||||
if (siblingID === targetID) {
|
||||
target = sibling;
|
||||
}
|
||||
};
|
||||
|
||||
const sortUpdates = performIntegerSort(
|
||||
dropped,
|
||||
{
|
||||
target,
|
||||
siblings,
|
||||
},
|
||||
);
|
||||
|
||||
const updateEntries = sortUpdates.map(({ target, update }) => {
|
||||
return [ `${target._id}.sort`, update.sort ];
|
||||
});
|
||||
const update = Object.fromEntries(updateEntries);
|
||||
|
||||
mergeObject(
|
||||
this.#attributes,
|
||||
update,
|
||||
{
|
||||
insertKeys: false,
|
||||
insertValues: false,
|
||||
inplace: true,
|
||||
performDeletions: false,
|
||||
},
|
||||
);
|
||||
|
||||
this.render({ parts: [ `attributes` ] });
|
||||
};
|
||||
// #endregion Drag & Drop
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
.attribute {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
grid-template-columns: min-content 1fr repeat(3, auto);
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
|
|
@ -18,6 +18,18 @@
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
&.vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
taf-icon {
|
||||
cursor: grab;
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
class="attribute"
|
||||
data-attribute="{{ attr.id }}"
|
||||
>
|
||||
<taf-icon
|
||||
name="icons/drag-handle"
|
||||
var:stroke="currentColor"
|
||||
var:fill="currentColor"
|
||||
></taf-icon>
|
||||
{{#if attr.isNew}}
|
||||
<input
|
||||
type="text"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue