Perform location hierarchy changes in form submit instead of AJAX.

This commit is contained in:
Michael Stenta 2021-12-01 07:31:03 -05:00
parent 3fd2f9c893
commit 662f7801e0
2 changed files with 90 additions and 161 deletions

View File

@ -39,171 +39,25 @@
var changes = {}
tree.on('node.drop', function(event, source, target, index) {
var destination = (target === null) ? settings.asset_parent : target.uuid
var new_parent = (target === null) ? settings.asset_parent : target.asset_id
if (!changes.hasOwnProperty(source.id)) {
if (source.original_parent !== destination) {
if (source.original_parent !== new_parent) {
changes[source.id] = {
'uuid': source.uuid,
'asset_id': source.asset_id,
'original_parent': source.original_parent,
'original_type': source.original_type,
'destination': destination,
'type': (target === null) ? settings.asset_parent_type : target.type,
'new_parent': new_parent,
}
}
}
else {
if (changes[source.id].original_parent !== destination) {
changes[source.id].destination = destination
if (changes[source.id].original_parent !== new_parent) {
changes[source.id].new_parent = new_parent
}
else {
delete changes[source.id]
}
}
})
$('input#edit-reset').on('click', function(event) {
event.preventDefault()
// Reset the changes so nothing is pushed accidentally.
changes = {}
// Reset the tree to the original status.
tree.reload()
tree.nodes().expand()
domTree.clearSelection()
})
$('input#edit-save').on('click', function(event) {
event.preventDefault()
var button = $(this)
var messages = new Drupal.Message()
messages.clear()
var entries = Object.entries(changes)
if (entries.length <= 0) {
messages.add(Drupal.t('No changes to save'), { type: 'status' })
return
}
button.attr('disabled',true)
var token = ''
$.ajax({
async: false,
url: Drupal.url('session/token'),
success(data) {
if (data) {
token = data
}
},
})
// Build an array of ajax requests.
var requests = [];
for (var [treeUuid, item] of entries) {
if (item.destination === '' && item.original_parent !== '') {
var deleteItem = {
'data': [
{
'type': 'asset--' + item.original_type,
'id': item.original_parent,
}
]
}
requests.push($.ajax({
type: 'DELETE',
cache: false,
headers: {
'X-CSRF-Token': token,
},
url: '/api/asset/' + item.original_type + '/' + item.uuid + '/relationships/parent',
data: JSON.stringify(deleteItem),
contentType: 'application/vnd.api+json',
success: function success(data) {
messages.clear()
messages.add(Drupal.t('Locations have been saved'), { type: 'status' })
button.attr('disabled',false)
delete changes.treeUuid
},
error: function error(xmlhttp) {
var e = new Drupal.AjaxError(xmlhttp)
messages.clear()
messages.add(e.message, { type: 'error' })
button.attr('disabled',false)
}
}));
}
else {
var patch = {
'data': [
{
'type': 'asset--' + item.type,
'id': item.destination,
}
]
}
requests.push($.ajax({
type: 'POST',
cache: false,
headers: {
'X-CSRF-Token': token,
},
url: '/api/asset/' + item.type + '/' + item.uuid + '/relationships/parent',
data: JSON.stringify(patch),
contentType: 'application/vnd.api+json',
success: function success(data) {
if (item.original_parent !== settings.asset_parent) {
var deleteItem = {
'data': [
{
'type': 'asset--' + item.original_type,
'id': item.original_parent,
}
]
}
requests.push($.ajax({
type: 'DELETE',
cache: false,
headers: {
'X-CSRF-Token': token,
},
url: '/api/asset/' + item.original_type + '/' + item.uuid + '/relationships/parent',
data: JSON.stringify(deleteItem),
contentType: 'application/vnd.api+json',
success: function success(data) {
messages.clear()
messages.add(Drupal.t('Locations have been saved'), { type: 'status' })
button.attr('disabled',false)
delete changes.treeUuid
},
error: function error(xmlhttp) {
var e = new Drupal.AjaxError(xmlhttp)
messages.clear()
messages.add(e.message, { type: 'error' })
button.attr('disabled',false)
}
}))
}
else {
messages.clear()
messages.add(Drupal.t('Locations have been saved'), { type: 'status' })
button.attr('disabled',false)
}
},
error: function error(xmlhttp) {
var e = new Drupal.AjaxError(xmlhttp)
messages.clear()
messages.add(e.message, { type: 'error' })
button.attr('disabled',false)
}
}))
}
}
// Refresh the page once all requests are completed.
$.when.apply($, requests).done(function () {
location.reload();
})
$('input[name=changes]').val(JSON.stringify(changes))
})
tree.on('node.click', function(event, node) {

View File

@ -3,6 +3,7 @@
namespace Drupal\farm_ui_location\Form;
use Drupal\asset\Entity\AssetInterface;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
@ -116,6 +117,11 @@ class LocationHierarchyForm extends FormBase {
],
];
// Create a hidden field to store hierarchy changes recorded client-side.
$form['changes'] = [
'#type' => 'hidden',
];
// Add buttons for toggling drag and drop, saving, and resetting.
$form['actions'] = ['#type' => 'actions'];
$form['actions']['toggle'] = [
@ -150,16 +156,14 @@ class LocationHierarchyForm extends FormBase {
$form['#attached']['library'][] = 'farm_ui_location/locations-drag-and-drop';
$tree = [
[
'uuid' => !empty($asset) ? $asset->uuid() : '',
'asset_id' => !empty($asset) ? $asset->id() : '',
'text' => !empty($asset) ? $asset->label() : $this->t('All locations'),
'children' => !empty($asset) ? $this->buildTree($asset) : $this->buildTree(),
'type' => !empty($asset) ? $asset->bundle() : '',
'url' => !empty($asset) ? $asset->toUrl('canonical', ['absolute' => TRUE])->toString() : '/locations',
],
];
$form['#attached']['drupalSettings']['asset_tree'] = $tree;
$form['#attached']['drupalSettings']['asset_parent'] = !empty($asset) ? $asset->uuid() : '';
$form['#attached']['drupalSettings']['asset_parent_type'] = !empty($asset) ? $asset->bundle() : '';
$form['#attached']['drupalSettings']['asset_parent'] = !empty($asset) ? $asset->id() : '';
// Return the form.
return $form;
@ -184,14 +188,12 @@ class LocationHierarchyForm extends FormBase {
if ($locations) {
foreach ($locations as $location) {
$element = [
'uuid' => $location->uuid(),
'asset_id' => $location->id(),
'text' => $location->label(),
'children' => $this->buildTree($location),
'type' => $location->bundle(),
'url' => $location->toUrl('canonical', ['absolute' => TRUE])->toString(),
];
$element['original_parent'] = $asset ? $asset->uuid() : '';
$element['original_type'] = $asset ? $asset->bundle() : '';
$element['original_parent'] = $asset ? $asset->id() : '';
$tree[] = $element;
}
}
@ -238,4 +240,77 @@ class LocationHierarchyForm extends FormBase {
return $assets;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Only process the form if the "Save" button was clicked.
if ($form_state->getTriggeringElement()['#id'] != 'edit-save') {
return;
}
// Load hierarchy changes. If there are none, do nothing.
$changes = Json::decode($form_state->getValue('changes'));
if (empty($changes)) {
$this->messenger()->addStatus($this->t('No changes were made.'));
return;
}
// Get asset storage.
$storage = $this->entityTypeManager->getStorage('asset');
// Maintain a list of assets that need to be saved.
$save_assets = [];
// Iterate through the changes.
foreach ($changes as $change) {
// Load the asset.
$asset = $storage->load($change['asset_id']);
// Remove the original parent.
if (!empty($asset->get('parent'))) {
/** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $parent */
foreach ($asset->get('parent') as $delta => $parent) {
$parent_id = $parent->getValue()['target_id'];
if ($change['original_parent'] == $parent_id) {
unset($asset->get('parent')[$delta]);
if (!array_key_exists($asset->id(), $save_assets)) {
$save_assets[$asset->id()] = $asset;
}
}
}
}
// Add the new parent, if applicable.
if (!empty($change['new_parent'])) {
$asset->get('parent')[] = ['target_id' => $change['new_parent']];
if (!array_key_exists($asset->id(), $save_assets)) {
$save_assets[$asset->id()] = $asset;
}
}
}
// Save assets with a revision message.
/** @var \Drupal\asset\Entity\AssetInterface[] $save_assets */
foreach ($save_assets as $asset) {
$message = $this->t('Parents removed via the Locations drag and drop editor.');
$parent_names = [];
foreach ($asset->get('parent') as $parent) {
$parent_names[] = $storage->load($parent->getValue()['target_id'])->label();
}
if (!empty($parent_names)) {
$message = $this->t('Parents changed to %parents via the Locations drag and drop editor.', ['%parents' => implode(', ', $parent_names)]);
}
$asset->setNewRevision(TRUE);
$asset->setRevisionLogMessage($message);
$asset->save();
}
// Show a summary of the results.
$message = $this->formatPlural(count($save_assets), 'Updated the parent hierarchy of %count asset.', 'Updated the parent hierarchy of %count assets.', ['%count' => count($save_assets)]);
$this->messenger()->addStatus($message);
}
}