Skip to content

Commit fd65d23

Browse files
committed
Add the move buttons in JS
1 parent 2f94b23 commit fd65d23

File tree

4 files changed

+96
-134
lines changed

4 files changed

+96
-134
lines changed

src/helpers/Cp.php

+3-38
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ public static function elementCardHtml(ElementInterface $element, array $config
711711
Html::beginTag('div', ['class' => 'card-actions-container']) .
712712
Html::beginTag('div', ['class' => 'card-actions']) .
713713
($config['selectable'] ? self::componentCheckboxHtml(sprintf('%s-label', $config['id'])) : '') .
714-
($config['showActionMenu'] ? self::componentActionMenu($element, $config) : '') .
714+
($config['showActionMenu'] ? self::componentActionMenu($element) : '') .
715715
($config['sortable'] ? Html::button('', [
716716
'class' => ['move', 'icon'],
717717
'title' => Craft::t('app', 'Reorder'),
@@ -1025,10 +1025,10 @@ private static function elementLabelHtml(ElementInterface $element, array $confi
10251025
]);
10261026
}
10271027

1028-
private static function componentActionMenu(Actionable $component, array $config = []): string
1028+
private static function componentActionMenu(Actionable $component): string
10291029
{
10301030
return Craft::$app->getView()->namespaceInputs(
1031-
function() use ($component, $config): string {
1031+
function() use ($component): string {
10321032
$actionMenuItems = array_filter(
10331033
$component->getActionMenuItems(),
10341034
fn(array $item) => $item['showInChips'] ?? !($item['destructive'] ?? false)
@@ -1046,41 +1046,6 @@ function() use ($component, $config): string {
10461046
}
10471047
}
10481048

1049-
if ($config['sortable'] ?? false) {
1050-
$moveUpId = sprintf('action-move-up-%s', mt_rand());
1051-
$label = (isset($config['showInGrid']) && $config['showInGrid']) ? Craft::t('app', 'Move forward') : Craft::t('app', 'Move up');
1052-
$icon = 'arrow-up';
1053-
if ($config['showInGrid']) {
1054-
$icon = Craft::$app->getLocale()->getOrientation() === 'ltr' ? 'arrow-left' : 'arrow-right';
1055-
}
1056-
$actionMenuItems[] = [
1057-
'id' => $moveUpId,
1058-
'label' => $label,
1059-
'icon' => $icon,
1060-
'destructive' => false,
1061-
'attributes' => [
1062-
'class' => ['move'],
1063-
'data' => ['move-action' => 'up'],
1064-
],
1065-
];
1066-
$moveDownId = sprintf('action-move-down-%s', mt_rand());
1067-
$label = (isset($config['showInGrid']) && $config['showInGrid']) ? Craft::t('app', 'Move backward') : Craft::t('app', 'Move down');
1068-
$icon = 'arrow-down';
1069-
if ($config['showInGrid']) {
1070-
$icon = Craft::$app->getLocale()->getOrientation() === 'ltr' ? 'arrow-right' : 'arrow-left';
1071-
}
1072-
$actionMenuItems[] = [
1073-
'id' => $moveDownId,
1074-
'label' => $label,
1075-
'icon' => $icon,
1076-
'destructive' => false,
1077-
'attributes' => [
1078-
'class' => ['move'],
1079-
'data' => ['move-action' => 'down'],
1080-
],
1081-
];
1082-
}
1083-
10841049
return static::disclosureMenu($actionMenuItems, [
10851050
'hiddenLabel' => Craft::t('app', 'Actions'),
10861051
'buttonAttributes' => [

src/web/assets/cp/dist/cp.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/web/assets/cp/dist/cp.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/web/assets/cp/src/js/NestedElementManager.js

+91-94
Original file line numberDiff line numberDiff line change
@@ -602,17 +602,78 @@ Craft.NestedElementManager = Garnish.Base.extend(
602602
}
603603
}
604604

605+
const destructiveGroup = actionDisclosure.getFirstDestructiveGroup();
606+
let moveUpButton, moveDownButton, duplicateButton;
607+
608+
const $li = $element.parent();
609+
const getPrev = () => $li.prev('li');
610+
const getNext = () => $li.next('li');
611+
612+
if (this.settings.sortable) {
613+
this.elementSort.addItems($li);
614+
615+
const ul = actionDisclosure.addGroup(null, true, destructiveGroup);
616+
617+
// Move up/forward
618+
moveUpButton = actionDisclosure.addItem(
619+
{
620+
icon: async () =>
621+
await Craft.ui.icon(
622+
this.settings.showInGrid
623+
? Craft.orientation === 'ltr'
624+
? 'arrow-left'
625+
: 'arrow-right'
626+
: 'arrow-up'
627+
),
628+
label: this.settings.showInGrid
629+
? Craft.t('app', 'Move forward')
630+
: Craft.t('app', 'Move up'),
631+
onActivate: () => {
632+
const $prev = getPrev();
633+
if ($prev.length) {
634+
$li.insertBefore($prev);
635+
this.onSortChange($li);
636+
}
637+
},
638+
},
639+
ul
640+
);
641+
642+
// Move down/backward
643+
moveDownButton = actionDisclosure.addItem(
644+
{
645+
icon: async () =>
646+
await Craft.ui.icon(
647+
this.settings.showInGrid
648+
? Craft.orientation === 'ltr'
649+
? 'arrow-right'
650+
: 'arrow-left'
651+
: 'arrow-down'
652+
),
653+
label: this.settings.showInGrid
654+
? Craft.t('app', 'Move backward')
655+
: Craft.t('app', 'Move down'),
656+
onActivate: () => {
657+
const $next = getNext();
658+
if ($next.length) {
659+
$li.insertAfter($next);
660+
this.onSortChange($li);
661+
}
662+
},
663+
},
664+
ul
665+
);
666+
}
667+
605668
const duplicatable = Garnish.hasAttr($element, 'data-duplicatable');
606669
const copyable = Garnish.hasAttr($element, 'data-copyable');
607670

608671
if (duplicatable || copyable) {
609-
const destructiveGroup =
610-
actionDisclosure.getFirstDestructiveGroup();
611672
const ul = actionDisclosure.addGroup(null, true, destructiveGroup);
612673

613674
if (duplicatable) {
614675
// Duplicate
615-
const duplicateButton = actionDisclosure.addItem(
676+
duplicateButton = actionDisclosure.addItem(
616677
{
617678
icon: async () => await Craft.ui.icon('clone'),
618679
label: Craft.t('app', 'Duplicate'),
@@ -622,14 +683,6 @@ Craft.NestedElementManager = Garnish.Base.extend(
622683
},
623684
ul
624685
);
625-
626-
actionDisclosure.on('show', () => {
627-
if (this.canCreate()) {
628-
actionDisclosure.showItem(duplicateButton);
629-
} else {
630-
actionDisclosure.hideItem(duplicateButton);
631-
}
632-
});
633686
}
634687

635688
if (copyable) {
@@ -652,95 +705,39 @@ Craft.NestedElementManager = Garnish.Base.extend(
652705
);
653706
}
654707
}
655-
}
656-
}, 1);
657708

658-
if (this.settings.sortable) {
659-
this.elementSort.addItems($element.parent());
660-
}
709+
if (Garnish.hasAttr($element, 'data-deletable')) {
710+
const ul = actionDisclosure.addGroup();
711+
actionDisclosure.addItem(
712+
{
713+
icon: async () => await Craft.ui.icon('trash'),
714+
label: this.settings.deleteLabel || Craft.t('app', 'Delete'),
715+
destructive: true,
716+
onActivate: () => {
717+
if (confirm(this.settings.deleteConfirmationMessage)) {
718+
this.deleteElement($element);
719+
}
720+
},
721+
},
722+
ul
723+
);
724+
}
661725

662-
const $actionMenuBtn = $element.find('.action-btn');
663-
if ($actionMenuBtn.length > 0) {
664-
const disclosureMenu = $actionMenuBtn
665-
.disclosureMenu()
666-
.data('disclosureMenu');
667-
const $actionMenu = disclosureMenu.$container;
668-
669-
if (this.settings.sortable) {
670-
const $container = $element.parents('.elements');
671-
const $parent = $element.parent();
672-
673-
// show/hide move up/down buttons
674-
disclosureMenu.on('show', () => {
675-
if ($parent.prev('li').length) {
676-
$actionMenu
677-
.find('button[data-move-action=up]:first')
678-
.parent()
679-
.removeClass('hidden');
680-
} else {
681-
$actionMenu
682-
.find('button[data-move-action=up]:first')
683-
.parent()
684-
.addClass('hidden');
685-
}
686-
if ($parent.next('li').length) {
687-
$actionMenu
688-
.find('button[data-move-action=down]:first')
689-
.parent()
690-
.removeClass('hidden');
691-
} else {
692-
$actionMenu
693-
.find('button[data-move-action=down]:first')
694-
.parent()
695-
.addClass('hidden');
726+
actionDisclosure.on('show', () => {
727+
if (moveUpButton) {
728+
actionDisclosure.toggleItem(moveUpButton, getPrev().length);
696729
}
697-
});
698730

699-
const $moveUpBtn = $element
700-
.find('.action-btn')
701-
.data('disclosureMenu')
702-
?.$container.find('[data-move-action="up"]');
703-
if ($moveUpBtn?.length) {
704-
this.addListener($moveUpBtn, 'activate', () => {
705-
let $prev = $parent.prev('li');
706-
if ($prev.length) {
707-
$parent.insertBefore($prev);
708-
this.onSortChange($parent);
709-
}
710-
});
711-
}
712-
const $moveDownBtn = $element
713-
.find('.action-btn')
714-
.data('disclosureMenu')
715-
?.$container.find('[data-move-action="down"]');
716-
if ($moveDownBtn?.length) {
717-
this.addListener($moveDownBtn, 'activate', () => {
718-
let $next = $parent.next('li');
719-
if ($next.length) {
720-
$parent.insertAfter($next);
721-
this.onSortChange($parent);
722-
}
723-
});
724-
}
725-
}
731+
if (moveDownButton) {
732+
actionDisclosure.toggleItem(moveDownButton, getNext().length);
733+
}
726734

727-
if (Garnish.hasAttr($element, 'data-deletable')) {
728-
const ul = disclosureMenu.addGroup();
729-
disclosureMenu.addItem(
730-
{
731-
icon: async () => await Craft.ui.icon('trash'),
732-
label: this.settings.deleteLabel || Craft.t('app', 'Delete'),
733-
destructive: true,
734-
onActivate: () => {
735-
if (confirm(this.settings.deleteConfirmationMessage)) {
736-
this.deleteElement($element);
737-
}
738-
},
739-
},
740-
ul
741-
);
735+
if (duplicateButton) {
736+
actionDisclosure.toggleItem(duplicateButton, this.canCreate());
737+
}
738+
});
742739
}
743-
}
740+
}, 1);
744741
},
745742

746743
createElementEditor($element) {

0 commit comments

Comments
 (0)