Skip to content

Commit 7dd502e

Browse files
authored
Merge pull request #14172 from craftcms/feature/cms-1233-multiple-tab-support-for-inline-matrix-blocks
Feature/cms 1233 multiple tab support for inline matrix blocks
2 parents 5ef95c7 + 26aaa41 commit 7dd502e

File tree

22 files changed

+364
-140
lines changed

22 files changed

+364
-140
lines changed

CHANGELOG-WIP.md

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
- The “Save as a new entry” action is now available to all users with the “Create entries” permission, and will create a new unpublished draft rather than a fully-saved entry. ([#9577](https://github.com/craftcms/cms/issues/9577), [#10244](https://github.com/craftcms/cms/discussions/10244))
1414
- Entry conditions can now have a “Matrix field” rule. ([#13794](https://github.com/craftcms/cms/discussions/13794))
1515
- Money field condition rules now use money inputs. ([#14148](https://github.com/craftcms/cms/pull/14148))
16+
- Inline-editable Matrix blocks now support multiple tabs. ([8500](https://github.com/craftcms/cms/discussions/8500), [#14139](https://github.com/craftcms/cms/issues/14139))
17+
- Inline-editable Matrix blocks now include “Open in a new tab” action items.
1618
- Selected elements within relational fields now include a context menu with “View in a new tab”, “Edit”, and “Remove” options.
1719
- Selected elements within relational fields now include a dedicated drag handle.
1820
- Selected assets within Assets fields no longer open the file preview modal when their thumbnail is clicked on. The “Preview file” quick action, or the <kbd>Shift</kbd> + <kbd>Spacebar</kbd> keyboard shortcut, can be used instead.
@@ -46,6 +48,7 @@
4648
- Selected elements within relational fields now include “Move up/down” or “Move forward/backward” in their action menus.
4749
- Improved the accessibility of time zone fields.
4850
- Improved the accessibility of form alternative action menus.
51+
- Improved the accessibility of inline-editable Matrix blocks.
4952

5053
### Administration
5154
- Added the “Icon” entry type setting. ([#14169](https://github.com/craftcms/cms/pull/14169))

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Inline-editable Matrix blocks now support multiple tabs. ([8500](https://github.com/craftcms/cms/discussions/8500), [#14139](https://github.com/craftcms/cms/issues/14139))
6+
- Inline-editable Matrix blocks now include “Open in a new tab” action items.
57
- Added the “Icon” entry type setting. ([#14169](https://github.com/craftcms/cms/pull/14169))
68
- Added the “Icon” field type. ([#14169](https://github.com/craftcms/cms/pull/14169))
79
- Added an SVG icon set based on Font Awesome 6.5.1. ([#14169](https://github.com/craftcms/cms/pull/14169))
@@ -12,7 +14,10 @@
1214
- Improved the accessibility of time zone fields.
1315
- Improved the accessibility of form alternative action menus.
1416
- Improved the accessibility of element indexes. ([#12286](https://github.com/craftcms/cms/pull/12286))
17+
- Improved the accessibility of inline-editable Matrix blocks.
1518
- Database backups no longer include data from the `phpsessions` table, if it exists. ([#13589](https://github.com/craftcms/cms/pull/13589))
19+
- Disclosure menu items now default to the `button` type. `link` is only assumed if a `url` key is set.
20+
- Disclosure menus now support defining horizontal rules via `hr: true` (in addition to `type: 'hr'`).
1621
- Added the `utils/prune-orphaned-entries` command. ([#14154](https://github.com/craftcms/cms/pull/14154))
1722
- Added `craft\base\Actionable`. ([#14169](https://github.com/craftcms/cms/pull/14169))
1823
- Added `craft\base\Chippable`. ([#14169](https://github.com/craftcms/cms/pull/14169))

src/fields/Matrix.php

+10
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,16 @@ public function getStaticHtml(mixed $value, ElementInterface $element): string
10171017

10181018
$id = StringHelper::randomString();
10191019

1020+
$js = '';
1021+
1022+
foreach ($entries as $entry) {
1023+
$js .= <<<JS
1024+
Craft.cp.initMatrixTabs($('div.matrixblock.static[data-uid="$entry->uid"]'));
1025+
JS;
1026+
}
1027+
1028+
Craft::$app->getView()->registerJs("(() => {\n$js\n})();");
1029+
10201030
return Craft::$app->getView()->renderTemplate('_components/fieldtypes/Matrix/input.twig', [
10211031
'id' => $id,
10221032
'name' => $id,

src/helpers/Cp.php

+7-5
Original file line numberDiff line numberDiff line change
@@ -2579,9 +2579,9 @@ public static function disclosureMenu(array $items, array $config = []): string
25792579
*
25802580
* The item config can contain a `type` key set to a [[MenuItemType]] case. By default, it will be set to:
25812581
*
2582-
* - [[MenuItemType::Button]] if `action` is set
2582+
* - [[MenuItemType::Link]] if `url` is set
25832583
* - [[MenuItemType::Group]] if `heading` or `items` are set
2584-
* - [[MenuItemType::Link]] in all other cases
2584+
* - [[MenuItemType::Button]] in all other cases
25852585
*
25862586
* Link and button item configs can contain the following keys:
25872587
*
@@ -2626,12 +2626,14 @@ public static function normalizeMenuItems(array $items): array
26262626
{
26272627
return array_map(function(array $item) {
26282628
if (!isset($item['type'])) {
2629-
if (isset($item['action'])) {
2630-
$item['type'] = MenuItemType::Button;
2629+
if (isset($item['url'])) {
2630+
$item['type'] = MenuItemType::Link;
2631+
} elseif ($item['hr'] ?? false) {
2632+
$item['type'] = MenuItemType::HR;
26312633
} elseif (isset($item['heading']) || isset($item['items'])) {
26322634
$item['type'] = MenuItemType::Group;
26332635
} else {
2634-
$item['type'] = MenuItemType::Link;
2636+
$item['type'] = MenuItemType::Button;
26352637
}
26362638
}
26372639

src/services/Elements.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4010,7 +4010,7 @@ private function _crossSiteValidationErrors(
40104010
$message .
40114011
Html::tag('span', '', [
40124012
'data-icon' => 'external',
4013-
'aria-label' => Craft::t('app', 'Open the full edit page in a new tab'),
4013+
'aria-label' => Craft::t('app', 'Open in a new tab'),
40144014
'role' => 'img',
40154015
]) .
40164016
Html::endTag('a');

src/templates/_components/fieldtypes/Matrix/block.twig

+123-31
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
{% set actionMenuId = "matrixblock-action-menu--#{entry.uid}" %}
2525

2626
{% set actionBtnAttributes = {
27-
class: ['btn', 'settings', 'icon', 'menubtn'],
27+
class: ['action-btn', 'btn'],
2828
type: 'button',
2929
role: 'button',
3030
title: 'Actions'|t('app'),
@@ -37,6 +37,100 @@
3737
}
3838
} %}
3939

40+
{% set actionMenuItems = [
41+
{
42+
label: 'Collapse'|t('app'),
43+
attributes: {
44+
data: {icon: 'down-left-and-up-right-to-center', action: 'collapse'},
45+
},
46+
},
47+
{
48+
label: 'Expand'|t('app'),
49+
attributes: {
50+
data: {icon: 'up-right-and-down-left-from-center', action: 'expand'},
51+
},
52+
liAttributes: {
53+
class: ['hidden'],
54+
},
55+
},
56+
{
57+
label: 'Disable'|t('app'),
58+
attributes: {
59+
data: {icon: 'circle-dashed', action: 'disable'},
60+
},
61+
liAttributes: {
62+
class: {
63+
hidden: not entry.enabled,
64+
}|filter|keys,
65+
},
66+
},
67+
{
68+
label: 'Enable'|t('app'),
69+
attributes: {
70+
data: {icon: 'circle', action: 'enable'},
71+
},
72+
liAttributes: {
73+
class: {
74+
hidden: entry.enabled,
75+
}|filter|keys,
76+
},
77+
},
78+
{
79+
label: 'Move up'|t('app'),
80+
attributes: {
81+
data: {icon: 'arrow-up', action: 'moveUp'},
82+
},
83+
},
84+
{
85+
label: 'Move down'|t('app'),
86+
attributes: {
87+
data: {icon: 'arrow-down', action: 'moveDown'},
88+
},
89+
},
90+
] %}
91+
92+
{% if entry.id %}
93+
{% set actionMenuItems = actionMenuItems|merge([
94+
{hr: true},
95+
{
96+
label: 'Open in a new tab'|t('app'),
97+
url: entry.getCpEditUrl(),
98+
attributes: {
99+
target: '_blank',
100+
data: {icon: 'external'},
101+
},
102+
},
103+
]) %}
104+
{% endif %}
105+
106+
{% if not staticEntries %}
107+
{% set actionMenuItems = actionMenuItems|merge([
108+
{hr: true},
109+
{
110+
label: 'Delete'|t('app'),
111+
destructive: true,
112+
attributes: {
113+
data: {icon: 'xmark', action: 'delete'},
114+
},
115+
},
116+
{hr: true},
117+
]) %}
118+
119+
{% for entryType in entryTypes %}
120+
{% set actionMenuItems = actionMenuItems|push({
121+
label: 'Add {type} above'|t('app', {type: entryType.name|t('site')}),
122+
attributes: {
123+
data: {icon: 'plus', action: 'add', type: entryType.handle},
124+
},
125+
}) %}
126+
{% endfor %}
127+
{% endif %}
128+
129+
{% namespace baseInputName %}
130+
{% set form = entry.getFieldLayout().createForm(entry, static) %}
131+
{% set tabs = form.getTabMenu() %}
132+
{% endnamespace %}
133+
40134
<div {{ attr(entryAttributes) }}>
41135
{% if not static %}
42136
{{ hiddenInput("#{name}[sortOrder][]", entry.uid) }}
@@ -46,13 +140,24 @@
46140
{% endif %}
47141
{{ hiddenInput("#{baseInputName}[type]", entryType.handle) }}
48142
{{ hiddenInput("#{baseInputName}[enabled]", entry.enabled ? '1' : '') }}
49-
<div class="titlebar">
50-
<div class="blocktype{% if entry.hasErrors() %} error{% endif %}">
51-
{{ entryTypeName }}
52-
{% if entry.hasErrors() %}<span data-icon="alert" aria-label="{{ 'Error'|t('app') }}"></span>{% endif %}
53-
</div>
54-
<div class="preview"></div>
143+
{% endif %}
144+
145+
<div class="titlebar">
146+
<div class="blocktype{% if not static and entry.hasErrors() %} error{% endif %}">
147+
{{ entryTypeName }}
148+
{% if not static and entry.hasErrors() %}<span data-icon="alert" aria-label="{{ 'Error'|t('app') }}"></span>{% endif %}
149+
</div>
150+
<div class="preview"></div>
151+
<div class="matrixblock-tabs">
152+
{% namespace baseInputName %}
153+
{% if tabs|length > 1 %}
154+
{% include '_includes/tabs.twig' with {'tabs': tabs, 'containerAttributes': {'id': 'tabs'}} %}
155+
{% endif %}
156+
{% endnamespace %}
55157
</div>
158+
</div>
159+
160+
{% if not static %}
56161
<div class="checkbox" title="{{ 'Select'|t('app') }}" aria-label="{{ 'Select'|t('app') }}"></div>
57162
<div class="actions">
58163
<div class="status off" title="{{ 'Disabled'|t('app') }}">
@@ -63,36 +168,23 @@
63168
</div>
64169

65170
<div>
66-
<button {{ attr(actionBtnAttributes) }}></button>
67-
<div id="{{ actionMenuId }}" class="menu menu--disclosure">
68-
<ul>
69-
<li><a data-icon="collapse" data-action="collapse" href="#" type="button" role="button" aria-label="{{ 'Collapse'|t('app') }}">{{ "Collapse"|t('app') }}</a></li>
70-
<li class="hidden"><a data-icon="expand" data-action="expand" href="#" type="button" role="button" aria-label="{{ 'Expand'|t('app') }}">{{ "Expand"|t('app') }}</a></li>
71-
<li{% if not entry.enabled %} class="hidden"{% endif %}><a data-icon="disabled" data-action="disable" href="#" type="button" role="button" aria-label="{{ 'Disable'|t('app') }}">{{ "Disable"|t('app') }}</a></li>
72-
<li{% if entry.enabled %} class="hidden"{% endif %}><a data-icon="enabled" data-action="enable" href="#" type="button" role="button" aria-label="{{ 'Enable'|t('app') }}">{{ "Enable"|t('app') }}</a></li>
73-
<li><a data-icon="uarr" data-action="moveUp" href="#" type="button" role="button" aria-label="{{ 'Move up'|t('app') }}">{{ 'Move up'|t('app') }}</a></li>
74-
<li><a data-icon="darr" data-action="moveDown" href="#" type="button" role="button" aria-label="{{ 'Move down'|t('app') }}">{{ 'Move down'|t('app') }}</a></li>
75-
</ul>
76-
{% if not staticEntries %}
77-
<hr class="padded">
78-
<ul>
79-
<li><a class="error" data-icon="remove" data-action="delete" href="#" type="button" role="button" aria-label="{{ 'Delete'|t('app') }}">{{ "Delete"|t('app') }}</a></li>
80-
</ul>
81-
<hr class="padded">
82-
<ul>
83-
{% for entryType in entryTypes %}
84-
<li><a data-icon="plus" data-action="add" data-type="{{ entryType.handle }}" href="#" type="button" role="button" aria-label="{{ 'Add {type} above'|t('app', { type: entryType.name|t('site') }) }}">{{ "Add {type} above"|t('app', { type: entryType.name|t('site') }) }}</a></li>
85-
{% endfor %}
86-
</ul>
87-
{% endif %}
88-
</div>
171+
{{ disclosureMenu(actionMenuItems, {
172+
hiddenLabel: 'Actions'|t('app'),
173+
buttonAttributes: {
174+
class: ['action-btn'],
175+
title: 'Actions'|t('app'),
176+
data: {
177+
'disclosure-trigger': true,
178+
},
179+
},
180+
}) }}
89181
</div>
90182
<a class="move icon" title="{{ 'Reorder'|t('app') }}" aria-label="{{ 'Reorder'|t('app') }}" role="button"></a>
91183
</div>
92184
{% endif %}
93185
<div class="fields">
94186
{% namespace baseInputName %}
95-
{{ entry.getFieldLayout().createForm(entry, static).render()|raw }}
187+
{{ form.render()|raw }}
96188
{% endnamespace %}
97189
</div>
98190
</div>

src/templates/_includes/disclosuremenu.twig

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
{% macro itemType(item) %}
77
{%- if item.type ?? false %}
88
{{- item.type }}
9-
{%- elseif item.action ?? false %}
10-
{{- 'button' }}
9+
{%- elseif item.url ?? false %}
10+
{{- 'link' }}
11+
{%- elseif item.hr ?? false %}
12+
{{- 'hr' }}
1113
{%- elseif item.heading ?? item.items ?? false %}
1214
{{- 'group' }}
1315
{%- else %}
14-
{{- 'link' }}
16+
{{- 'button' }}
1517
{%- endif %}
1618
{%- endmacro %}
1719

src/templates/users/_auth-methods.twig

+1-5
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,8 @@
4040
</div>
4141
{{ disclosureMenu(actionMenuItems, {
4242
buttonAttributes: {
43-
class: ['auth-method-action-btn', 'hairline'],
44-
removeClass: 'menubtn',
43+
class: ['auth-method-action-btn', 'action-btn', 'hairline'],
4544
title: 'Actions'|t('app'),
46-
data: {
47-
icon: 'ellipsis',
48-
},
4945
},
5046
}) }}
5147
</div>

src/translations/en/app.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@
10741074
'Oops!' => 'Oops!',
10751075
'Open PRs' => 'Open PRs',
10761076
'Open in Image Editor' => 'Open in Image Editor',
1077-
'Open the full edit page in a new tab' => 'Open the full edit page in a new tab',
1077+
'Open in a new tab' => 'Open in a new tab',
10781078
'Opens in a new window' => 'Opens in a new window',
10791079
'Operator' => 'Operator',
10801080
'Optgroup?' => 'Optgroup?',

src/web/CpScreenResponseFormatter.php

-2
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,7 @@ private function _formatTemplate(YiiResponse $response, CpScreenResponseBehavior
179179
'buttonAttributes' => [
180180
'id' => 'action-btn',
181181
'class' => ['action-btn'],
182-
'removeClass' => 'menubtn',
183182
'title' => Craft::t('app', 'Actions'),
184-
'data' => ['icon' => 'ellipsis'],
185183
],
186184
]),
187185
'submitButtonLabel' => $behavior->submitButtonLabel,

src/web/assets/cp/CpAsset.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ private function _registerTranslations(View $view): void
270270
'Notes',
271271
'Notice',
272272
'OK',
273-
'Open the full edit page in a new tab',
273+
'Open in a new tab',
274274
'Options',
275275
'Password',
276276
'Past year',

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/dist/css/cp.css

+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/css/cp.css.map

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

0 commit comments

Comments
 (0)