Skip to content
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

Bugfix/nested elements and revisions 2 #15961

Merged
merged 7 commits into from
Nov 5, 2024
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: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- Fixed an error that could occur when editing a nested Matrix entry in a slideout or full-page editor, if it was initially edited while the Matrix field was in inline-editable blocks mode.
- Fixed an error that could occur when editing an address that had provisional changes.
- Fixed a bug where address cards weren’t showing provisional changes.
- Fixed a bug where it was possible to edit nested addresses when viewing a revision. ([#15961](https://github.com/craftcms/cms/pull/15961))
- Fixed a bug where nested elements could have checkboxes and drag handles when viewing a revision. ([#15961](https://github.com/craftcms/cms/pull/15961))
- Updated Axios to 1.7.7. ([#15958](https://github.com/craftcms/cms/issues/15958))

## 5.4.9 - 2024-10-22
Expand Down
5 changes: 3 additions & 2 deletions src/base/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -1184,13 +1184,14 @@ public static function indexHtml(
bool $sortable,
): string {
$request = Craft::$app->getRequest();
$static = $viewState['static'] ?? false;
$variables = [
'viewMode' => $viewState['mode'],
'context' => $context,
'disabledElementIds' => $disabledElementIds,
'collapsedElementIds' => $request->getParam('collapsedElementIds'),
'selectable' => $selectable,
'sortable' => $sortable,
'selectable' => !$static && $selectable,
'sortable' => !$static && $sortable,
'showHeaderColumn' => $viewState['showHeaderColumn'] ?? false,
'inlineEditing' => $viewState['inlineEditing'] ?? false,
'nestedInputNamespace' => $viewState['nestedInputNamespace'] ?? null,
Expand Down
2 changes: 1 addition & 1 deletion src/elements/NestedElementManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ function(string $id, array $config, string $attribute, array &$settings) use ($o
'static' => $config['static'],
];

if ($config['sortable']) {
if (!$config['static'] && $config['sortable']) {
$view->startJsBuffer();
$actionConfig = ElementHelper::actionConfig(new ChangeSortOrder($owner, $attribute));
$actionConfig['bodyHtml'] = $view->clearJsBuffer();
Expand Down
162 changes: 82 additions & 80 deletions src/fieldlayoutelements/addresses/AddressField.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,92 +98,94 @@ public function formHtml(ElementInterface $element = null, bool $static = false)

$view = Craft::$app->getView();

$view->registerJsWithVars(fn($namespace) => <<<JS
(() => {
const initFields = (values) => {
const fields = {};
const fieldNames = [
'countryCode',
'addressLine1',
'addressLine2',
'addressLine3',
'administrativeArea',
'locality',
'dependentLocality',
'postalCode',
'sortingCode',
];
const hotFieldNames = [
'countryCode',
'administrativeArea',
'locality',
];
for (let name of fieldNames) {
fields[name] = $('#' + Craft.namespaceId(name, $namespace));
if (values) {
fields[name].val(values[name]);
}
}
for (let name of hotFieldNames) {
const field = fields[name];
if (field.prop('nodeName') !== 'SELECT') {
break;
if (!$static) {
$view->registerJsWithVars(fn($namespace) => <<<JS
(() => {
const initFields = (values) => {
const fields = {};
const fieldNames = [
'countryCode',
'addressLine1',
'addressLine2',
'addressLine3',
'administrativeArea',
'locality',
'dependentLocality',
'postalCode',
'sortingCode',
];
const hotFieldNames = [
'countryCode',
'administrativeArea',
'locality',
];
for (let name of fieldNames) {
fields[name] = $('#' + Craft.namespaceId(name, $namespace));
if (values) {
fields[name].val(values[name]);
}
}

let oldFieldVal = field.val();
const spinner = $('#' + Craft.namespaceId(name + '-spinner', $namespace));
field.off().on('change', () => {
if (!field.val() || oldFieldVal === field.val()) {
return;
for (let name of hotFieldNames) {
const field = fields[name];
if (field.prop('nodeName') !== 'SELECT') {
break;
}
spinner.removeClass('hidden');
const hotValues = {};
for (let hotName of hotFieldNames) {
hotValues[hotName] = fields[hotName].val();
if (hotName === name) {
break;

let oldFieldVal = field.val();
const spinner = $('#' + Craft.namespaceId(name + '-spinner', $namespace));
field.off().on('change', () => {
if (!field.val() || oldFieldVal === field.val()) {
return;
}
}
Craft.sendActionRequest('POST', 'addresses/fields', {
params: Object.assign({}, hotValues, {
namespace: $namespace,
}),
}).then(async (response) => {
const values = Object.assign(
Object.fromEntries(fieldNames.map(name => [name, fields[name].val()])),
Object.fromEntries(hotFieldNames.map(name => [name, hotValues[name] || null]))
);
const activeElementId = document.activeElement ? document.activeElement.id : null;
const \$addressFields = $(
Object.entries(fields)
.filter(([name]) => name !== 'countryCode')
.map(([, \$field]) => \$field.closest('.field')[0])
);
\$addressFields.eq(0).replaceWith(response.data.fieldsHtml);
\$addressFields.remove();
await Craft.appendHeadHtml(response.data.headHtml);
await Craft.appendBodyHtml(response.data.bodyHtml);
initFields(values);
if (activeElementId) {
$('#' + activeElementId).focus();
spinner.removeClass('hidden');
const hotValues = {};
for (let hotName of hotFieldNames) {
hotValues[hotName] = fields[hotName].val();
if (hotName === name) {
break;
}
}
}).catch(e => {
Craft.cp.displayError();
throw e;
}).finally(() => {
spinner.addClass('hidden');
});
})
Craft.sendActionRequest('POST', 'addresses/fields', {
params: Object.assign({}, hotValues, {
namespace: $namespace,
}),
}).then(async (response) => {
const values = Object.assign(
Object.fromEntries(fieldNames.map(name => [name, fields[name].val()])),
Object.fromEntries(hotFieldNames.map(name => [name, hotValues[name] || null]))
);
const activeElementId = document.activeElement ? document.activeElement.id : null;
const \$addressFields = $(
Object.entries(fields)
.filter(([name]) => name !== 'countryCode')
.map(([, \$field]) => \$field.closest('.field')[0])
);
\$addressFields.eq(0).replaceWith(response.data.fieldsHtml);
\$addressFields.remove();
await Craft.appendHeadHtml(response.data.headHtml);
await Craft.appendBodyHtml(response.data.bodyHtml);
initFields(values);
if (activeElementId) {
$('#' + activeElementId).focus();
}
}).catch(e => {
Craft.cp.displayError();
throw e;
}).finally(() => {
spinner.addClass('hidden');
});
})
}
};

initFields();
})();
JS, [
$view->getNamespace(),
]);
}
};

initFields();
})();
JS, [
$view->getNamespace(),
]);

return Cp::addressFieldsHtml($element);
return Cp::addressFieldsHtml($element, $static);
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/fieldlayoutelements/addresses/CountryCodeField.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ protected function inputHtml(?ElementInterface $element = null, bool $static = f
'options' => Craft::$app->getAddresses()->getCountryRepository()->getList(Craft::$app->language),
'value' => $element->countryCode,
'autocomplete' => $element->getBelongsToCurrentUser() ? 'country' : 'off',
'disabled' => $static,
]) .
Html::tag('div', '', [
'id' => 'countryCode-spinner',
Expand Down
30 changes: 22 additions & 8 deletions src/helpers/Cp.php
Original file line number Diff line number Diff line change
Expand Up @@ -2116,10 +2116,11 @@ public static function autosuggestFieldHtml(array $config): string
* Returns address fields’ HTML (sans country) for a given address.
*
* @param Address $address
* @param bool $static
* @return string
* @since 4.0.0
*/
public static function addressFieldsHtml(Address $address): string
public static function addressFieldsHtml(Address $address, bool $static = false): string
{
$requiredFields = [];
$scenario = $address->getScenario();
Expand Down Expand Up @@ -2155,10 +2156,11 @@ public static function addressFieldsHtml(Address $address): string
'value' => $address->addressLine1,
'autocomplete' => $belongsToCurrentUser ? 'address-line1' : 'off',
'required' => isset($requiredFields['addressLine1']),
'errors' => $address->getErrors('addressLine1'),
'errors' => !$static ? $address->getErrors('addressLine1') : [],
'data' => [
'error-key' => 'addressLine1',
],
'disabled' => $static,
]) .
static::textFieldHtml([
'status' => $address->getAttributeStatus('addressLine2'),
Expand All @@ -2168,10 +2170,11 @@ public static function addressFieldsHtml(Address $address): string
'value' => $address->addressLine2,
'autocomplete' => $belongsToCurrentUser ? 'address-line2' : 'off',
'required' => isset($requiredFields['addressLine2']),
'errors' => $address->getErrors('addressLine2'),
'errors' => !$static ? $address->getErrors('addressLine2') : [],
'data' => [
'error-key' => 'addressLine2',
],
'disabled' => $static,
]) .
static::textFieldHtml([
'status' => $address->getAttributeStatus('addressLine3'),
Expand All @@ -2181,10 +2184,11 @@ public static function addressFieldsHtml(Address $address): string
'value' => $address->addressLine3,
'autocomplete' => $belongsToCurrentUser ? 'address-line3' : 'off',
'required' => isset($requiredFields['addressLine3']),
'errors' => $address->getErrors('addressLine3'),
'errors' => !$static ? $address->getErrors('addressLine3') : [],
'data' => [
'error-key' => 'addressLine3',
],
'disabled' => $static,
]) .
self::_subdivisionField(
$address,
Expand All @@ -2194,6 +2198,7 @@ public static function addressFieldsHtml(Address $address): string
isset($requiredFields['administrativeArea']),
[$address->countryCode],
true,
$static,
) .
self::_subdivisionField(
$address,
Expand All @@ -2203,6 +2208,7 @@ public static function addressFieldsHtml(Address $address): string
isset($requiredFields['locality']),
$parents['locality'],
true,
$static,
) .
self::_subdivisionField(
$address,
Expand All @@ -2212,6 +2218,7 @@ public static function addressFieldsHtml(Address $address): string
isset($requiredFields['dependentLocality']),
$parents['dependentLocality'],
false,
$static,
) .
static::textFieldHtml([
'fieldClass' => array_filter([
Expand All @@ -2225,10 +2232,11 @@ public static function addressFieldsHtml(Address $address): string
'value' => $address->postalCode,
'autocomplete' => $belongsToCurrentUser ? 'postal-code' : 'off',
'required' => isset($requiredFields['postalCode']),
'errors' => $address->getErrors('postalCode'),
'errors' => !$static ? $address->getErrors('postalCode') : [],
'data' => [
'error-key' => 'postalCode',
],
'disabled' => $static,
]) .
static::textFieldHtml([
'fieldClass' => array_filter([
Expand All @@ -2241,10 +2249,11 @@ public static function addressFieldsHtml(Address $address): string
'name' => 'sortingCode',
'value' => $address->sortingCode,
'required' => isset($requiredFields['sortingCode']),
'errors' => $address->getErrors('sortingCode'),
'errors' => !$static ? $address->getErrors('sortingCode') : [],
'data' => [
'error-key' => 'sortingCode',
],
'disabled' => $static,
]);
}

Expand Down Expand Up @@ -2299,6 +2308,7 @@ private static function _subdivisionField(
bool $required,
?array $parents,
bool $spinner,
bool $static = false,
): string {
$value = $address->$name;
$options = Craft::$app->getAddresses()->getSubdivisionRepository()->getList($parents, Craft::$app->language);
Expand All @@ -2310,7 +2320,7 @@ private static function _subdivisionField(
}

if ($spinner) {
$errors = $address->getErrors($name);
$errors = !$static ? $address->getErrors($name) : [];
$input =
Html::beginTag('div', [
'class' => ['flex', 'flex-nowrap'],
Expand All @@ -2322,6 +2332,7 @@ private static function _subdivisionField(
'options' => $options,
'errors' => $errors,
'autocomplete' => $autocomplete,
'disabled' => $static,
]) .
Html::tag('div', '', [
'id' => "$name-spinner",
Expand All @@ -2338,6 +2349,7 @@ private static function _subdivisionField(
'data' => [
'error-key' => $name,
],
'disabled' => $static,
]);
}

Expand All @@ -2355,6 +2367,7 @@ private static function _subdivisionField(
'data' => [
'error-key' => $name,
],
'disabled' => $static,
]);
}

Expand All @@ -2368,10 +2381,11 @@ private static function _subdivisionField(
'name' => $name,
'value' => $value,
'required' => $required,
'errors' => $address->getErrors($name),
'errors' => !$static ? $address->getErrors($name) : [],
'data' => [
'error-key' => $name,
],
'disabled' => $static,
]);
}

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.

1 change: 1 addition & 0 deletions src/web/assets/cp/src/js/TableElementIndexView.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Craft.TableElementIndexView = Craft.BaseElementIndexView.extend({

if (
this.elementIndex.isAdministrative &&
!this.elementIndex.settings.static &&
this.elementIndex.settings.inlineEditable !== false &&
this.$elementContainer.has('> tr[data-id] > th .element[data-editable]')
) {
Expand Down