|
33 | 33 | use craft\elements\db\ElementQuery; |
34 | 34 | use craft\elements\db\ElementQueryInterface; |
35 | 35 | use craft\elements\db\NestedElementQueryInterface; |
| 36 | +use craft\elements\deletionblockers\RelationDeletionBlocker; |
36 | 37 | use craft\elements\ElementCollection; |
37 | 38 | use craft\elements\Entry; |
38 | 39 | use craft\elements\exporters\Expanded; |
|
47 | 48 | use craft\events\DefineAttributeHtmlEvent; |
48 | 49 | use craft\events\DefineAttributeKeywordsEvent; |
49 | 50 | use craft\events\DefineEagerLoadingMapEvent; |
| 51 | +use craft\events\DefineElementDeletionBlockersEvent; |
50 | 52 | use craft\events\DefineHtmlEvent; |
51 | 53 | use craft\events\DefineMenuItemsEvent; |
52 | 54 | use craft\events\DefineMetadataEvent; |
@@ -755,6 +757,24 @@ abstract class Element extends Component implements ElementInterface |
755 | 757 | */ |
756 | 758 | public const EVENT_AFTER_PROPAGATE = 'afterPropagate'; |
757 | 759 |
|
| 760 | + /** |
| 761 | + * @event DefineElementDeletionBlockersEvent The event that is triggered when defining any blockers that should prevent a user from being deleted |
| 762 | + * |
| 763 | + * --- |
| 764 | + * ```php |
| 765 | + * use craft\elements\User; |
| 766 | + * use craft\events\DefineUserDeletionBlockersEvent; |
| 767 | + * use yii\base\Event; |
| 768 | + * |
| 769 | + * Event::on(User::class, User::EVENT_DEFINE_DELETION_BLOCKERS, function(DefineElementDeletionBlockersEvent $event) { |
| 770 | + * $event->blockers[] = // ... |
| 771 | + * }); |
| 772 | + * ``` |
| 773 | + * |
| 774 | + * @since 5.10.0 |
| 775 | + */ |
| 776 | + public const EVENT_DEFINE_DELETION_BLOCKERS = 'defineDeletionBlockers'; |
| 777 | + |
758 | 778 | /** |
759 | 779 | * @event ModelEvent The event that is triggered before the element is deleted. |
760 | 780 | * |
@@ -2214,6 +2234,36 @@ private static function _mapRevisionCreators(array $sourceElements): array |
2214 | 2234 | ]; |
2215 | 2235 | } |
2216 | 2236 |
|
| 2237 | + /** |
| 2238 | + * @inheritdoc |
| 2239 | + */ |
| 2240 | + public static function deletionBlockers(ElementCollection $elements, bool $hardDelete): array |
| 2241 | + { |
| 2242 | + $blockers = [ |
| 2243 | + new RelationDeletionBlocker(Entry::class, $elements, $hardDelete, [ |
| 2244 | + 'elementIndexSettings' => [ |
| 2245 | + 'defaultTableColumns' => [ |
| 2246 | + ['section'], |
| 2247 | + ], |
| 2248 | + 'defaultSort' => ['section', 'asc'], |
| 2249 | + ], |
| 2250 | + ]), |
| 2251 | + ]; |
| 2252 | + |
| 2253 | + // Fire a 'defineDeletionBlockers' event |
| 2254 | + if (Event::hasHandlers(static::class, self::EVENT_DEFINE_DELETION_BLOCKERS)) { |
| 2255 | + $event = new DefineElementDeletionBlockersEvent([ |
| 2256 | + 'elements' => $elements, |
| 2257 | + 'hardDelete' => $hardDelete, |
| 2258 | + 'blockers' => $blockers, |
| 2259 | + ]); |
| 2260 | + Event::trigger(static::class, self::EVENT_DEFINE_DELETION_BLOCKERS, $event); |
| 2261 | + $blockers = $event->blockers; |
| 2262 | + } |
| 2263 | + |
| 2264 | + return $blockers; |
| 2265 | + } |
| 2266 | + |
2217 | 2267 | /** |
2218 | 2268 | * @inheritdoc |
2219 | 2269 | */ |
@@ -4265,22 +4315,47 @@ protected function destructiveActionMenuItems(): array |
4265 | 4315 |
|
4266 | 4316 | // Delete |
4267 | 4317 | if ($canDeleteCanonical) { |
| 4318 | + $view = Craft::$app->getView(); |
| 4319 | + $deleteId = sprintf('action-delete-%s', mt_rand()); |
4268 | 4320 | $items[] = [ |
| 4321 | + 'id' => $deleteId, |
4269 | 4322 | 'icon' => 'trash', |
4270 | 4323 | 'label' => StringHelper::upperCaseFirst(Craft::t('app', 'Delete {type}', [ |
4271 | 4324 | 'type' => $isUnpublishedDraft ? Craft::t('app', 'draft') : static::lowerDisplayName(), |
4272 | 4325 | ])), |
4273 | | - 'action' => $isUnpublishedDraft ? 'elements/delete-draft' : 'elements/delete', |
4274 | | - 'params' => [ |
4275 | | - 'elementId' => $this->getCanonicalId(), |
4276 | | - 'siteId' => $this->siteId, |
4277 | | - ], |
4278 | | - 'redirect' => "$redirectUrl#", |
4279 | | - 'confirm' => Craft::t('app', 'Are you sure you want to delete this {type}?', [ |
4280 | | - 'type' => $isUnpublishedDraft ? Craft::t('app', 'draft') : static::lowerDisplayName(), |
4281 | | - ]), |
4282 | | - 'destructive' => true, |
4283 | 4326 | ]; |
| 4327 | + |
| 4328 | + $view->registerJsWithVars(fn( |
| 4329 | + $id, |
| 4330 | + $elementType, |
| 4331 | + $elementId, |
| 4332 | + $siteId, |
| 4333 | + $ownerId, |
| 4334 | + $confirmationMessage, |
| 4335 | + $redirect, |
| 4336 | + ) => <<<JS |
| 4337 | +$('#' + $id).on('activate', async () => { |
| 4338 | + new Craft.ElementDeletionManager($elementType, [$elementId], { |
| 4339 | + siteId: $siteId, |
| 4340 | + ownerId: $ownerId, |
| 4341 | + confirmationMessage: $confirmationMessage, |
| 4342 | + onSuccess: () => { |
| 4343 | + document.location.href = $redirect; |
| 4344 | + }, |
| 4345 | + }); |
| 4346 | +}); |
| 4347 | +JS, |
| 4348 | + [ |
| 4349 | + $view->namespaceInputId($deleteId), |
| 4350 | + static::class, |
| 4351 | + $this->id, |
| 4352 | + $this->siteId, |
| 4353 | + $this instanceof NestedElementInterface ? $this->getOwnerId() : null, |
| 4354 | + Craft::t('app', 'Are you sure you want to delete this {type}?', [ |
| 4355 | + 'type' => $isDraft ? Craft::t('app', 'draft') : static::lowerDisplayName(), |
| 4356 | + ]), |
| 4357 | + "$redirectUrl#", |
| 4358 | + ]); |
4284 | 4359 | } |
4285 | 4360 | } elseif ($isDraft && $canDeleteDraft) { |
4286 | 4361 | // Delete draft for site |
|
0 commit comments