summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorwebchick <drupal@webchick.net>2017-10-16 18:15:27 -0400
committerwebchick <drupal@webchick.net>2017-10-16 18:15:27 -0400
commit18f322a212d777e4f2c364fd8cc7ecfe442cf24c (patch)
treec4e632f0fd8efd7d95159e586e2f56ff2dc64309
parentfd8d98399a69ba243679fc8ecc1d8bf221c18530 (diff)
downloaddrupal-18f322a212d777e4f2c364fd8cc7ecfe442cf24c.tar.gz
drupal-18f322a212d777e4f2c364fd8cc7ecfe442cf24c.zip
Issue #2764931 by tedbow, tim.plunkett, nod_, drpal, droplet, dawehner, Wim Leers, phenaproxima: Contextual links don't work with 'use-ajax' links
-rw-r--r--core/misc/ajax.es6.js55
-rw-r--r--core/misc/ajax.js40
-rw-r--r--core/modules/contextual/contextual.libraries.yml1
-rw-r--r--core/modules/contextual/js/contextual.es6.js15
-rw-r--r--core/modules/contextual/js/contextual.js4
-rw-r--r--core/modules/contextual/tests/modules/contextual_test/contextual_test.links.contextual.yml8
-rw-r--r--core/modules/contextual/tests/modules/contextual_test/contextual_test.module20
-rw-r--r--core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php11
-rw-r--r--core/modules/settings_tray/js/settings_tray.es6.js48
-rw-r--r--core/modules/settings_tray/js/settings_tray.js26
10 files changed, 158 insertions, 70 deletions
diff --git a/core/misc/ajax.es6.js b/core/misc/ajax.es6.js
index 2e6fa91d77cf..7d7484e3759e 100644
--- a/core/misc/ajax.es6.js
+++ b/core/misc/ajax.es6.js
@@ -46,26 +46,7 @@
}
}
- // Bind Ajax behaviors to all items showing the class.
- $('.use-ajax').once('ajax').each(function () {
- const element_settings = {};
- // Clicked links look better with the throbber than the progress bar.
- element_settings.progress = { type: 'throbber' };
-
- // For anchor tags, these will go to the target of the anchor rather
- // than the usual location.
- const href = $(this).attr('href');
- if (href) {
- element_settings.url = href;
- element_settings.event = 'click';
- }
- element_settings.dialogType = $(this).data('dialog-type');
- element_settings.dialogRenderer = $(this).data('dialog-renderer');
- element_settings.dialog = $(this).data('dialog-options');
- element_settings.base = $(this).attr('id');
- element_settings.element = this;
- Drupal.ajax(element_settings);
- });
+ Drupal.ajax.bindAjaxLinks(document.body);
// This class means to submit the form to the action using Ajax.
$('.use-ajax-submit').once('ajax').each(function () {
@@ -269,6 +250,39 @@
};
/**
+ * Bind Ajax functionality to links that use the 'use-ajax' class.
+ *
+ * @param {HTMLElement} element
+ * Element to enable Ajax functionality for.
+ */
+ Drupal.ajax.bindAjaxLinks = (element) => {
+ // Bind Ajax behaviors to all items showing the class.
+ $(element).find('.use-ajax').once('ajax').each((i, ajaxLink) => {
+ const $linkElement = $(ajaxLink);
+
+ const elementSettings = {
+ // Clicked links look better with the throbber than the progress bar.
+ progress: { type: 'throbber' },
+ dialogType: $linkElement.data('dialog-type'),
+ dialog: $linkElement.data('dialog-options'),
+ dialogRenderer: $linkElement.data('dialog-renderer'),
+ base: $linkElement.attr('id'),
+ element: ajaxLink,
+ };
+ const href = $linkElement.attr('href');
+ /**
+ * For anchor tags, these will go to the target of the anchor rather
+ * than the usual location.
+ */
+ if (href) {
+ elementSettings.url = href;
+ elementSettings.event = 'click';
+ }
+ Drupal.ajax(elementSettings);
+ });
+ };
+
+ /**
* Settings for an Ajax object.
*
* @typedef {object} Drupal.Ajax~element_settings
@@ -1340,4 +1354,5 @@
}
},
};
+
}(jQuery, window, Drupal, drupalSettings));
diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index 955cf12d2211..a899f4a9b999 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -27,23 +27,7 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
}
}
- $('.use-ajax').once('ajax').each(function () {
- var element_settings = {};
-
- element_settings.progress = { type: 'throbber' };
-
- var href = $(this).attr('href');
- if (href) {
- element_settings.url = href;
- element_settings.event = 'click';
- }
- element_settings.dialogType = $(this).data('dialog-type');
- element_settings.dialogRenderer = $(this).data('dialog-renderer');
- element_settings.dialog = $(this).data('dialog-options');
- element_settings.base = $(this).attr('id');
- element_settings.element = this;
- Drupal.ajax(element_settings);
- });
+ Drupal.ajax.bindAjaxLinks(document.body);
$('.use-ajax-submit').once('ajax').each(function () {
var element_settings = {};
@@ -137,6 +121,28 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
});
};
+ Drupal.ajax.bindAjaxLinks = function (element) {
+ $(element).find('.use-ajax').once('ajax').each(function (i, ajaxLink) {
+ var $linkElement = $(ajaxLink);
+
+ var elementSettings = {
+ progress: { type: 'throbber' },
+ dialogType: $linkElement.data('dialog-type'),
+ dialog: $linkElement.data('dialog-options'),
+ dialogRenderer: $linkElement.data('dialog-renderer'),
+ base: $linkElement.attr('id'),
+ element: ajaxLink
+ };
+ var href = $linkElement.attr('href');
+
+ if (href) {
+ elementSettings.url = href;
+ elementSettings.event = 'click';
+ }
+ Drupal.ajax(elementSettings);
+ });
+ };
+
Drupal.Ajax = function (base, element, element_settings) {
var defaults = {
event: element ? 'mousedown' : null,
diff --git a/core/modules/contextual/contextual.libraries.yml b/core/modules/contextual/contextual.libraries.yml
index 51281afb5279..ec9068037b1c 100644
--- a/core/modules/contextual/contextual.libraries.yml
+++ b/core/modules/contextual/contextual.libraries.yml
@@ -20,6 +20,7 @@ drupal.contextual-links:
dependencies:
- core/jquery
- core/drupal
+ - core/drupal.ajax
- core/drupalSettings
- core/backbone
- core/modernizr
diff --git a/core/modules/contextual/js/contextual.es6.js b/core/modules/contextual/js/contextual.es6.js
index 8c2b1aed4017..286e1ef9566f 100644
--- a/core/modules/contextual/js/contextual.es6.js
+++ b/core/modules/contextual/js/contextual.es6.js
@@ -249,4 +249,19 @@
Drupal.theme.contextualTrigger = function () {
return '<button class="trigger visually-hidden focusable" type="button"></button>';
};
+
+ /**
+ * Bind Ajax contextual links when added.
+ *
+ * @param {jQuery.Event} event
+ * The `drupalContextualLinkAdded` event.
+ * @param {object} data
+ * An object containing the data relevant to the event.
+ *
+ * @listens event:drupalContextualLinkAdded
+ */
+ $(document).on('drupalContextualLinkAdded', (event, data) => {
+ Drupal.ajax.bindAjaxLinks(data.$el[0]);
+ });
+
}(jQuery, Drupal, drupalSettings, _, Backbone, window.JSON, window.sessionStorage));
diff --git a/core/modules/contextual/js/contextual.js b/core/modules/contextual/js/contextual.js
index a23ac66ab3c7..ed210d070d57 100644
--- a/core/modules/contextual/js/contextual.js
+++ b/core/modules/contextual/js/contextual.js
@@ -144,4 +144,8 @@
Drupal.theme.contextualTrigger = function () {
return '<button class="trigger visually-hidden focusable" type="button"></button>';
};
+
+ $(document).on('drupalContextualLinkAdded', function (event, data) {
+ Drupal.ajax.bindAjaxLinks(data.$el[0]);
+ });
})(jQuery, Drupal, drupalSettings, _, Backbone, window.JSON, window.sessionStorage); \ No newline at end of file
diff --git a/core/modules/contextual/tests/modules/contextual_test/contextual_test.links.contextual.yml b/core/modules/contextual/tests/modules/contextual_test/contextual_test.links.contextual.yml
index 35e03b7333da..1738756a12e4 100644
--- a/core/modules/contextual/tests/modules/contextual_test/contextual_test.links.contextual.yml
+++ b/core/modules/contextual/tests/modules/contextual_test/contextual_test.links.contextual.yml
@@ -2,3 +2,11 @@ contextual_test:
title: 'Test Link'
route_name: 'contextual_test'
group: 'contextual_test'
+contextual_test_ajax:
+ title: 'Test Link with Ajax'
+ route_name: 'contextual_test'
+ group: 'contextual_test'
+ options:
+ attributes:
+ class: ['use-ajax']
+ data-dialog-type: 'modal'
diff --git a/core/modules/contextual/tests/modules/contextual_test/contextual_test.module b/core/modules/contextual/tests/modules/contextual_test/contextual_test.module
index b8f2e60f5109..d57255cf104a 100644
--- a/core/modules/contextual/tests/modules/contextual_test/contextual_test.module
+++ b/core/modules/contextual/tests/modules/contextual_test/contextual_test.module
@@ -15,3 +15,23 @@ function contextual_test_block_view_alter(array &$build, BlockPluginInterface $b
'route_parameters' => [],
];
}
+
+/**
+ * Implements hook_contextual_links_view_alter().
+ *
+ * @todo Apparently this too late to attach the library?
+ * It won't work without contextual_test_page_attachments_alter()
+ * Is that a problem? Should the contextual module itself do the attaching?
+ */
+function contextual_test_contextual_links_view_alter(&$element, $items) {
+ if (isset($element['#links']['contextual-test-ajax'])) {
+ $element['#attached']['library'][] = 'core/drupal.dialog.ajax';
+ }
+}
+
+/**
+ * Implements hook_page_attachments_alter().
+ */
+function contextual_test_page_attachments_alter(array &$attachments) {
+ $attachments['#attached']['library'][] = 'core/drupal.dialog.ajax';
+}
diff --git a/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php b/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
index a24d2bae5978..de836924119f 100644
--- a/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
+++ b/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
@@ -69,6 +69,17 @@ class ContextualLinksTest extends JavascriptTestBase {
$this->clickContextualLink('#block-branding', 'Test Link');
$this->assertSession()->pageTextContains('Everything is contextual!');
+ // Test click a contextual link that uses ajax.
+ $this->drupalGet('user');
+ $this->assertSession()->assertWaitOnAjaxRequest();
+ $current_page_string = 'NOT_RELOADED_IF_ON_PAGE';
+ $this->getSession()->executeScript('document.body.appendChild(document.createTextNode("' . $current_page_string . '"));');
+ $this->clickContextualLink('#block-branding', 'Test Link with Ajax');
+ $this->assertNotEmpty($this->assertSession()->waitForElementVisible('css', '#drupal-modal'));
+ $this->assertSession()->elementContains('css', '#drupal-modal', 'Everything is contextual!');
+ // Check to make sure that page was not reloaded.
+ $this->assertSession()->pageTextContains($current_page_string);
+
// Test clicking contextual link with toolbar.
$this->container->get('module_installer')->install(['toolbar']);
$this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), ['access toolbar']);
diff --git a/core/modules/settings_tray/js/settings_tray.es6.js b/core/modules/settings_tray/js/settings_tray.es6.js
index 7ce08dabb866..67a6af04b5bc 100644
--- a/core/modules/settings_tray/js/settings_tray.es6.js
+++ b/core/modules/settings_tray/js/settings_tray.es6.js
@@ -149,6 +149,27 @@
}
/**
+ * Prepares Ajax links to work with off-canvas and Settings Tray module.
+ */
+ function prepareAjaxLinks() {
+ // Find all Ajax instances that use the 'off_canvas' renderer.
+ Drupal.ajax.instances
+ // If there is an element and the renderer is 'off_canvas' then we want
+ // to add our changes.
+ .filter(instance => instance && $(instance.element).attr('data-dialog-renderer') === 'off_canvas')
+ // Loop through all Ajax instances that use the 'off_canvas' renderer to
+ // set active editable ID.
+ .forEach((instance) => {
+ // Check to make sure existing dialogOptions aren't overridden.
+ if (!('dialogOptions' in instance.options.data)) {
+ instance.options.data.dialogOptions = {};
+ }
+ instance.options.data.dialogOptions.settingsTrayActiveEditableId = $(instance.element).parents('.settings-tray-editable').attr('id');
+ instance.progress = { type: 'fullscreen' };
+ });
+ }
+
+ /**
* Reacts to contextual links being added.
*
* @param {jQuery.Event} event
@@ -159,6 +180,12 @@
* @listens event:drupalContextualLinkAdded
*/
$(document).on('drupalContextualLinkAdded', (event, data) => {
+ /**
+ * When contextual links are add we need to set extra properties on the
+ * instances in Drupal.ajax.instances for them to work with Edit Mode.
+ */
+ prepareAjaxLinks();
+
// When the first contextual link is added to the page set Edit Mode.
$('body').once('settings_tray.edit_mode_init').each(() => {
const editMode = localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false';
@@ -168,12 +195,6 @@
});
/**
- * Bind Ajax behaviors to all items showing the class.
- * @todo Fix contextual links to work with use-ajax links in
- * https://www.drupal.org/node/2764931.
- */
- Drupal.attachBehaviors(data.$el[0]);
- /**
* Bind a listener to all 'Quick edit' links for blocks. Click "Edit" button
* in toolbar to force Contextual Edit which starts Settings Tray edit
* mode also.
@@ -211,21 +232,6 @@
Drupal.behaviors.toggleEditMode = {
attach() {
$(toggleEditSelector).once('settingstray').on('click.settingstray', toggleEditMode);
- // Find all Ajax instances that use the 'off_canvas' renderer.
- Drupal.ajax.instances
- // If there is an element and the renderer is 'off_canvas' then we want
- // to add our changes.
- .filter(instance => instance && $(instance.element).attr('data-dialog-renderer') === 'off_canvas')
- // Loop through all Ajax instances that use the 'off_canvas' renderer to
- // set active editable ID.
- .forEach((instance) => {
- // Check to make sure existing dialogOptions aren't overridden.
- if (!('dialogOptions' in instance.options.data)) {
- instance.options.data.dialogOptions = {};
- }
- instance.options.data.dialogOptions.settingsTrayActiveEditableId = $(instance.element).parents('.settings-tray-editable').attr('id');
- instance.progress = { type: 'fullscreen' };
- });
},
};
diff --git a/core/modules/settings_tray/js/settings_tray.js b/core/modules/settings_tray/js/settings_tray.js
index 88cbb0eb6e4a..78c5b603826a 100644
--- a/core/modules/settings_tray/js/settings_tray.js
+++ b/core/modules/settings_tray/js/settings_tray.js
@@ -93,7 +93,21 @@
setEditModeState(!isInEditMode());
}
+ function prepareAjaxLinks() {
+ Drupal.ajax.instances.filter(function (instance) {
+ return instance && $(instance.element).attr('data-dialog-renderer') === 'off_canvas';
+ }).forEach(function (instance) {
+ if (!('dialogOptions' in instance.options.data)) {
+ instance.options.data.dialogOptions = {};
+ }
+ instance.options.data.dialogOptions.settingsTrayActiveEditableId = $(instance.element).parents('.settings-tray-editable').attr('id');
+ instance.progress = { type: 'fullscreen' };
+ });
+ }
+
$(document).on('drupalContextualLinkAdded', function (event, data) {
+ prepareAjaxLinks();
+
$('body').once('settings_tray.edit_mode_init').each(function () {
var editMode = localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false';
if (editMode) {
@@ -101,8 +115,6 @@
}
});
- Drupal.attachBehaviors(data.$el[0]);
-
data.$el.find(blockConfigureSelector).on('click.settingstray', function () {
if (!isInEditMode()) {
$(toggleEditSelector).trigger('click').trigger('click.settings_tray');
@@ -122,16 +134,6 @@
Drupal.behaviors.toggleEditMode = {
attach: function attach() {
$(toggleEditSelector).once('settingstray').on('click.settingstray', toggleEditMode);
-
- Drupal.ajax.instances.filter(function (instance) {
- return instance && $(instance.element).attr('data-dialog-renderer') === 'off_canvas';
- }).forEach(function (instance) {
- if (!('dialogOptions' in instance.options.data)) {
- instance.options.data.dialogOptions = {};
- }
- instance.options.data.dialogOptions.settingsTrayActiveEditableId = $(instance.element).parents('.settings-tray-editable').attr('id');
- instance.progress = { type: 'fullscreen' };
- });
}
};