Skip to content
Snippets Groups Projects
Commit 5aa230e0 authored by Mingsong's avatar Mingsong
Browse files

Issue #3205538: Add (optional) confirmation dialog after drag&drop

parent f30124e2
No related branches found
No related tags found
No related merge requests found
...@@ -16,3 +16,6 @@ hierarchy_manager.hm_display_profile.*: ...@@ -16,3 +16,6 @@ hierarchy_manager.hm_display_profile.*:
config: config:
type: text type: text
label: 'Configuration' label: 'Configuration'
confirm:
type: boolean
label: 'Confirm'
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
const optionsJson = treeContainer.attr("options"); const optionsJson = treeContainer.attr("options");
const dataURL = treeContainer.attr('data-source') + '&parent=0'; const dataURL = treeContainer.attr('data-source') + '&parent=0';
const updateURL = treeContainer.attr('url-update'); const updateURL = treeContainer.attr('url-update');
const confirm = treeContainer.attr("confirm");
let reload = true; let reload = true;
let rollback = false; let rollback = false;
let themes = { let themes = {
...@@ -103,61 +104,80 @@ ...@@ -103,61 +104,80 @@
const drupalMessages = new Drupal.Message(); const drupalMessages = new Drupal.Message();
if (!rollback) { if (!rollback) {
// Update the data on server side. let parentText = Drupal.t('root');
$.post(updateURL, { if (parent !== 0) {
keys: [movedNode.id], parentText = $("<div/>").html(thisTree.get_node(parent).text);
target: data.position, parentText.find("span").remove();
parent: parent, parentText = parentText.text();
old_parent: old_parent, }
old_position: data.old_position // Function to move the tree item.
}) function moveTreeItem() {
.done(function(response) { // Update the data on server side.
if (response.result !== "success") { $.post(updateURL, {
alert("Server error:" + response.result); keys: [movedNode.id],
rollback = true; target: data.position,
thisTree.move_node(movedNode, data.old_parent, data.old_position); parent: parent,
} old_parent: old_parent,
else { old_position: data.old_position
if (parent === 0) { })
var parentText = Drupal.t('root'); .done(function(response) {
} if (response.result !== "success") {
else { alert("Server error:" + response.result);
var parentText = parent_node.text; rollback = true;
} thisTree.move_node(movedNode, data.old_parent, data.old_position);
if (parent_node.data && !parent_node.data.draggable) {
// The parent node is not draggable.
// We have to update all duplicated nodes
// by refreshing the whole tree.
thisTree.refresh();
} }
else { else {
// Update the nodes changed in the server side. if (parent_node.data && !parent_node.data.draggable) {
if (response.updated_nodes) { // The parent node is not draggable.
let update_nodes = response.updated_nodes; // We have to update all duplicated nodes
for (const id in update_nodes) { // by refreshing the whole tree.
let node = thisTree.get_node(id); thisTree.refresh();
if (node) { }
node.data.weight = update_nodes[id]; else {
// Update the nodes changed in the server side.
if (response.updated_nodes) {
let update_nodes = response.updated_nodes;
for (const id in update_nodes) {
let node = thisTree.get_node(id);
if (node) {
node.data.weight = update_nodes[id];
}
} }
//Refresh the tree without reloading data from server.
thisTree.sort(parent_node, true);
thisTree.redraw(true);
} }
//Refresh the tree without reloading data from server.
thisTree.sort(parent_node, true);
thisTree.redraw(true);
} }
let message = Drupal.t('@node is moved to position @position under @parent', {'@node': data.node.text, '@parent': parentText, '@position': data.position + 1});
// Inform user the movement.
drupalMessages.clear();
drupalMessages.add(message);
} }
})
let message = Drupal.t('@node is moved to position @position under @parent', {'@node': data.node.text, '@parent': parentText, '@position': data.position + 1}); .fail(function() {
// Inform user the movement.
drupalMessages.clear(); drupalMessages.clear();
drupalMessages.add(message); drupalMessages.add(Drupal.t("Can't connect to the server."), {type: 'error'});
} rollback = true;
}) thisTree.move_node(movedNode, data.old_parent, data.old_position);
.fail(function() { });
drupalMessages.clear(); }
drupalMessages.add(Drupal.t("Can't connect to the server."), {type: 'error'});
rollback = true; // Check if confirmation dialog is enabled.
thisTree.move_node(movedNode, data.old_parent, data.old_position); if (typeof confirm !== 'undefined' && confirm !== false) {
}); // Confirmation dialog enabled.
let modalTitle = Drupal.t('Confirm move?');
let modalMessage = Drupal.t('Move <em class="placeholder">@node</em> to position @position under <em class="placeholder">@parent</em>?', { '@node': data.node.text, '@parent': parentText, '@position': data.position + 1 });
modalConfirmation(modalTitle, modalMessage, moveTreeItem, function () {
// Callback when confirmation is denied.
rollback = true;
thisTree.move_node(movedNode, data.old_parent, data.old_position);
});
} else {
// Confirmation dialog disabled.
moveTreeItem()
}
} }
else { else {
rollback = false; rollback = false;
...@@ -184,4 +204,51 @@ ...@@ -184,4 +204,51 @@
}); });
} }
}; };
/**
* Generic modal helper function.
*
* @param {string} title - The title for the confirm dialog.
* @param {string} message - The main message for the confirm dialog.
* @param {function} accept - Callback fired when the user answers positive.
* @param {function} deny - Callback fired when the user answers negative.
* @returns {Object} - A jQuery dialog object.
*/
function modalConfirmation(title, message, accept, deny) {
let proceed = false;
let modalConfirmationForm = $('<div></div>').appendTo('body')
.html(message)
.dialog({
modal: true,
title: title,
autoOpen: false,
width: 400,
resizable: false,
sticky: true,
closeOnEscape: true,
dialogClass: "hm-confirm",
buttons: [
{
class: 'button button--primary',
text: Drupal.t('Yes'),
click: function () {
proceed = true;
$(this).dialog('close');
}
},
{
class: 'button',
text: Drupal.t('No'),
click: function () {
$(this).dialog('close');
}
}
],
close: function () {
proceed ? accept() : deny();
}
});
return modalConfirmationForm.dialog('open');
}
})(jQuery, Drupal); })(jQuery, Drupal);
...@@ -34,6 +34,7 @@ use Drupal\Core\Config\Entity\ConfigEntityBase; ...@@ -34,6 +34,7 @@ use Drupal\Core\Config\Entity\ConfigEntityBase;
* "label", * "label",
* "plugin", * "plugin",
* "config", * "config",
* "confirm",
* }, * },
* links = { * links = {
* "canonical" = "/admin/structure/hm_display_profile/{hm_display_profile}", * "canonical" = "/admin/structure/hm_display_profile/{hm_display_profile}",
...@@ -73,4 +74,11 @@ class HmDisplayProfile extends ConfigEntityBase implements HmDisplayProfileInter ...@@ -73,4 +74,11 @@ class HmDisplayProfile extends ConfigEntityBase implements HmDisplayProfileInter
* @var string * @var string
*/ */
protected $config; protected $config;
/**
* The confirmation option.
*
* @var bool
*/
protected $confirm = FALSE;
} }
...@@ -114,6 +114,13 @@ class HmDisplayProfileForm extends EntityForm { ...@@ -114,6 +114,13 @@ class HmDisplayProfileForm extends EntityForm {
]; ];
} }
$form['confirm'] = [
'#type' => 'checkbox',
'#title' => $this->t('Confirm drag&drop'),
'#default_value' => $hm_display_profile->get("confirm"),
'#description' => $this->t('Displays a dialog when changing the hierarchy.'),
];
return $form; return $form;
} }
...@@ -132,6 +139,9 @@ class HmDisplayProfileForm extends EntityForm { ...@@ -132,6 +139,9 @@ class HmDisplayProfileForm extends EntityForm {
$hm_display_profile->set('config', $input['config']); $hm_display_profile->set('config', $input['config']);
} }
if (isset($input['confirm'])) {
$hm_display_profile->set('confirm', $input['confirm']);
}
$status = $hm_display_profile->save(); $status = $hm_display_profile->save();
......
...@@ -98,7 +98,8 @@ class HmMenuForm extends MenuForm { ...@@ -98,7 +98,8 @@ class HmMenuForm extends MenuForm {
$source_url = Url::fromRoute('hierarchy_manager.menu.tree.json', ['mid' => $mid], ['query' => ['token' => $token, 'destination' => $destination]])->toString(); $source_url = Url::fromRoute('hierarchy_manager.menu.tree.json', ['mid' => $mid], ['query' => ['token' => $token, 'destination' => $destination]])->toString();
$update_url = Url::fromRoute('hierarchy_manager.menu.tree.update', ['mid' => $mid], ['query' => ['token' => $token]])->toString(); $update_url = Url::fromRoute('hierarchy_manager.menu.tree.update', ['mid' => $mid], ['query' => ['token' => $token]])->toString();
$config = $display_profile->get("config"); $config = $display_profile->get("config");
return $display_plugin_instance->getForm($source_url, $update_url, $form, $form_state, $config); $confirm = $display_profile->get("confirm");
return $display_plugin_instance->getForm($source_url, $update_url, $form, $form_state, $config, $confirm);
} }
} }
......
...@@ -64,7 +64,8 @@ class HmOverviewTerms extends OverviewTerms { ...@@ -64,7 +64,8 @@ class HmOverviewTerms extends OverviewTerms {
$source_url = Url::fromRoute('hierarchy_manager.taxonomy.tree.json', ['vid' => $vid], ['query' => ['token' => $token, 'destination' => $destination]])->toString(); $source_url = Url::fromRoute('hierarchy_manager.taxonomy.tree.json', ['vid' => $vid], ['query' => ['token' => $token, 'destination' => $destination]])->toString();
$update_url = Url::fromRoute('hierarchy_manager.taxonomy.tree.update', ['vid' => $vid], ['query' => ['token' => $token]])->toString(); $update_url = Url::fromRoute('hierarchy_manager.taxonomy.tree.update', ['vid' => $vid], ['query' => ['token' => $token]])->toString();
$config = $display_profile->get("config"); $config = $display_profile->get("config");
return $instance->getForm($source_url, $update_url, $form, $form_state, $config); $confirm = $display_profile->get('confirm');
return $instance->getForm($source_url, $update_url, $form, $form_state, $config, $confirm);
} }
} }
} }
......
...@@ -23,7 +23,7 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte ...@@ -23,7 +23,7 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte
/* /*
* Build the tree form. * Build the tree form.
*/ */
public function getForm(string $url_source, string $url_update, array &$form = [], FormStateInterface &$form_state = NULL, $options = NULL) { public function getForm(string $url_source, string $url_update, array &$form = [], FormStateInterface &$form_state = NULL, $options = NULL, $confirm = FALSE) {
if (!empty($url_source)) { if (!empty($url_source)) {
if (!empty(($form_state))) { if (!empty(($form_state))) {
$parent_formObj = $form_state->getFormObject(); $parent_formObj = $form_state->getFormObject();
...@@ -70,6 +70,7 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte ...@@ -70,6 +70,7 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte
'id' => isset($parent_id) ? 'hm-jstree-' . $parent_id : 'hm-jstree', 'id' => isset($parent_id) ? 'hm-jstree-' . $parent_id : 'hm-jstree',
'parent-id' => isset($parent_id) ? $parent_id : '', 'parent-id' => isset($parent_id) ? $parent_id : '',
'options' => $options, 'options' => $options,
'confirm' => $confirm,
'data-source' => $url_source, 'data-source' => $url_source,
'url-update' => $url_update, 'url-update' => $url_update,
], ],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment