Skip to content
Snippets Groups Projects
Commit 2c6f28be authored by Angie Byron's avatar Angie Byron
Browse files

Issue #2785589 by tedbow, nod_, droplet, drpal, alexpott, Wim Leers, xjm: Fix...

Issue #2785589 by tedbow, nod_, droplet, drpal, alexpott, Wim Leers, xjm: Fix js and jsdoc of outside-in module
parent 8d0d69f0
Branches
Tags
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
...@@ -7,32 +7,10 @@ ...@@ -7,32 +7,10 @@
'use strict'; 'use strict';
$('.outside-in-editable') var blockConfigureSelector = '[data-dialog-renderer="offcanvas"]';
// Bind an event listener to the .outside-in-editable div var toggleEditSelector = '[data-drupal-outsidein="toggle"]';
// This listen for click events and stops default actions of those elements. var itemsToToggleSelector = '#main-canvas, #toolbar-bar, [data-drupal-outsidein="editable"] a, [data-drupal-outsidein="editable"] button';
.on('click', '.js-outside-in-edit-mode', function (e) { var contextualItemsSelector = '[data-contextual-id] a, [data-contextual-id] button';
if (localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false') {
e.preventDefault();
}
})
// Bind an event listener to the .outside-in-editable div
// When a click occurs try and find the outside-in edit link
// and click it.
.not('div.contextual a, div.contextual button')
.on('click', function (e) {
if ($(e.target.offsetParent).hasClass('contextual')) {
return;
}
if (!localStorage.getItem('Drupal.contextualToolbar.isViewing')) {
return;
}
var editLink = $(e.target).find('a[data-dialog-renderer="offcanvas"]')[0];
if (!editLink) {
var closest = $(e.target).closest('.outside-in-editable');
editLink = closest.find('li a[data-dialog-renderer="offcanvas"]')[0];
}
editLink.click();
});
/** /**
* Reacts to contextual links being added. * Reacts to contextual links being added.
...@@ -53,9 +31,10 @@ ...@@ -53,9 +31,10 @@
// Bind a listener to all 'Quick edit' links for blocks // Bind a listener to all 'Quick edit' links for blocks
// Click "Edit" button in toolbar to force Contextual Edit which starts // Click "Edit" button in toolbar to force Contextual Edit which starts
// Settings Tray edit mode also. // Settings Tray edit mode also.
data.$el.find('.outside-inblock-configure a').on('click', function () { data.$el.find(blockConfigureSelector)
if (!isActiveMode()) { .on('click.outsidein', function () {
$('div.contextual-toolbar-tab.toolbar-tab button').click(); if (!isInEditMode()) {
$(toggleEditSelector).trigger('click.outsidein');
} }
}); });
}); });
...@@ -63,35 +42,100 @@ ...@@ -63,35 +42,100 @@
/** /**
* Gets all items that should be toggled with class during edit mode. * Gets all items that should be toggled with class during edit mode.
* *
* @return {*} * @return {jQuery}
* Items that should be toggled. * Items that should be toggled.
*/ */
var getItemsToToggle = function () { function getItemsToToggle() {
return $('#main-canvas, #toolbar-bar, .outside-in-editable a, .outside-in-editable button') return $(itemsToToggleSelector).not(contextualItemsSelector);
.not('div.contextual a, div.contextual button'); }
};
var isActiveMode = function () { /**
* Helper to check the state of the outside-in mode.
*
* @todo don't use a class for this.
*
* @return {boolean}
* State of the outside-in edit mode.
*/
function isInEditMode() {
return $('#toolbar-bar').hasClass('js-outside-in-edit-mode'); return $('#toolbar-bar').hasClass('js-outside-in-edit-mode');
}; }
/**
* Helper to toggle Edit mode.
*/
function toggleEditMode() {
setEditModeState(!isInEditMode());
}
/**
* Prevent default click events except contextual links.
*
* In edit mode the default action of click events is suppressed.
*
* @param {jQuery.Event} event
* The click event.
*/
function preventClick(event) {
// Do not prevent contextual links.
if ($(event.target).closest('.contextual-links').length) {
return;
}
event.preventDefault();
}
var setToggleActiveMode = function setToggleActiveMode(forceActive) { /**
forceActive = forceActive || false; * Helper to switch edit mode state.
if (forceActive || !isActiveMode()) { *
$('#toolbar-bar .contextual-toolbar-tab button').text(Drupal.t('Editing')); * @param {boolean} editMode
* True enable edit mode, false disable edit mode.
*/
function setEditModeState(editMode) {
editMode = !!editMode;
var $editButton = $(toggleEditSelector);
var $editables;
// Turn on edit mode.
if (editMode) {
$editButton.text(Drupal.t('Editing'));
// Close the Manage tray if open when entering edit mode. // Close the Manage tray if open when entering edit mode.
if ($('#toolbar-item-administration-tray').hasClass('is-active')) { if ($('#toolbar-item-administration-tray').hasClass('is-active')) {
$('#toolbar-item-administration').click(); $('#toolbar-item-administration').trigger('click');
}
$editables = $('[data-drupal-outsidein="editable"]').once('outsidein');
if ($editables.length) {
// Use event capture to prevent clicks on links.
document.querySelector('#main-canvas').addEventListener('click', preventClick, true);
// When a click occurs try and find the outside-in edit link
// and click it.
$editables
.not(contextualItemsSelector)
.on('click.outsidein', function (e) {
// Contextual links are allowed to function in Edit mode.
if ($(e.target).closest('.contextual').length || !localStorage.getItem('Drupal.contextualToolbar.isViewing')) {
return;
}
$(e.currentTarget).find(blockConfigureSelector).trigger('click');
});
} }
getItemsToToggle().addClass('js-outside-in-edit-mode');
$('.edit-mode-inactive').addClass('visually-hidden');
} }
// Disable edit mode.
else { else {
$('#toolbar-bar .contextual-toolbar-tab button').text(Drupal.t('Edit')); $editables = $('[data-drupal-outsidein="editable"]').removeOnce('outsidein');
getItemsToToggle().removeClass('js-outside-in-edit-mode'); if ($editables.length) {
$('.edit-mode-inactive').removeClass('visually-hidden'); document.querySelector('#main-canvas').removeEventListener('click', preventClick, true);
$editables.off('.outsidein');
}
$editButton.text(Drupal.t('Edit'));
// Close/remove offcanvas.
$('.ui-dialog-offcanvas .ui-dialog-titlebar-close').trigger('click');
}
getItemsToToggle().toggleClass('js-outside-in-edit-mode', editMode);
$('.edit-mode-inactive').toggleClass('visually-hidden', editMode);
} }
};
/** /**
* Attaches contextual's edit toolbar tab behavior. * Attaches contextual's edit toolbar tab behavior.
...@@ -105,7 +149,7 @@ ...@@ -105,7 +149,7 @@
attach: function () { attach: function () {
var editMode = localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false'; var editMode = localStorage.getItem('Drupal.contextualToolbar.isViewing') === 'false';
if (editMode) { if (editMode) {
setToggleActiveMode(true); setEditModeState(true);
} }
} }
}; };
...@@ -118,11 +162,10 @@ ...@@ -118,11 +162,10 @@
* @prop {Drupal~behaviorAttach} attach * @prop {Drupal~behaviorAttach} attach
* Toggle the js-outside-edit-mode class. * Toggle the js-outside-edit-mode class.
*/ */
Drupal.behaviors.toggleActiveMode = { Drupal.behaviors.toggleEditMode = {
attach: function () { attach: function () {
$('.contextual-toolbar-tab.toolbar-tab button').once('toggle-edit-mode').on('click', function () {
setToggleActiveMode(); $(toggleEditSelector).once('outsidein').on('click.outsidein', toggleEditMode);
});
var search = Drupal.ajax.WRAPPER_FORMAT + '=drupal_dialog'; var search = Drupal.ajax.WRAPPER_FORMAT + '=drupal_dialog';
var replace = Drupal.ajax.WRAPPER_FORMAT + '=drupal_dialog_offcanvas'; var replace = Drupal.ajax.WRAPPER_FORMAT + '=drupal_dialog_offcanvas';
......
...@@ -18,6 +18,7 @@ drupal.outside_in: ...@@ -18,6 +18,7 @@ drupal.outside_in:
dependencies: dependencies:
- core/jquery - core/jquery
- core/drupal - core/drupal
- core/jquery.once
- core/drupal.ajax - core/drupal.ajax
drupal.off_canvas: drupal.off_canvas:
version: VERSION version: VERSION
......
...@@ -93,8 +93,9 @@ function outside_in_preprocess_block(&$variables) { ...@@ -93,8 +93,9 @@ function outside_in_preprocess_block(&$variables) {
// The main system block does not contain the block contextual links. // The main system block does not contain the block contextual links.
$variables['#cache']['contexts'][] = 'outside_in_is_applied'; $variables['#cache']['contexts'][] = 'outside_in_is_applied';
if ($variables['plugin_id'] !== 'system_main_block' && \Drupal::service('outside_in.manager')->isApplicable()) { if ($variables['plugin_id'] !== 'system_main_block' && \Drupal::service('outside_in.manager')->isApplicable()) {
// Add class to all blocks to allow Javascript to target. // Add class and attributes to all blocks to allow Javascript to target.
$variables['attributes']['class'][] = 'outside-in-editable'; $variables['attributes']['class'][] = 'outside-in-editable';
$variables['attributes']['data-drupal-outsidein'] = 'editable';
} }
} }
...@@ -108,6 +109,7 @@ function outside_in_toolbar_alter(&$items) { ...@@ -108,6 +109,7 @@ function outside_in_toolbar_alter(&$items) {
if (isset($items['contextual']['tab']) && \Drupal::service('outside_in.manager')->isApplicable()) { if (isset($items['contextual']['tab']) && \Drupal::service('outside_in.manager')->isApplicable()) {
$items['contextual']['#weight'] = -1000; $items['contextual']['#weight'] = -1000;
$items['contextual']['#attached']['library'][] = 'outside_in/drupal.outside_in'; $items['contextual']['#attached']['library'][] = 'outside_in/drupal.outside_in';
$items['contextual']['tab']['#attributes']['data-drupal-outsidein'] = 'toggle';
// Set a class on items to mark whether they should be active in edit mode. // Set a class on items to mark whether they should be active in edit mode.
// @todo Create a dynamic method for modules to set their own items. // @todo Create a dynamic method for modules to set their own items.
......
...@@ -12,7 +12,17 @@ class OutsideInBlockFormTest extends OutsideInJavascriptTestBase { ...@@ -12,7 +12,17 @@ class OutsideInBlockFormTest extends OutsideInJavascriptTestBase {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public static $modules = ['block', 'system', 'breakpoint', 'toolbar', 'contextual', 'outside_in']; public static $modules = [
'node',
'block',
'system',
'breakpoint',
'toolbar',
'contextual',
'outside_in',
'quickedit',
'search',
];
/** /**
* {@inheritdoc} * {@inheritdoc}
...@@ -26,72 +36,92 @@ protected function setUp() { ...@@ -26,72 +36,92 @@ protected function setUp() {
'administer blocks', 'administer blocks',
'access contextual links', 'access contextual links',
'access toolbar', 'access toolbar',
'administer nodes',
'access in-place editing',
'search content',
]); ]);
$this->drupalLogin($user); $this->drupalLogin($user);
$this->placeBlock('system_powered_by_block', ['id' => 'powered']); $this->placeBlock('system_powered_by_block', ['id' => 'powered']);
$this->placeBlock('system_branding_block', ['id' => 'branding']); $this->placeBlock('system_branding_block', ['id' => 'branding']);
$this->placeBlock('search_form_block', ['id' => 'search']);
} }
/** /**
* Tests updating the "Powered by Drupal" block in the Off-Canvas tray. * Tests opening Offcanvas tray by click blocks and elements in the blocks.
*/ */
public function testPoweredByBlock() { public function testBlocks() {
$blocks = [
[
'id' => 'block-powered',
'new_page_text' => 'Can you imagine anyone showing the label on this block?',
'element_selector' => '.content a',
'button_text' => 'Save Powered by Drupal',
],
[
'id' => 'block-branding',
'new_page_text' => 'The site that will live a very short life.',
'element_selector' => 'a[rel="home"]:nth-child(2)',
'button_text' => 'Save Site branding',
],
[
'id' => 'block-search',
'element_selector' => '#edit-submit',
'button_text' => 'Save Search form',
],
];
$page = $this->getSession()->getPage(); $page = $this->getSession()->getPage();
$web_assert = $this->assertSession(); foreach ($blocks as $block) {
$block_selector = '#' . $block['id'];
$this->drupalGet('user'); $this->drupalGet('user');
$this->enableEditingMode(); $this->toggleEditingMode();
$this->openBlockForm($block_selector);
// Open "Powered by Drupal" block form by clicking div.
$page->find('css', '#block-powered')->click();
$this->waitForOffCanvasToOpen();
$this->assertOffCanvasBlockFormIsValid();
switch ($block['id']) {
case 'block-powered':
// Fill out form, save the form. // Fill out form, save the form.
$new_label = 'Can you imagine anyone showing the label on this block?'; $page->fillField('settings[label]', $block['new_page_text']);
$page->fillField('settings[label]', $new_label);
$page->checkField('settings[label_display]'); $page->checkField('settings[label_display]');
break;
// @todo Uncomment the following lines after GastonJS problem solved. case 'block-branding':
// https://www.drupal.org/node/2789381 // Fill out form, save the form.
// $this->getTray()->pressButton('Save block'); $page->fillField('settings[site_information][site_name]', $block['new_page_text']);
// Make sure the changes are present. break;
// $web_assert->pageTextContains($new_label);
} }
/** if (isset($block['new_page_text'])) {
* Tests updating the System Branding block in the Off-Canvas tray. $page->pressButton($block['button_text']);
* // Make sure the changes are present.
* Also tests updating the site name. $this->getSession()->wait(500);
*/
public function testBrandingBlock() {
$web_assert = $this->assertSession(); $web_assert = $this->assertSession();
$this->drupalGet('user'); $web_assert->pageTextContains($block['new_page_text']);
$page = $this->getSession()->getPage(); }
$this->enableEditingMode();
// Open branding block form by clicking div. $this->openBlockForm($block_selector);
$page->find('css', '#block-branding')->click();
$this->waitForOffCanvasToOpen();
$this->assertOffCanvasBlockFormIsValid();
// Fill out form, save the form. $this->toggleEditingMode();
$new_site_name = 'The site that will live a very short life.'; // Canvas should close when editing module is closed.
$page->fillField('settings[site_information][site_name]', $new_site_name); $this->waitForOffCanvasToClose();
// @todo Uncomment the following lines after GastonJS problem solved. // Go into Edit mode again.
// https://www.drupal.org/node/2789381 $this->toggleEditingMode();
// $this->getTray()->pressButton('Save block');
// Make sure the changes are present. $element_selector = "$block_selector {$block['element_selector']}";
//$web_assert->pageTextContains($new_site_name); // Open block form by clicking a element inside the block.
// This confirms that default action for links and form elements is
// suppressed.
$this->openBlockForm($element_selector);
// Exit edit mode.
$this->toggleEditingMode();
}
} }
/** /**
* Enables Editing mode by pressing "Edit" button in the toolbar. * Enables Editing mode by pressing "Edit" button in the toolbar.
*/ */
protected function enableEditingMode() { protected function toggleEditingMode() {
$this->waitForElement('div[data-contextual-id="block:block=powered:langcode=en|outside_in::langcode=en"] .contextual-links a'); $this->waitForElement('div[data-contextual-id="block:block=powered:langcode=en|outside_in::langcode=en"] .contextual-links a');
$this->waitForElement('#toolbar-bar', 3000); $this->waitForElement('#toolbar-bar', 3000);
...@@ -114,4 +144,15 @@ protected function assertOffCanvasBlockFormIsValid() { ...@@ -114,4 +144,15 @@ protected function assertOffCanvasBlockFormIsValid() {
$web_assert->elementNotExists('css', 'select[data-drupal-selector="edit-region"]'); $web_assert->elementNotExists('css', 'select[data-drupal-selector="edit-region"]');
} }
/**
* Open block form by clicking the element found with a css selector.
*
* @param string $block_selector
* A css selector selects the block or an element within it.
*/
protected function openBlockForm($block_selector) {
$this->click($block_selector);
$this->waitForOffCanvasToOpen();
$this->assertOffCanvasBlockFormIsValid();
}
} }
...@@ -27,6 +27,8 @@ public function enableTheme($theme) { ...@@ -27,6 +27,8 @@ public function enableTheme($theme) {
* Waits for Off-canvas tray to open. * Waits for Off-canvas tray to open.
*/ */
protected function waitForOffCanvasToOpen() { protected function waitForOffCanvasToOpen() {
$web_assert = $this->assertSession();
$web_assert->assertWaitOnAjaxRequest();
$this->waitForElement('#drupal-offcanvas'); $this->waitForElement('#drupal-offcanvas');
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment