Skip to content

Commit

Permalink
fix(UI): Fixed drag and drop custom-form fields, node-type fields and…
Browse files Browse the repository at this point in the history
… attribute-values by setting new position against previous or next element id
  • Loading branch information
ambroisemaupate committed Jun 3, 2024
1 parent 59dcc37 commit 1c929fc
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 54 deletions.
50 changes: 38 additions & 12 deletions lib/Rozier/src/AjaxControllers/AjaxAbstractFieldsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

abstract class AjaxAbstractFieldsController extends AbstractAjaxController
{
public function __construct(protected readonly HandlerFactoryInterface $handlerFactory)
{
}

protected function findEntity(int|string $entityId): ?AbstractField
{
return $this->em()->find($this->getEntityClass(), (int) $entityId);
}

/**
* Handle actions for any abstract fields.
*
Expand Down Expand Up @@ -70,11 +76,31 @@ protected function handleFieldActions(Request $request, AbstractField $field = n
*/
protected function updatePosition(array $parameters, AbstractField $field = null): array
{
/*
* First, we set the new parent
*/
if (!empty($parameters['newPosition']) && null !== $field) {
$field->setPosition((float) $parameters['newPosition']);
if (!empty($parameters['afterFieldId']) && is_numeric($parameters['afterFieldId'])) {
$afterField = $this->findEntity((int) $parameters['afterFieldId']);
if (null === $afterField) {
throw new BadRequestHttpException('afterFieldId does not exist');
}
$field->setPosition($afterField->getPosition() + 0.5);
// Apply position update before cleaning
$this->em()->flush();
$handler = $this->handlerFactory->getHandler($field);
$handler->cleanPositions();
$this->em()->flush();
return [
'statusCode' => '200',
'status' => 'success',
'responseText' => $this->getTranslator()->trans('field.%name%.updated', [
'%name%' => $field->getName(),
]),
];
}
if (!empty($parameters['beforeFieldId']) && is_numeric($parameters['beforeFieldId'])) {
$beforeField = $this->findEntity((int) $parameters['beforeFieldId']);
if (null === $beforeField) {
throw new BadRequestHttpException('beforeFieldId does not exist');
}
$field->setPosition($beforeField->getPosition() - 0.5);
// Apply position update before cleaning
$this->em()->flush();
$handler = $this->handlerFactory->getHandler($field);
Expand All @@ -88,12 +114,12 @@ protected function updatePosition(array $parameters, AbstractField $field = null
]),
];
}
return [
'statusCode' => '400',
'status' => 'error',
'responseText' => $this->getTranslator()->trans('field.%name%.updated', [
'%name%' => $field->getName(),
]),
];

throw new BadRequestHttpException('Cannot update position for Field. Missing parameters.');
}

/**
* @return class-string<AbstractField>
*/
abstract protected function getEntityClass(): string;
}
42 changes: 27 additions & 15 deletions lib/Rozier/src/AjaxControllers/AjaxAttributeValuesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
namespace Themes\Rozier\AjaxControllers;

use RZ\Roadiz\CoreBundle\Entity\AttributeValue;
use RZ\Roadiz\CoreBundle\Entity\Node;
use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

final class AjaxAttributeValuesController extends AbstractAjaxController
{
Expand Down Expand Up @@ -70,12 +70,31 @@ protected function updatePosition(array $parameters, AttributeValue $attributeVa
'%name%' => $attributeValue->getAttribute()->getLabelOrCode(),
'%nodeName%' => $attributable->getNodeName(),
];
/*
* First, we set the new parent
*/
if (!empty($parameters['newPosition'])) {
$attributeValue->setPosition((float) $parameters['newPosition']);
// Apply position update before cleaning

if (!empty($parameters['afterAttributeValueId']) && is_numeric($parameters['afterAttributeValueId'])) {
/** @var AttributeValue|null $afterAttributeValue */
$afterAttributeValue = $this->em()->find(AttributeValue::class, (int) $parameters['afterAttributeValueId']);
if (null === $afterAttributeValue) {
throw new BadRequestHttpException('afterAttributeValueId does not exist');
}
$attributeValue->setPosition($afterAttributeValue->getPosition() + 0.5);
$this->em()->flush();
return [
'statusCode' => '200',
'status' => 'success',
'responseText' => $this->getTranslator()->trans(
'attribute_value_translation.%name%.updated_from_node.%nodeName%',
$details
),
];
}
if (!empty($parameters['beforeAttributeValueId']) && is_numeric($parameters['beforeAttributeValueId'])) {
/** @var AttributeValue|null $beforeAttributeValue */
$beforeAttributeValue = $this->em()->find(AttributeValue::class, (int) $parameters['beforeAttributeValueId']);
if (null === $beforeAttributeValue) {
throw new BadRequestHttpException('beforeAttributeValueId does not exist');
}
$attributeValue->setPosition($beforeAttributeValue->getPosition() - 0.5);
$this->em()->flush();
return [
'statusCode' => '200',
Expand All @@ -87,13 +106,6 @@ protected function updatePosition(array $parameters, AttributeValue $attributeVa
];
}

return [
'statusCode' => '400',
'status' => 'error',
'responseText' => $this->getTranslator()->trans(
'attribute_value_translation.%name%.updated_from_node.%nodeName%',
$details
),
];
throw new BadRequestHttpException('Cannot update position for AttributeValue. Missing parameters.');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@ class AjaxCustomFormFieldsController extends AjaxAbstractFieldsController
*/
public function editAction(Request $request, int $customFormFieldId): Response
{
/*
* Validate
*/
$this->validateRequest($request);
$this->denyAccessUnlessGranted('ROLE_ACCESS_CUSTOMFORMS_DELETE');

$field = $this->em()->find(CustomFormField::class, (int) $customFormFieldId);
$field = $this->findEntity((int) $customFormFieldId);

if (null !== $field && null !== $response = $this->handleFieldActions($request, $field)) {
return $response;
Expand All @@ -40,4 +37,9 @@ public function editAction(Request $request, int $customFormFieldId): Response
]
));
}

protected function getEntityClass(): string
{
return CustomFormField::class;
}
}
10 changes: 6 additions & 4 deletions lib/Rozier/src/AjaxControllers/AjaxNodeTypeFieldsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@ class AjaxNodeTypeFieldsController extends AjaxAbstractFieldsController
*/
public function editAction(Request $request, int $nodeTypeFieldId): Response
{
/*
* Validate
*/
$this->validateRequest($request);
$this->denyAccessUnlessGranted('ROLE_ACCESS_NODEFIELDS_DELETE');

$field = $this->em()->find(NodeTypeField::class, (int) $nodeTypeFieldId);
$field = $this->findEntity($nodeTypeFieldId);

if (null !== $response = $this->handleFieldActions($request, $field)) {
return $response;
Expand All @@ -40,4 +37,9 @@ public function editAction(Request $request, int $nodeTypeFieldId): Response
]
));
}

protected function getEntityClass(): string
{
return NodeTypeField::class;
}
}
2 changes: 1 addition & 1 deletion lib/Rozier/src/AjaxControllers/AjaxNodeTypesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use Symfony\Component\Routing\Exception\InvalidParameterException;
use Themes\Rozier\Models\NodeTypeModel;

class AjaxNodeTypesController extends AjaxAbstractFieldsController
class AjaxNodeTypesController extends AbstractAjaxController
{
/**
* @param Request $request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ export default class AttributeValuePosition {
let $element = $(element)
let attributeValueId = parseInt($element.data('id'))
let $sibling = $element.prev()
let newPosition = 0.0
let beforeElementId = null
let afterElementId = null

if ($sibling.length === 0) {
$sibling = $element.next()
newPosition = parseInt($sibling.data('position')) - 0.5
beforeElementId = parseInt($sibling.data('id'))
} else {
newPosition = parseInt($sibling.data('position')) + 0.5
afterElementId = parseInt($sibling.data('id'))
}
const route = window.Rozier.routes.attributeValueAjaxEdit
if (!route || !attributeValueId) {
Expand All @@ -57,7 +58,8 @@ export default class AttributeValuePosition {
_token: window.Rozier.ajaxToken,
_action: 'updatePosition',
attributeValueId: attributeValueId,
newPosition: newPosition,
beforeAttributeValueId: beforeElementId,
afterAttributeValueId: afterElementId,
}),
})
if (!response.ok) {
Expand All @@ -74,7 +76,7 @@ export default class AttributeValuePosition {
} catch (response) {
const data = await response.json()
window.UIkit.notify({
message: data.error_message || '',
message: data.title || '',
status: 'danger',
timeout: 3000,
pos: 'top-center',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,22 @@ export default class CustomFormFieldsPosition {
let $element = $(element)
let customFormFieldId = parseInt($element.data('field-id'))
let $sibling = $element.prev()
let newPosition = 0.0
let afterFieldId = null
let beforeFieldId = null

if ($sibling.length === 0) {
$sibling = $element.next()
newPosition = parseInt($sibling.data('position')) - 0.5
beforeFieldId = parseInt($sibling.data('field-id'))
} else {
newPosition = parseInt($sibling.data('position')) + 0.5
afterFieldId = parseInt($sibling.data('field-id'))
}

const postData = {
_token: window.Rozier.ajaxToken,
_action: 'updatePosition',
customFormFieldId: customFormFieldId,
newPosition: newPosition,
beforeFieldId: beforeFieldId,
afterFieldId: afterFieldId,
}
const response = await fetch(
window.Rozier.routes.customFormsFieldAjaxEdit.replace('%customFormFieldId%', customFormFieldId),
Expand All @@ -54,14 +56,13 @@ export default class CustomFormFieldsPosition {
if (!response.ok) {
const data = await response.json()
window.UIkit.notify({
message: data.error_message,
message: data.title,
status: 'danger',
timeout: 3000,
pos: 'top-center',
})
} else {
const data = await response.json()
$element.attr('data-position', newPosition)
window.UIkit.notify({
message: data.responseText,
status: data.status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,22 @@ export default class NodeTypeFieldsPosition {
let $element = $(element)
let nodeTypeFieldId = parseInt($element.data('field-id'))
let $sibling = $element.prev()
let newPosition = 0.0
let beforeFieldId = null
let afterFieldId = null

if ($sibling.length === 0) {
$sibling = $element.next()
newPosition = parseInt($sibling.data('position')) - 0.5
beforeFieldId = parseInt($sibling.data('field-id'))
} else {
newPosition = parseInt($sibling.data('position')) + 0.5
afterFieldId = parseInt($sibling.data('field-id'))
}

const postData = {
_token: window.Rozier.ajaxToken,
_action: 'updatePosition',
nodeTypeFieldId: nodeTypeFieldId,
newPosition: newPosition,
beforeFieldId: beforeFieldId,
afterFieldId: afterFieldId,
}
const response = await fetch(
window.Rozier.routes.nodeTypesFieldAjaxEdit.replace('%nodeTypeFieldId%', nodeTypeFieldId),
Expand All @@ -102,14 +104,13 @@ export default class NodeTypeFieldsPosition {
if (!response.ok) {
const data = await response.json()
window.UIkit.notify({
message: data.error_message,
message: data.title,
status: 'danger',
timeout: 3000,
pos: 'top-center',
})
} else {
const data = await response.json()
$element.attr('data-position', newPosition)
window.UIkit.notify({
message: data.responseText,
status: data.status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<tbody class="uk-sortable" data-uk-sortable="{animation:0, dragCustomClass:'setting-row rz-node-type-field-dragged', handleClass:'attribute-value-col'}">
{% for attribute_value_translation_form in attribute_value_translation_forms %}
{% set attributeValue = attribute_value_translation_form.vars.data.attributeValue %}
<tr class="setting-row" data-position="{{ attributeValue.position }}" data-id="{{ attributeValue.getId }}">
<tr class="setting-row" data-position="{{ attributeValue.position }}" data-id="{{ attributeValue.id }}">
<th class="name attribute-value-col">
<span class="color" style="--data-color: {{ attributeValue.attribute.color|default('transparent') }};"></span>
<strong>{{- attribute_value_translation_form.vars.data|attribute_label -}}</strong>
Expand Down

0 comments on commit 1c929fc

Please sign in to comment.