Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp the reorderable list component #10186

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ THE SOFTWARE.
<j:arg value="${toolDescriptor.clazz}" type="java.lang.Class" />
</j:invokeStatic>
<f:hetero-list name="installers" items="${instance.installers}" descriptors="${descriptors}"
addCaption="${%Add Installer}" deleteCaption="${%Delete Installer}"
addCaption="${%Add Installer}"
hasHeader="true"/>
</f:block>
</j:jelly>
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ THE SOFTWARE.
<st:include page="config.jelly" from="${descriptor}" class="${descriptor.clazz}"/>
<f:descriptorList descriptors="${descriptor.propertyDescriptors}" field="properties"/>
<l:isAdmin>
<f:repeatableDeleteButton value="${%label.delete(descriptor.displayName)}"/>
<f:repeatableDeleteButton />
</l:isAdmin>
</div>
</f:repeatable>
Expand Down
35 changes: 18 additions & 17 deletions core/src/main/resources/lib/form/hetero-list.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,30 @@ THE SOFTWARE.
</st:documentation>
<d:taglib uri="local">
<d:tag name="body">
<div class="help-sibling" style="width:100%">
<j:set var="help" value="${descriptor.helpFile}" />
<j:set var="help" value="${descriptor.helpFile}" />
<j:set var="disableHandle" value="${attrs.disableDragAndDrop or readOnlyMode}" />

<div class="repeated-chunk__header">
<div class="${attrs.disableDragAndDrop or readOnlyMode ? '' : 'dd-handle'}"/>
<div class="repeated-chunk__header ${disableHandle ? 'repeated-chunk__header--no-handle' : ''}">
<j:if test="${!disableHandle}">
<div class="dd-handle" />
</j:if>

${descriptor.displayName}
${descriptor.displayName}

<f:helpLink url="${help}"/>
<f:helpLink url="${help}"/>

<j:if test="${!readOnlyMode}">
<f:repeatableDeleteButton value="${attrs.deleteCaption}" />
</j:if>
</div>
<j:if test="${!readOnlyMode}">
<f:repeatableDeleteButton value="${attrs.deleteCaption}" />
</j:if>
</div>

<f:class-entry descriptor="${descriptor}" />

<div class="jenkins-repeated-chunk__content">
<j:if test="${help!=null}">
<f:helpArea />
</j:if>

<f:class-entry descriptor="${descriptor}" />

<d:invokeBody/>
</div>
</d:tag>
Expand All @@ -120,7 +123,7 @@ THE SOFTWARE.
</div>
</j:forEach>

<div class="repeatable-insertion-point" />
<template class="repeatable-insertion-point" />

<div class="prototypes to-be-removed">
<!-- render one prototype for each type -->
Expand Down Expand Up @@ -153,10 +156,8 @@ THE SOFTWARE.
</div>

<j:if test="${!readOnlyMode}">
<div>
<button type="button" class="jenkins-button hetero-list-add" menualign="${attrs.menuAlign}" suffix="${attrs.name}">${attrs.addCaption?:'%Add'}<l:icon src="symbol-chevron-down"/>
</button>
</div>
<button type="button" class="jenkins-button hetero-list-add" menualign="${attrs.menuAlign}" suffix="${attrs.name}">${attrs.addCaption?:'%Add'}<l:icon src="symbol-chevron-down"/>
</button>
</j:if>
</div>
</j:jelly>
20 changes: 13 additions & 7 deletions core/src/main/resources/lib/form/repeatable.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,12 @@ THE SOFTWARE.
<div class="repeated-chunk__header">
<j:if test="${!empty(header)}"><div class="${readOnlyMode ? '' : 'dd-handle'}"/>${header}</j:if>
</div>
<j:scope>
<j:set var="${var}" value="${null}"/>
<d:invokeBody />
</j:scope>
<div class="jenkins-repeated-chunk__content">
<j:scope>
<j:set var="${var}" value="${null}"/>
<d:invokeBody />
</j:scope>
</div>
</div>
<j:if test="${!empty(items) and !attrs.noAddButton and attrs.enableTopButton}">
<button type="button" class="jenkins-button repeatable-add repeatable-add-top">
Expand All @@ -153,7 +155,9 @@ THE SOFTWARE.
<div class="repeated-chunk__header">
<j:if test="${!empty(header)}"><div class="${readOnlyMode ? '' : 'dd-handle'}"/>${header}</j:if>
</div>
<d:invokeBody />
<div class="jenkins-repeated-chunk__content">
<d:invokeBody />
</div>
</div>
</j:forEach>
<j:remove var="${var}" />
Expand All @@ -165,12 +169,14 @@ THE SOFTWARE.
<div class="repeated-chunk__header">
<j:if test="${!empty(header)}"><div class="${readOnlyMode ? '' : 'dd-handle'}"/>${header}</j:if>
</div>
<d:invokeBody />
<div class="jenkins-repeated-chunk__content">
<d:invokeBody />
</div>
</div>
</j:forEach>
</j:if>

<div class="repeatable-insertion-point" />
<template class="repeatable-insertion-point" />
<j:if test="${!attrs.noAddButton}">
<button type="button" class="jenkins-button repeatable-add">
${attrs.add?:'%Add'}
Expand Down
12 changes: 5 additions & 7 deletions core/src/main/resources/lib/form/repeatable/repeatable.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ var repeatableSupport = {
addOnTop = false;
}

// importNode isn't supported in IE.
// nc = document.importNode(node,true);
var nc = document.createElement("div");
nc.className = "repeated-chunk fade-in";
nc.setAttribute("name", this.name);
Expand All @@ -59,7 +57,6 @@ var repeatableSupport = {
registerSortableDragDrop(nc);
}

nc.classList.remove("fade-in");
Behaviour.applySubtree(nc, true);
this.update();
},
Expand Down Expand Up @@ -101,13 +98,13 @@ var repeatableSupport = {
parentOfButton.insertBefore(addTopButton, parentOfButton.firstChild);
Behaviour.applySubtree(addTopButton, true);
}
children[0].className = "repeated-chunk first last only";
children[0].className = "repeated-chunk fade-in first last only";
} else {
children[0].className = "repeated-chunk first";
children[0].className = "repeated-chunk first fade-in";
for (var i = 1; i < children.length - 1; i++) {
children[i].className = "repeated-chunk middle";
children[i].className = "repeated-chunk middle fade-in";
}
children[children.length - 1].className = "repeated-chunk last";
children[children.length - 1].className = "repeated-chunk last fade-in";
}
}
},
Expand All @@ -133,6 +130,7 @@ var repeatableSupport = {
// transition end not triggered in tests
n.ontransitionend.call(n, {});
}

n.style.maxHeight = n.offsetHeight + "px";
n.classList.add("fade-out");
setTimeout(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ THE SOFTWARE.
</st:attribute>
</st:documentation>
<st:adjunct includes="lib.form.repeatable.repeatable"/>
<button tooltip="${attrs.value ?: '%Delete'}" class="repeatable-delete danger" type="button">

<j:set var="deleteText" value="${attrs.value ?: '%Delete'}" />
<button class="repeatable-delete danger" type="button" style="--width: calc(${deleteText.length()}ch + 20px)">
<l:icon src="symbol-close" />
<span>${deleteText}</span>
</button>
</j:jelly>
6 changes: 2 additions & 4 deletions core/src/main/resources/lib/form/repeatableProperty.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@ THE SOFTWARE.


<f:repeatable field="${attrs.field}" default="${attrs.default}" noAddButton="${attrs.noAddButton}" header="${attrs.header}" add="${attrs.add}" minimum="${attrs.minimum ?: 0}" enableTopButton="${attrs.enableTopButton}">
<div style="width:100%">
<st:include page="config.jelly" class="${descriptor.clazz}" />
<d:invokeBody/>
</div>
<st:include page="config.jelly" class="${descriptor.clazz}" />
<d:invokeBody/>
</f:repeatable>
</j:jelly>
1 change: 0 additions & 1 deletion src/main/js/components/dropdowns/hetero-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ function generateButtons() {
}
Behaviour.applySubtree(nc, true);
ensureVisible(nc);
nc.classList.remove("fade-in");
layoutUpdateCallback.call();
},
true,
Expand Down
40 changes: 34 additions & 6 deletions src/main/js/sortable-drag-drop.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,49 @@ function registerSortableDragDrop(e) {
return false;
}

let initialX, currentItem;
const maxRotation = 2; // Maximum rotation in degrees
const maxDistance = 150; // Maximum distance for the full rotation effect

function onPointerMove(evt) {
if (!currentItem) {
return;
}

const currentX = evt.clientX + window.scrollX;
const distanceX = currentX - initialX - 20;

// Calculate rotation angle based on the distance moved
const rotation = Math.max(
-maxRotation,
Math.min(maxRotation, (distanceX / maxDistance) * maxRotation),
);

currentItem.style.rotate = `${rotation}deg`;
currentItem.style.translate = distanceX * -0.75 + "px";
}

new Sortable(e, {
animation: 200,
draggable: ".repeated-chunk",
handle: ".dd-handle",
ghostClass: "repeated-chunk--sortable-ghost",
chosenClass: "repeated-chunk--sortable-chosen",
forceFallback: true, // Do not use html5 drag & drop behaviour because it does not work with autoscroll
scroll: true,
bubbleScroll: true,
onChoose: function (event) {
const draggableDiv = event.item;
const height = draggableDiv.clientHeight;
draggableDiv.style.height = `${height}px`;
onStart: function (evt) {
const rect = evt.item.getBoundingClientRect();
initialX = rect.left + window.scrollX;
currentItem = document.querySelector(".sortable-drag");
document.addEventListener("pointermove", onPointerMove);
},
onUnchoose: function (event) {
event.item.style.removeProperty("height");
onEnd: function () {
document.removeEventListener("pointermove", onPointerMove);
if (currentItem) {
currentItem.style.rotate = "";
currentItem = null;
}
},
});
}
Expand Down
6 changes: 5 additions & 1 deletion src/main/scss/abstracts/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
z-index: 0;
text-decoration: none !important;
border-radius: 0.66rem;
cursor: pointer;
border: none;
outline: none;
background: transparent;

&::before,
&::after {
Expand All @@ -74,7 +78,7 @@
}

&::before {
background-color: transparent;
background-color: var(--item-background);
}

&::after {
Expand Down
Loading
Loading