Skip to content

Live conditions for inline Matrix blocks #14223

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

Merged
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
2 changes: 1 addition & 1 deletion CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
- Improved checkbox-style deselection behavior for control panel items, to account for double-clicks.
- Table views are no longer available for element indexes on mobile.
- Address conditions now have “Address Line 1”, “Address Line 2”, “Administrative Area”, “Country”, “Dependent Locality”, “First Name”, “Full Name”, “Last Name”, “Locality”, “Organization Tax ID”, “Organization”, “Postal Code”, and “Sorting Code” rules.
- Added live conditional field support to user edit pages. ([#14115](https://github.com/craftcms/cms/pull/14115))
- Added live conditional field support to user edit pages and inline-editable Matrix blocks. ([#14115](https://github.com/craftcms/cms/pull/14115), [#14223](https://github.com/craftcms/cms/pull/14223))
- Earth icons are now localized based on the system time zone.

### User Management
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

- Added live conditional field support to inline-editable Matrix blocks. ([#14223](https://github.com/craftcms/cms/pull/14223))
- Inline-editable Matrix blocks have been redesigned to be visually lighter. ([#14187](https://github.com/craftcms/cms/pull/14187))
- Matrix fields set to the inline-editable blocks view mode no longer show inline entry-creation buttons unless there’s a single entry type. ([#14187](https://github.com/craftcms/cms/pull/14187))
- Improved the accessibility of Matrix fields with the “inline-editable blocks” view mode. ([#14187](https://github.com/craftcms/cms/pull/14187))
Expand Down
4 changes: 3 additions & 1 deletion src/base/NestedElementTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ public function getField(): ?ElementContainerFieldInterface
return null;
}

$field = $this->getOwner()->getFieldLayout()->getFieldById($this->fieldId);
$field = $this->getOwner()?->getFieldLayout()->getFieldById($this->fieldId)
?? Craft::$app->getFields()->getFieldById($this->fieldId);

if (!$field instanceof ElementContainerFieldInterface) {
throw new InvalidConfigException("Invalid field ID: $this->fieldId");
}
Expand Down
62 changes: 39 additions & 23 deletions src/controllers/ElementsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,29 +188,9 @@ public function actionRedirect(?int $elementId = null, ?string $elementUid = nul
*/
public function actionCreate(): Response
{
if (!$this->_elementType) {
throw new BadRequestHttpException('Request missing required body param.');
}

$this->_validateElementType($this->_elementType);

/** @var ElementInterface $element */
$element = $this->element = Craft::createObject($this->_elementType);
if ($this->_siteId) {
$element->siteId = $this->_siteId;
}
$element->setAttributes($this->_attributes);

$element = $this->_createElement();
$user = static::currentUser();

if (!Craft::$app->getElements()->canSave($element, $user)) {
throw new ForbiddenHttpException('User not authorized to create this element.');
}

if (!$element->slug) {
$element->slug = ElementHelper::tempSlug();
}

// Save it
$element->setScenario(Element::SCENARIO_ESSENTIALS);
if (!Craft::$app->getDrafts()->saveElementAsDraft($element, $user->id, null, null, false)) {
Expand Down Expand Up @@ -1747,9 +1727,13 @@ public function actionUpdateFieldLayout(): ?Response
$this->requirePostRequest();
$this->requireCpRequest();

/** @var Element|DraftBehavior|null $element */
$element = $this->_element();
if ($this->_elementId || $this->_elementUid) {
$element = $this->_element();
} else {
$element = $this->_createElement();
}

/** @var Element|DraftBehavior|null $element */
if (!$element || $element->getIsRevision()) {
throw new BadRequestHttpException('No element was identified by the request.');
}
Expand Down Expand Up @@ -2034,6 +2018,38 @@ private function _element(?int $elementId = null, ?string $elementUid = null, ?b
return $element;
}

/**
* Creates a new element.
*
* @throws BadRequestHttpException
* @throws ForbiddenHttpException
*/
private function _createElement(): ElementInterface
{
if (!$this->_elementType) {
throw new BadRequestHttpException('Request missing required body param.');
}

$this->_validateElementType($this->_elementType);

/** @var ElementInterface $element */
$element = $this->element = Craft::createObject($this->_elementType);
if ($this->_siteId) {
$element->siteId = $this->_siteId;
}
$element->setAttributes($this->_attributes);

if (!Craft::$app->getElements()->canSave($element)) {
throw new ForbiddenHttpException('User not authorized to create this element.');
}

if (!$element->slug) {
$element->slug = ElementHelper::tempSlug();
}

return $element;
}

/**
* Ensures the given element type is valid.
*
Expand Down
36 changes: 30 additions & 6 deletions src/fields/Matrix.php
Original file line number Diff line number Diff line change
Expand Up @@ -521,15 +521,25 @@ public function getSupportedSitesForElement(NestedElementInterface $element): ar
*/
public function canViewElement(NestedElementInterface $element, User $user): ?bool
{
return Craft::$app->getElements()->canView($element->getOwner(), $user);
$owner = $element->getOwner();
if (!$owner) {
return true;
}

return Craft::$app->getElements()->canView($owner, $user);
}

/**
* @inheritdoc
*/
public function canSaveElement(NestedElementInterface $element, User $user): ?bool
{
if (!Craft::$app->getElements()->canSave($element->getOwner(), $user)) {
$owner = $element->getOwner();
if (!$owner) {
return true;
}

if (!Craft::$app->getElements()->canSave($owner, $user)) {
return false;
}

Expand All @@ -547,6 +557,10 @@ public function canSaveElement(NestedElementInterface $element, User $user): ?bo
public function canDuplicateElement(NestedElementInterface $element, User $user): ?bool
{
$owner = $element->getOwner();
if (!$owner) {
return true;
}

if (!Craft::$app->getElements()->canSave($owner, $user)) {
return false;
}
Expand All @@ -561,6 +575,10 @@ public function canDuplicateElement(NestedElementInterface $element, User $user)
public function canDeleteElement(NestedElementInterface $element, User $user): ?bool
{
$owner = $element->getOwner();
if (!$owner) {
return true;
}

if (!Craft::$app->getElements()->canSave($element->getOwner(), $user)) {
return false;
}
Expand All @@ -575,6 +593,10 @@ public function canDeleteElement(NestedElementInterface $element, User $user): ?
public function canDeleteElementForSite(NestedElementInterface $element, User $user): ?bool
{
$owner = $element->getOwner();
if (!$owner) {
return true;
}

if (!Craft::$app->getElements()->canSave($owner, $user)) {
return false;
}
Expand Down Expand Up @@ -1016,19 +1038,21 @@ public function getStaticHtml(mixed $value, ElementInterface $element): string
return '<p class="light">' . Craft::t('app', 'No entries.') . '</p>';
}

$id = StringHelper::randomString();
$view = Craft::$app->getView();
$view->registerAssetBundle(MatrixAsset::class);

$id = StringHelper::randomString();
$js = '';

foreach ($entries as $entry) {
$js .= <<<JS
Craft.cp.initMatrixTabs($('.matrixblock[data-uid="$entry->uid"] > .titlebar .matrixblock-tabs'));
Craft.MatrixInput.initTabs($('.matrixblock[data-uid="$entry->uid"] > .titlebar .matrixblock-tabs'));
JS;
}

Craft::$app->getView()->registerJs("(() => {\n$js\n})();");
$view->registerJs("(() => {\n$js\n})();");

return Craft::$app->getView()->renderTemplate('_components/fieldtypes/Matrix/input.twig', [
return $view->renderTemplate('_components/fieldtypes/Matrix/input.twig', [
'id' => $id,
'name' => $id,
'entryTypes' => $this->getEntryTypes(),
Expand Down
29 changes: 14 additions & 15 deletions src/templates/_components/fieldtypes/Matrix/block.twig
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,15 @@
}|filter,
data: {
uid: entry.uid,
'owner-id': entry.ownerId,
'field-id': entry.fieldId,
type: entryType.handle,
'type-name': entryTypeName,
collapsed: entry.collapsed,
'type-id': entry.typeId,
'field-layout-id': entry.getFieldLayout().id,
'visible-layout-elements': form.getVisibleElements(),
'base-input-name': baseInputName|namespaceInputName,
},
role: 'listitem',
} %}
Expand Down Expand Up @@ -165,23 +169,18 @@
{% endtag %}
{% endif %}
<div class="preview"></div>
{% if tabs|length > 1 %}
{% tag 'div' with {
class: ['matrixblock-tabs'],
style: {
'--custom-sel-tab-shadow-color': entryType.color.cssVar(200) ?? null,
}|filter,
} %}
{% tag 'div' with {
class: ['matrixblock-tabs'],
style: {
'--custom-sel-tab-shadow-color': entryType.color.cssVar(200) ?? null,
}|filter,
} %}
{% if tabs|length > 1 %}
{% namespace baseInputName %}
{% include '_includes/tabs.twig' with {
tabs,
containerAttributes: {
id: 'tabs',
},
} %}
{% include '_includes/tabs.twig' %}
{% endnamespace %}
{% endtag %}
{% endif %}
{% endif %}
{% endtag %}
{% endtag %}{# /.titlebar #}

{% if not static %}
Expand Down
2 changes: 1 addition & 1 deletion src/web/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ public function getBodyParams(): array
// Was a namespace passed?
$namespace = $this->getHeaders()->get('X-Craft-Namespace');
if ($namespace) {
$params = $params[$namespace] ?? [];
$params = ArrayHelper::getValue($params, $namespace, []);
}

$this->setBodyParams($this->_utf8AllTheThings($params));
Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js.map

Large diffs are not rendered by default.

41 changes: 0 additions & 41 deletions src/web/assets/cp/src/js/CP.js
Original file line number Diff line number Diff line change
Expand Up @@ -685,47 +685,6 @@ Craft.CP = Garnish.Base.extend(
}
},

initMatrixTabs: function (container) {
const $tabs = $(container).find('div[id$="tabs"].pane-tabs');
if (!$tabs.length) {
return;
}

// init tab manager
let tabManager = new Craft.Tabs($tabs);

// prevent items in the disclosure menu from changing the URL
let disclosureMenu = tabManager.$menuBtn.data('trigger');
$(disclosureMenu.$container)
.find('li, a')
.on('click', function (ev) {
ev.preventDefault();
});

tabManager.on('selectTab', (ev) => {
const href = ev.$tab.attr('href');

// Show its content area
if (href && href.charAt(0) === '#') {
$(href).removeClass('hidden');
}

// Trigger a resize event to update any UI components that are listening for it
Garnish.$win.trigger('resize');

// Fixes Redactor fixed toolbars on previously hidden panes
Garnish.$doc.trigger('scroll');
});

tabManager.on('deselectTab', (ev) => {
const href = ev.$tab.attr('href');
if (href && href.charAt(0) === '#') {
// Hide its content area
$(ev.$tab.attr('href')).addClass('hidden');
}
});
},

handleBreadcrumbVisibility: function () {
if (!this.$crumbItems.length) {
return;
Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/matrix/dist/MatrixInput.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/matrix/dist/MatrixInput.js.map

Large diffs are not rendered by default.

Loading