Skip to content
Snippets Groups Projects
Unverified Commit 6d6ab587 authored by Lauri Timmanee's avatar Lauri Timmanee
Browse files

Issue #3274937 by nod_, woldtwerk, Dom., Wim Leers: Get CKEditor 5 to work in (modal) dialogs

parent f90d8922
No related branches found
No related tags found
37 merge requests!12227Issue #3181946 by jonmcl, mglaman,!7471uncessary 5 files are moved from media-library folder to misc folder,!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!54479.5.x SF update,!5014Issue #3071143: Table Render Array Example Is Incorrect,!4868Issue #1428520: Improve menu parent link selection,!4289Issue #1344552 by marcingy, Niklas Fiekas, Ravi.J, aleevas, Eduardo Morales...,!4114Issue #2707291: Disable body-level scrolling when a dialog is open as a modal,!3630Issue #2815301 by Chi, DanielVeza, kostyashupenko, smustgrave: Allow to create...,!3291Issue #3336463: Rewrite rules for gzipped CSS and JavaScript aggregates never match,!3143Issue #3313342: [PHP 8.1] Deprecated function: strpos(): Passing null to parameter #1 LayoutBuilderUiCacheContext.php on line 28,!3102Issue #3164428 by DonAtt, longwave, sahil.goyal, Anchal_gupta, alexpott: Use...,!2853#3274419 Makes BaseFieldOverride inherit the internal property from the base field.,!2719Issue #3110137: Remove Classy from core.,!2437Issue #3238257 by hooroomoo, Wim Leers: Fragment link pointing to <textarea>...,!2378Issue #2875033: Optimize joins and table selection in SQL entity query implementation,!2074Issue #2707689: NodeForm::actions() checks for delete access on new entities,!2062Issue #3246454: Add weekly granularity to views date sort,!1591Issue #3199697: Add JSON:API Translation experimental module,!1484Exposed filters get values from URL when Ajax is on,!1255Issue #3238922: Refactor (if feasible) uses of the jQuery serialize function to use vanillaJS,!1254Issue #3238915: Refactor (if feasible) uses of the jQuery ready function to use VanillaJS,!1162Issue #3100350: Unable to save '/' root path alias,!1073issue #3191727: Focus states on mobile second level navigation items fixed,!10223132456: Fix issue where views instances are emptied before an ajax request is complete,!957Added throwing of InvalidPluginDefinitionException from getDefinition().,!925Issue #2339235: Remove taxonomy hard dependency on node module,!877Issue #2708101: Default value for link text is not saved,!873Issue #2875228: Site install not using batch API service,!872Draft: Issue #3221319: Race condition when creating menu links and editing content deletes menu links,!844Resolve #3036010 "Updaters",!712Issue #2909128: Autocomplete intermittent on Chrome Android,!579Issue #2230909: Simple decimals fail to pass validation,!560Move callback classRemove outside of the loop,!555Issue #3202493,!485Sets the autocomplete attribute for username/password input field on login form.,!30Issue #3182188: Updates composer usage to point at ./vendor/bin/composer
......@@ -440,6 +440,15 @@ function ckeditor5_library_info_alter(&$libraries, $extension) {
}
}
if ($extension === 'core') {
// CSS rule to resolve the conflict with z-index between CKEditor 5 and jQuery UI.
$libraries['drupal.dialog']['css']['component']['modules/ckeditor5/css/ckeditor5.dialog.fix.css'] = [];
// Fix the CKEditor 5 focus management in dialogs. Modify the library
// declaration to ensure this file is always loaded after
// drupal.dialog.jquery-ui.js.
$libraries['drupal.dialog']['js']['modules/ckeditor5/js/ckeditor5.dialog.fix.js'] = [];
}
// Only add translation processing if the locale module is enabled.
if (!$moduleHandler->moduleExists('locale')) {
return;
......
.ui-dialog ~ .ck-body-wrapper {
--ck-z-modal: 1261;
}
/**
* @file
* This file overrides the way jQuery UI focus trap works.
*
* When a focus event is fired while a CKEditor 5 instance is focused, do not
* trap the focus and let CKEditor 5 manage that focus.
*/
(($) => {
// Get core version of the _focusTabbable method.
const oldFocusTabbable = $.ui.dialog._proto._focusTabbable;
$.widget('ui.dialog', $.ui.dialog, {
// Override core override of jQuery UI's `_focusTabbable()` so that
// CKEditor 5 in modals can work as expected.
_focusTabbable() {
// When the focused element is a CKEditor 5 instance, disable jQuery UI
// focus trap and delegate focus trap to CKEditor 5.
const hasFocus = this._focusedElement
? this._focusedElement.get(0)
: null;
// In case the element is a CKEditor 5 instance, do not change focus
// management.
if (!(hasFocus && hasFocus.ckeditorInstance)) {
oldFocusTabbable.call(this);
}
},
});
})(jQuery);
/**
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/2815083
* @preserve
**/
($ => {
const oldFocusTabbable = $.ui.dialog._proto._focusTabbable;
$.widget('ui.dialog', $.ui.dialog, {
_focusTabbable() {
const hasFocus = this._focusedElement ? this._focusedElement.get(0) : null;
if (!(hasFocus && hasFocus.ckeditorInstance)) {
oldFocusTabbable.call(this);
}
}
});
})(jQuery);
\ No newline at end of file
......@@ -4,3 +4,10 @@ ckeditor5_test.off_canvas:
_controller: '\Drupal\ckeditor5_test\Controller\CKEditor5OffCanvasTestController::testOffCanvas'
requirements:
_access: 'TRUE'
ckeditor5_test.dialog:
path: '/ckeditor5_test/dialog'
defaults:
_controller: '\Drupal\ckeditor5_test\Controller\CKEditor5DialogTestController::testDialog'
requirements:
_access: 'TRUE'
<?php
declare(strict_types = 1);
namespace Drupal\ckeditor5_test\Controller;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Url;
/**
* Provides controller for testing CKEditor in off-canvas dialogs.
*/
class CKEditor5DialogTestController {
/**
* Returns a link that can open a node add form in an modal dialog.
*
* @return array
* A render array.
*/
public function testDialog() {
$build['link'] = [
'#type' => 'link',
'#title' => 'Add Node',
'#url' => Url::fromRoute('node.add', ['node_type' => 'page']),
'#attributes' => [
'class' => ['use-ajax'],
'data-dialog-type' => 'dialog',
'data-dialog-options' => Json::encode([
'width' => 700,
'modal' => TRUE,
'autoResize' => TRUE,
]),
],
];
$build['#attached']['library'][] = 'core/drupal.dialog.ajax';
return $build;
}
}
<?php
namespace Drupal\Tests\ckeditor5\FunctionalJavascript;
use Drupal\ckeditor5\Plugin\Editor\CKEditor5;
use Drupal\editor\Entity\Editor;
use Drupal\filter\Entity\FilterFormat;
use Drupal\Tests\ckeditor5\Traits\CKEditor5TestTrait;
use Drupal\user\RoleInterface;
use Symfony\Component\Validator\ConstraintViolation;
/**
* Tests for CKEditor 5 to ensure correct focus management in dialogs.
*
* @group ckeditor5
* @internal
*/
class CKEditor5DialogTest extends CKEditor5TestBase {
use CKEditor5TestTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'node',
'ckeditor5',
'ckeditor5_test',
];
/**
* Tests if CKEditor 5 tooltips can be interacted with in dialogs.
*/
public function testCKEditor5FocusInTooltipsInDialog() {
FilterFormat::create([
'format' => 'test_format',
'name' => 'CKEditor 5 with link',
'roles' => [RoleInterface::AUTHENTICATED_ID],
])->save();
Editor::create([
'format' => 'test_format',
'editor' => 'ckeditor5',
'settings' => [
'toolbar' => [
'items' => ['link'],
],
],
])->save();
$this->assertSame([], array_map(
function (ConstraintViolation $v) {
return (string) $v->getMessage();
},
iterator_to_array(CKEditor5::validatePair(
Editor::load('test_format'),
FilterFormat::load('test_format')
))
));
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
$this->drupalGet('/ckeditor5_test/dialog');
$page->clickLink('Add Node');
$assert_session->waitForElementVisible('css', '[role="dialog"]');
$assert_session->assertWaitOnAjaxRequest();
$content_area = $assert_session->waitForElementVisible('css', '.ck-editor__editable');
// Focus the editable area first.
$content_area->click();
// Then press the button to add a link.
$this->pressEditorButton('Link');
$link_url = '/ckeditor5_test/dialog';
$input = $assert_session->waitForElementVisible('css', '.ck-balloon-panel input.ck-input-text');
// Make sure the input field can have focus and we can type into it.
$input->setValue($link_url);
// Save the new link.
$page->find('css', '.ck-balloon-panel .ck-button-save')->click();
// Make sure something was added to the text.
$this->assertNotEmpty($content_area->getText());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment