Issue #2764931 by tedbow, tim.plunkett, nod_, drpal, droplet, dawehner, Wim Leers, phenaproxima: Contextual links don't work with 'use-ajax' links
parent
fd8d98399a
commit
18f322a212
|
@ -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 () {
|
||||
|
@ -268,6 +249,39 @@
|
|||
return Drupal.ajax.instances.filter(instance => instance && instance.element !== false && !document.body.contains(instance.element));
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -1340,4 +1354,5 @@
|
|||
}
|
||||
},
|
||||
};
|
||||
|
||||
}(jQuery, window, Drupal, drupalSettings));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -20,6 +20,7 @@ drupal.contextual-links:
|
|||
dependencies:
|
||||
- core/jquery
|
||||
- core/drupal
|
||||
- core/drupal.ajax
|
||||
- core/drupalSettings
|
||||
- core/backbone
|
||||
- core/modernizr
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
|
@ -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'
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
|
|
|
@ -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']);
|
||||
|
|
|
@ -148,6 +148,27 @@
|
|||
setEditModeState(!isInEditMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -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';
|
||||
|
@ -167,12 +194,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
|
||||
|
@ -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' };
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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' };
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue