Issue #2765525 by phenaproxima, Wim Leers, droplet: Add AJAX command to add style sheets to CKEditor instances

8.3.x
Alex Pott 2016-12-21 08:19:36 +00:00
parent 9d8d1ed77b
commit 6fa5085d66
8 changed files with 333 additions and 2 deletions

View File

@ -3,7 +3,7 @@
* CKEditor implementation of {@link Drupal.editors} API.
*/
(function (Drupal, debounce, CKEDITOR, $, displace) {
(function (Drupal, debounce, CKEDITOR, $, displace, AjaxCommands) {
'use strict';
@ -318,4 +318,33 @@
// Set the CKEditor cache-busting string to the same value as Drupal.
CKEDITOR.timestamp = drupalSettings.ckeditor.timestamp;
})(Drupal, Drupal.debounce, CKEDITOR, jQuery, Drupal.displace);
if (AjaxCommands) {
/**
* Command to add style sheets to a CKEditor instance.
*
* Works for both iframe and inline CKEditor instances.
*
* @param {Drupal.Ajax} [ajax]
* {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
* @param {object} response
* The response from the Ajax request.
* @param {string} response.editor_id
* The CKEditor instance ID.
* @param {number} [status]
* The XMLHttpRequest status.
*
* @see http://docs.ckeditor.com/#!/api/CKEDITOR.dom.document
*/
AjaxCommands.prototype.ckeditor_add_stylesheet = function (ajax, response, status) {
var editor = CKEDITOR.instances[response.editor_id];
if (editor) {
response.stylesheets.forEach(function (url) {
editor.document.appendStyleSheet(url);
});
}
};
}
})(Drupal, Drupal.debounce, CKEDITOR, jQuery, Drupal.displace, Drupal.AjaxCommands);

View File

@ -0,0 +1,64 @@
<?php
namespace Drupal\ckeditor\Ajax;
use Drupal\Core\Ajax\CommandInterface;
/**
* AJAX command to add style sheets to a CKEditor instance.
*/
class AddStyleSheetCommand implements CommandInterface {
/**
* The CKEditor instance ID.
*
* @var string
*/
protected $editorId;
/**
* The style sheet URLs to add to the CKEditor instance.
*
* @var string[]
*/
protected $styleSheets = [];
/**
* AddStyleSheetCommand constructor.
*
* @param string $editor_id
* The CKEditor instance ID.
* @param string[] $stylesheets
* The style sheet URLs to add to the CKEditor instance.
*/
public function __construct($editor_id, array $stylesheets = []) {
$this->editorId = $editor_id;
$this->styleSheets = $stylesheets;
}
/**
* Adds a style sheet to the CKEditor instance.
*
* @param string $stylesheet
* The style sheet URL.
*
* @return $this
* The called object, for chaining.
*/
public function addStyleSheet($stylesheet) {
$this->styleSheets[] = $stylesheet;
return $this;
}
/**
* {@inheritdoc}
*/
public function render() {
return [
'command' => 'ckeditor_add_stylesheet',
'editor_id' => $this->editorId,
'stylesheets' => $this->styleSheets,
];
}
}

View File

@ -0,0 +1,5 @@
ajax_css:
js:
js/ajax-css.js: {}
dependencies:
- ckeditor/drupal.ckeditor

View File

@ -0,0 +1,7 @@
ckeditor_test.ajax_css:
path: '/ckeditor_test/ajax_css'
defaults:
_title: 'AJAX CSS Test'
_form: '\Drupal\ckeditor_test\Form\AjaxCssForm'
requirements:
_access: 'TRUE'

View File

@ -0,0 +1,3 @@
body {
color: red;
}

View File

@ -0,0 +1,24 @@
/**
* @file
* Contains client-side code for testing CSS delivered to CKEditor via AJAX.
*/
(function (Drupal, ckeditor, editorSettings, $) {
'use strict';
Drupal.behaviors.ajaxCssForm = {
attach: function (context) {
// Initialize an inline CKEditor on the #edit-inline element if it
// isn't editable already.
$(context)
.find('#edit-inline')
.not('[contenteditable]')
.each(function () {
ckeditor.attachInlineEditor(this, editorSettings.formats.test_format);
});
}
};
})(Drupal, Drupal.editors.ckeditor, drupalSettings.editor, jQuery);

View File

@ -0,0 +1,111 @@
<?php
namespace Drupal\ckeditor_test\Form;
use Drupal\ckeditor\Ajax\AddStyleSheetCommand;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* A form for testing delivery of CSS to CKEditor via AJAX.
*/
class AjaxCssForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'ckeditor_test_ajax_css_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// Create an inline and iframe CKEditor instance so we can test against
// both.
$form['inline'] = [
'#type' => 'container',
'#attached' => [
'library' => [
'ckeditor_test/ajax_css',
],
],
'#children' => $this->t('Here be dragons.'),
];
$form['iframe'] = [
'#type' => 'text_format',
'#default_value' => $this->t('Here be llamas.'),
];
// A pair of buttons to trigger the AJAX events.
$form['actions'] = [
'css_inline' => [
'#type' => 'submit',
'#value' => $this->t('Add CSS to inline CKEditor instance'),
'#ajax' => [
'callback' => [$this, 'addCssInline'],
],
],
'css_frame' => [
'#type' => 'submit',
'#value' => $this->t('Add CSS to iframe CKEditor instance'),
'#ajax' => [
'callback' => [$this, 'addCssIframe'],
],
],
'#type' => 'actions',
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Nothing to do here.
}
/**
* Generates an AJAX response to add CSS to a CKEditor Text Editor instance.
*
* @param string $editor_id
* The Text Editor instance ID.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* An AJAX response.
*/
protected function generateResponse($editor_id) {
// Build a URL to the style sheet that will be added.
$url = drupal_get_path('module', 'ckeditor_test') . '/css/test.css';
$url = file_create_url($url);
$url = file_url_transform_relative($url);
$response = new AjaxResponse();
return $response
->addCommand(new AddStyleSheetCommand($editor_id, [$url]));
}
/**
* Handles the AJAX request to add CSS to the inline editor.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* An AJAX response.
*/
public function addCssInline() {
return $this->generateResponse('edit-inline');
}
/**
* Handles the AJAX request to add CSS to the iframe editor.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* An AJAX response.
*/
public function addCssIframe() {
return $this->generateResponse('edit-iframe-value');
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace Drupal\Tests\ckeditor\FunctionalJavascript;
use Drupal\editor\Entity\Editor;
use Drupal\filter\Entity\FilterFormat;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
/**
* Tests delivery of CSS to CKEditor via AJAX.
*
* @group ckeditor
*/
class AjaxCssTest extends JavascriptTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['ckeditor', 'ckeditor_test'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
FilterFormat::create([
'format' => 'test_format',
'name' => $this->randomMachineName(),
])->save();
Editor::create([
'editor' => 'ckeditor',
'format' => 'test_format',
])->save();
user_role_grant_permissions('anonymous', ['use text format test_format']);
}
/**
* Tests adding style sheets dynamically to CKEditor.
*/
public function testCkeditorAjaxAddCss() {
$this->drupalGet('/ckeditor_test/ajax_css');
$session = $this->getSession();
$assert = $this->assertSession();
$style_color = 'rgb(255, 0, 0)';
// Add the inline CSS and assert that the style is applied to the main body,
// but not the iframe.
$session->getPage()->pressButton('Add CSS to inline CKEditor instance');
$assert->assertWaitOnAjaxRequest();
$this->assertEquals($style_color, $this->getEditorStyle('edit-inline', 'color'));
$this->assertNotEquals($style_color, $this->getEditorStyle('edit-iframe-value', 'color'));
$session->reload();
// Add the iframe CSS and assert that the style is applied to the iframe,
// but not the main body.
$session->getPage()->pressButton('Add CSS to iframe CKEditor instance');
$assert->assertWaitOnAjaxRequest();
$this->assertNotEquals($style_color, $this->getEditorStyle('edit-inline', 'color'));
$this->assertEquals($style_color, $this->getEditorStyle('edit-iframe-value', 'color'));
}
/**
* Gets a computed style value for a CKEditor instance.
*
* @param string $instance_id
* The CKEditor instance ID.
* @param string $attribute
* The style attribute.
*
* @return string
* The computed style value.
*/
protected function getEditorStyle($instance_id, $attribute) {
$js = sprintf(
'CKEDITOR.instances["%s"].document.getBody().getComputedStyle("%s")',
$instance_id,
$attribute
);
return $this->getSession()->evaluateScript($js);
}
}