Issue #2765525 by phenaproxima, Wim Leers, droplet: Add AJAX command to add style sheets to CKEditor instances
parent
9d8d1ed77b
commit
6fa5085d66
|
@ -3,7 +3,7 @@
|
||||||
* CKEditor implementation of {@link Drupal.editors} API.
|
* CKEditor implementation of {@link Drupal.editors} API.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function (Drupal, debounce, CKEDITOR, $, displace) {
|
(function (Drupal, debounce, CKEDITOR, $, displace, AjaxCommands) {
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -318,4 +318,33 @@
|
||||||
// Set the CKEditor cache-busting string to the same value as Drupal.
|
// Set the CKEditor cache-busting string to the same value as Drupal.
|
||||||
CKEDITOR.timestamp = drupalSettings.ckeditor.timestamp;
|
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);
|
||||||
|
|
|
@ -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,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
ajax_css:
|
||||||
|
js:
|
||||||
|
js/ajax-css.js: {}
|
||||||
|
dependencies:
|
||||||
|
- ckeditor/drupal.ckeditor
|
|
@ -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'
|
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
color: red;
|
||||||
|
}
|
|
@ -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);
|
|
@ -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');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue