Update core 8.3.0
This commit is contained in:
parent
da7a7918f8
commit
cd7a898e66
6144 changed files with 132297 additions and 87747 deletions
|
|
@ -33,10 +33,10 @@ class EditorDialogSave implements CommandInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function render() {
|
||||
return array(
|
||||
return [
|
||||
'command' => 'editorDialogSave',
|
||||
'values' => $this->values,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class EditorController extends ControllerBase {
|
|||
|
||||
// Direct text editing is only supported for single-valued fields.
|
||||
$field = $entity->getTranslation($langcode)->$field_name;
|
||||
$editable_text = check_markup($field->value, $field->format, $langcode, array(FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE));
|
||||
$editable_text = check_markup($field->value, $field->format, $langcode, [FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE]);
|
||||
$response->addCommand(new GetUntransformedTextCommand($editable_text));
|
||||
|
||||
return $response;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class Standard extends Xss implements EditorXssFilterInterface {
|
|||
// directly.
|
||||
// <iframe> is considered safe because it only allows HTML content to be
|
||||
// embedded, hence ensuring the same origin policy always applies.
|
||||
$dangerous_tags = array('script', 'style', 'link', 'embed', 'object');
|
||||
$dangerous_tags = ['script', 'style', 'link', 'embed', 'object'];
|
||||
|
||||
// Simply blacklisting these five dangerous tags would bring safety, but
|
||||
// also user frustration: what if a text format is configured to allow
|
||||
|
|
@ -130,13 +130,13 @@ class Standard extends Xss implements EditorXssFilterInterface {
|
|||
*/
|
||||
protected static function getAllowedTags($restrictions) {
|
||||
if ($restrictions === FALSE || !isset($restrictions['allowed'])) {
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
$allowed_tags = array_keys($restrictions['allowed']);
|
||||
// Exclude the wildcard tag, which is used to set attribute restrictions on
|
||||
// all tags simultaneously.
|
||||
$allowed_tags = array_diff($allowed_tags, array('*'));
|
||||
$allowed_tags = array_diff($allowed_tags, ['*']);
|
||||
|
||||
return $allowed_tags;
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@ class Standard extends Xss implements EditorXssFilterInterface {
|
|||
*/
|
||||
protected static function getForbiddenTags($restrictions) {
|
||||
if ($restrictions === FALSE || !isset($restrictions['forbidden_tags'])) {
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
return $restrictions['forbidden_tags'];
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class Element {
|
|||
/**
|
||||
* Additional #pre_render callback for 'text_format' elements.
|
||||
*/
|
||||
function preRenderTextFormat(array $element) {
|
||||
public function preRenderTextFormat(array $element) {
|
||||
// Allow modules to programmatically enforce no client-side editor by
|
||||
// setting the #editor property to FALSE.
|
||||
if (isset($element['#editor']) && !$element['#editor']) {
|
||||
|
|
@ -64,14 +64,14 @@ class Element {
|
|||
if (!$element['format']['format']['#access']) {
|
||||
// Use the first (and only) available text format.
|
||||
$format_id = $format_ids[0];
|
||||
$element['format']['editor'] = array(
|
||||
$element['format']['editor'] = [
|
||||
'#type' => 'hidden',
|
||||
'#name' => $element['format']['format']['#name'],
|
||||
'#value' => $format_id,
|
||||
'#attributes' => array(
|
||||
'#attributes' => [
|
||||
'data-editor-for' => $field_id,
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
}
|
||||
// Otherwise, attach to text format selector.
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -49,14 +49,14 @@ class Editor extends ConfigEntityBase implements EditorInterface {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $settings = array();
|
||||
protected $settings = [];
|
||||
|
||||
/**
|
||||
* The structured array of image upload settings.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $image_upload = array();
|
||||
protected $image_upload = [];
|
||||
|
||||
/**
|
||||
* The filter format this text editor is associated with.
|
||||
|
|
|
|||
|
|
@ -94,26 +94,26 @@ class EditorImageDialog extends FormBase {
|
|||
$existing_file = isset($image_element['data-entity-uuid']) ? \Drupal::entityManager()->loadEntityByUuid('file', $image_element['data-entity-uuid']) : NULL;
|
||||
$fid = $existing_file ? $existing_file->id() : NULL;
|
||||
|
||||
$form['fid'] = array(
|
||||
$form['fid'] = [
|
||||
'#title' => $this->t('Image'),
|
||||
'#type' => 'managed_file',
|
||||
'#upload_location' => $image_upload['scheme'] . '://' . $image_upload['directory'],
|
||||
'#default_value' => $fid ? array($fid) : NULL,
|
||||
'#upload_validators' => array(
|
||||
'file_validate_extensions' => array('gif png jpg jpeg'),
|
||||
'file_validate_size' => array($max_filesize),
|
||||
'file_validate_image_resolution' => array($max_dimensions),
|
||||
),
|
||||
'#default_value' => $fid ? [$fid] : NULL,
|
||||
'#upload_validators' => [
|
||||
'file_validate_extensions' => ['gif png jpg jpeg'],
|
||||
'file_validate_size' => [$max_filesize],
|
||||
'file_validate_image_resolution' => [$max_dimensions],
|
||||
],
|
||||
'#required' => TRUE,
|
||||
);
|
||||
];
|
||||
|
||||
$form['attributes']['src'] = array(
|
||||
$form['attributes']['src'] = [
|
||||
'#title' => $this->t('URL'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => isset($image_element['src']) ? $image_element['src'] : '',
|
||||
'#maxlength' => 2048,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
];
|
||||
|
||||
// If the editor has image uploads enabled, show a managed_file form item,
|
||||
// otherwise show a (file URL) text form item.
|
||||
|
|
@ -137,7 +137,7 @@ class EditorImageDialog extends FormBase {
|
|||
if ($alt === '' && !empty($image_element['src'])) {
|
||||
$alt = '""';
|
||||
}
|
||||
$form['attributes']['alt'] = array(
|
||||
$form['attributes']['alt'] = [
|
||||
'#title' => $this->t('Alternative text'),
|
||||
'#placeholder' => $this->t('Short description for the visually impaired'),
|
||||
'#type' => 'textfield',
|
||||
|
|
@ -145,51 +145,51 @@ class EditorImageDialog extends FormBase {
|
|||
'#required_error' => $this->t('Alternative text is required.<br />(Only in rare cases should this be left empty. To create empty alternative text, enter <code>""</code> — two double quotes without any content).'),
|
||||
'#default_value' => $alt,
|
||||
'#maxlength' => 2048,
|
||||
);
|
||||
];
|
||||
|
||||
// When Drupal core's filter_align is being used, the text editor may
|
||||
// offer the ability to change the alignment.
|
||||
if (isset($image_element['data-align']) && $editor->getFilterFormat()->filters('filter_align')->status) {
|
||||
$form['align'] = array(
|
||||
$form['align'] = [
|
||||
'#title' => $this->t('Align'),
|
||||
'#type' => 'radios',
|
||||
'#options' => array(
|
||||
'#options' => [
|
||||
'none' => $this->t('None'),
|
||||
'left' => $this->t('Left'),
|
||||
'center' => $this->t('Center'),
|
||||
'right' => $this->t('Right'),
|
||||
),
|
||||
],
|
||||
'#default_value' => $image_element['data-align'] === '' ? 'none' : $image_element['data-align'],
|
||||
'#wrapper_attributes' => array('class' => array('container-inline')),
|
||||
'#attributes' => array('class' => array('container-inline')),
|
||||
'#parents' => array('attributes', 'data-align'),
|
||||
);
|
||||
'#wrapper_attributes' => ['class' => ['container-inline']],
|
||||
'#attributes' => ['class' => ['container-inline']],
|
||||
'#parents' => ['attributes', 'data-align'],
|
||||
];
|
||||
}
|
||||
|
||||
// When Drupal core's filter_caption is being used, the text editor may
|
||||
// offer the ability to in-place edit the image's caption: show a toggle.
|
||||
if (isset($image_element['hasCaption']) && $editor->getFilterFormat()->filters('filter_caption')->status) {
|
||||
$form['caption'] = array(
|
||||
$form['caption'] = [
|
||||
'#title' => $this->t('Caption'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $image_element['hasCaption'] === 'true',
|
||||
'#parents' => array('attributes', 'hasCaption'),
|
||||
);
|
||||
'#parents' => ['attributes', 'hasCaption'],
|
||||
];
|
||||
}
|
||||
|
||||
$form['actions'] = array(
|
||||
$form['actions'] = [
|
||||
'#type' => 'actions',
|
||||
);
|
||||
$form['actions']['save_modal'] = array(
|
||||
];
|
||||
$form['actions']['save_modal'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
// No regular submit-handler. This form only works via JavaScript.
|
||||
'#submit' => array(),
|
||||
'#ajax' => array(
|
||||
'#submit' => [],
|
||||
'#ajax' => [
|
||||
'callback' => '::submitForm',
|
||||
'event' => 'click',
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
|
@ -202,22 +202,22 @@ class EditorImageDialog extends FormBase {
|
|||
|
||||
// Convert any uploaded files from the FID values to data-entity-uuid
|
||||
// attributes and set data-entity-type to 'file'.
|
||||
$fid = $form_state->getValue(array('fid', 0));
|
||||
$fid = $form_state->getValue(['fid', 0]);
|
||||
if (!empty($fid)) {
|
||||
$file = $this->fileStorage->load($fid);
|
||||
$file_url = file_create_url($file->getFileUri());
|
||||
// Transform absolute image URLs to relative image URLs: prevent problems
|
||||
// on multisite set-ups and prevent mixed content errors.
|
||||
$file_url = file_url_transform_relative($file_url);
|
||||
$form_state->setValue(array('attributes', 'src'), $file_url);
|
||||
$form_state->setValue(array('attributes', 'data-entity-uuid'), $file->uuid());
|
||||
$form_state->setValue(array('attributes', 'data-entity-type'), 'file');
|
||||
$form_state->setValue(['attributes', 'src'], $file_url);
|
||||
$form_state->setValue(['attributes', 'data-entity-uuid'], $file->uuid());
|
||||
$form_state->setValue(['attributes', 'data-entity-type'], 'file');
|
||||
}
|
||||
|
||||
// When the alt attribute is set to two double quotes, transform it to the
|
||||
// empty string: two double quotes signify "empty alt attribute". See above.
|
||||
if (trim($form_state->getValue(array('attributes', 'alt'))) === '""') {
|
||||
$form_state->setValue(array('attributes', 'alt'), '');
|
||||
if (trim($form_state->getValue(['attributes', 'alt'])) === '""') {
|
||||
$form_state->setValue(['attributes', 'alt'], '');
|
||||
}
|
||||
|
||||
if ($form_state->getErrors()) {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class EditorLinkDialog extends FormBase {
|
|||
// The default values are set directly from \Drupal::request()->request,
|
||||
// provided by the editor plugin opening the dialog.
|
||||
$user_input = $form_state->getUserInput();
|
||||
$input = isset($user_input['editor_object']) ? $user_input['editor_object'] : array();
|
||||
$input = isset($user_input['editor_object']) ? $user_input['editor_object'] : [];
|
||||
|
||||
$form['#tree'] = TRUE;
|
||||
$form['#attached']['library'][] = 'editor/drupal.editor.dialog';
|
||||
|
|
@ -41,26 +41,26 @@ class EditorLinkDialog extends FormBase {
|
|||
|
||||
// Everything under the "attributes" key is merged directly into the
|
||||
// generated link tag's attributes.
|
||||
$form['attributes']['href'] = array(
|
||||
$form['attributes']['href'] = [
|
||||
'#title' => $this->t('URL'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => isset($input['href']) ? $input['href'] : '',
|
||||
'#maxlength' => 2048,
|
||||
);
|
||||
];
|
||||
|
||||
$form['actions'] = array(
|
||||
$form['actions'] = [
|
||||
'#type' => 'actions',
|
||||
);
|
||||
$form['actions']['save_modal'] = array(
|
||||
];
|
||||
$form['actions']['save_modal'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
// No regular submit-handler. This form only works via JavaScript.
|
||||
'#submit' => array(),
|
||||
'#ajax' => array(
|
||||
'#submit' => [],
|
||||
'#ajax' => [
|
||||
'callback' => '::submitForm',
|
||||
'event' => 'click',
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,26 +26,56 @@ abstract class EditorBase extends PluginBase implements EditorPluginInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultSettings() {
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo Remove in Drupal 9.0.0.
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor) {
|
||||
@trigger_error('The ' . __METHOD__ . ' method is deprecated since version 8.3.x and will be removed in 9.0.0.', E_USER_DEPRECATED);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo Remove in Drupal 9.0.0.
|
||||
*/
|
||||
public function settingsFormValidate(array $form, FormStateInterface $form_state) {
|
||||
@trigger_error('The ' . __METHOD__ . ' method is deprecated since version 8.3.x and will be removed in 9.0.0.', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo Remove in Drupal 9.0.0.
|
||||
*/
|
||||
public function settingsFormSubmit(array $form, FormStateInterface $form_state) {
|
||||
@trigger_error('The ' . __METHOD__ . ' method is deprecated since version 8.3.x and will be removed in 9.0.0.', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsFormSubmit(array $form, FormStateInterface $form_state) {
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
return $this->settingsForm($form, $form_state, $form_state->get('editor'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
return $this->settingsFormValidate($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
return $this->settingsFormSubmit($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class EditorManager extends DefaultPluginManager {
|
|||
* An array of translated text editor labels, keyed by ID.
|
||||
*/
|
||||
public function listOptions() {
|
||||
$options = array();
|
||||
$options = [];
|
||||
foreach ($this->getDefinitions() as $key => $definition) {
|
||||
$options[$key] = $definition['label'];
|
||||
}
|
||||
|
|
@ -59,9 +59,9 @@ class EditorManager extends DefaultPluginManager {
|
|||
* @see \Drupal\Core\Render\AttachmentsResponseProcessorInterface::processAttachments()
|
||||
*/
|
||||
public function getAttachments(array $format_ids) {
|
||||
$attachments = array('library' => array());
|
||||
$attachments = ['library' => []];
|
||||
|
||||
$settings = array();
|
||||
$settings = [];
|
||||
foreach ($format_ids as $format_id) {
|
||||
$editor = editor_load($format_id);
|
||||
if (!$editor) {
|
||||
|
|
@ -75,20 +75,20 @@ class EditorManager extends DefaultPluginManager {
|
|||
$attachments['library'] = array_merge($attachments['library'], $plugin->getLibraries($editor));
|
||||
|
||||
// Format-specific JavaScript settings.
|
||||
$settings['editor']['formats'][$format_id] = array(
|
||||
$settings['editor']['formats'][$format_id] = [
|
||||
'format' => $format_id,
|
||||
'editor' => $editor->getEditor(),
|
||||
'editorSettings' => $plugin->getJSSettings($editor),
|
||||
'editorSupportsContentFiltering' => $plugin_definition['supports_content_filtering'],
|
||||
'isXssSafe' => $plugin_definition['is_xss_safe'],
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
// Allow other modules to alter all JavaScript settings.
|
||||
$this->moduleHandler->alter('editor_js_settings', $settings);
|
||||
|
||||
if (empty($attachments['library']) && empty($settings)) {
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
$attachments['drupalSettings'] = $settings;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
namespace Drupal\editor\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\PluginFormInterface;
|
||||
use Drupal\editor\Entity\Editor;
|
||||
|
||||
/**
|
||||
|
|
@ -12,12 +12,17 @@ use Drupal\editor\Entity\Editor;
|
|||
* Modules implementing this interface may want to extend the EditorBase class,
|
||||
* which provides default implementations of each method where appropriate.
|
||||
*
|
||||
* If the editor's behavior depends on extensive options and/or external data,
|
||||
* then the implementing module can choose to provide a separate, global
|
||||
* configuration page rather than per-text-format settings. In that case, this
|
||||
* form should provide a link to the separate settings page.
|
||||
*
|
||||
* @see \Drupal\editor\Annotation\Editor
|
||||
* @see \Drupal\editor\Plugin\EditorBase
|
||||
* @see \Drupal\editor\Plugin\EditorManager
|
||||
* @see plugin_api
|
||||
*/
|
||||
interface EditorPluginInterface extends PluginInspectionInterface {
|
||||
interface EditorPluginInterface extends PluginInspectionInterface, PluginFormInterface {
|
||||
|
||||
/**
|
||||
* Returns the default settings for this configurable text editor.
|
||||
|
|
@ -28,53 +33,6 @@ interface EditorPluginInterface extends PluginInspectionInterface {
|
|||
*/
|
||||
public function getDefaultSettings();
|
||||
|
||||
/**
|
||||
* Returns a settings form to configure this text editor.
|
||||
*
|
||||
* If the editor's behavior depends on extensive options and/or external data,
|
||||
* then the implementing module can choose to provide a separate, global
|
||||
* configuration page rather than per-text-format settings. In that case, this
|
||||
* form should provide a link to the separate settings page.
|
||||
*
|
||||
* @param array $form
|
||||
* An empty form array to be populated with a configuration form, if any.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The state of the entire filter administration form.
|
||||
* @param \Drupal\editor\Entity\Editor $editor
|
||||
* A configured text editor object.
|
||||
*
|
||||
* @return array
|
||||
* A render array for the settings form.
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor);
|
||||
|
||||
/**
|
||||
* Validates the settings form for an editor.
|
||||
*
|
||||
* The contents of the editor settings are located in
|
||||
* $form_state->getValue(array('editor', 'settings')). Calls to $form_state->setError()
|
||||
* should reflect this location in the settings form.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*/
|
||||
public function settingsFormValidate(array $form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Modifies any values in the form state to prepare them for saving.
|
||||
*
|
||||
* Values in $form_state->getValue(array('editor', 'settings')) are saved by
|
||||
* Editor module in editor_form_filter_admin_format_submit().
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*/
|
||||
public function settingsFormSubmit(array $form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Returns JavaScript settings to be attached.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class EditorFileReference extends FilterBase implements ContainerFactoryPluginIn
|
|||
if (stristr($text, 'data-entity-type="file"') !== FALSE) {
|
||||
$dom = Html::load($text);
|
||||
$xpath = new \DOMXPath($dom);
|
||||
$processed_uuids = array();
|
||||
$processed_uuids = [];
|
||||
foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid]') as $node) {
|
||||
$uuid = $node->getAttribute('data-entity-uuid');
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class Editor extends PluginBase implements InPlaceEditorInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function getMetadata(FieldItemListInterface $items) {
|
||||
public function getMetadata(FieldItemListInterface $items) {
|
||||
$format_id = $items[0]->format;
|
||||
$metadata['format'] = $format_id;
|
||||
$metadata['formatHasTransformations'] = $this->textFormatHasTransformationFilters($format_id);
|
||||
|
|
@ -60,7 +60,7 @@ class Editor extends PluginBase implements InPlaceEditorInterface {
|
|||
*/
|
||||
protected function textFormatHasTransformationFilters($format_id) {
|
||||
$format = FilterFormat::load($format_id);
|
||||
return (bool) count(array_intersect(array(FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE), $format->getFiltertypes()));
|
||||
return (bool) count(array_intersect([FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE], $format->getFiltertypes()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -74,7 +74,7 @@ class Editor extends PluginBase implements InPlaceEditorInterface {
|
|||
$definitions = $manager->getDefinitions();
|
||||
|
||||
// Filter the current user's formats to those that support inline editing.
|
||||
$formats = array();
|
||||
$formats = [];
|
||||
foreach ($user_format_ids as $format_id) {
|
||||
if ($editor = editor_load($format_id)) {
|
||||
$editor_id = $editor->getEditor();
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class EditorAdminTest extends WebTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('filter', 'editor');
|
||||
public static $modules = ['filter', 'editor'];
|
||||
|
||||
/**
|
||||
* A user with the 'administer filters' permission.
|
||||
|
|
@ -33,16 +33,16 @@ class EditorAdminTest extends WebTestBase {
|
|||
parent::setUp();
|
||||
|
||||
// Add text format.
|
||||
$filtered_html_format = FilterFormat::create(array(
|
||||
$filtered_html_format = FilterFormat::create([
|
||||
'format' => 'filtered_html',
|
||||
'name' => 'Filtered HTML',
|
||||
'weight' => 0,
|
||||
'filters' => array(),
|
||||
));
|
||||
'filters' => [],
|
||||
]);
|
||||
$filtered_html_format->save();
|
||||
|
||||
// Create admin user.
|
||||
$this->adminUser = $this->drupalCreateUser(array('administer filters'));
|
||||
$this->adminUser = $this->drupalCreateUser(['administer filters']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -83,9 +83,9 @@ class EditorAdminTest extends WebTestBase {
|
|||
$this->verifyUnicornEditorConfiguration('filtered_html', FALSE);
|
||||
|
||||
// Switch back to 'None' and check the Unicorn Editor's settings are gone.
|
||||
$edit = array(
|
||||
$edit = [
|
||||
'editor[editor]' => '',
|
||||
);
|
||||
];
|
||||
$this->drupalPostAjaxForm(NULL, $edit, 'editor_configure');
|
||||
$unicorn_setting = $this->xpath('//input[@name="editor[settings][ponies_too]" and @type="checkbox" and @checked]');
|
||||
$this->assertTrue(count($unicorn_setting) === 0, "Unicorn Editor's settings form is no longer present.");
|
||||
|
|
@ -135,7 +135,7 @@ class EditorAdminTest extends WebTestBase {
|
|||
$this->drupalLogin($account);
|
||||
|
||||
// The node edit page header.
|
||||
$text = t('<em>Edit @type</em> @title', array('@type' => $node_type->label(), '@title' => $node->label()));
|
||||
$text = t('<em>Edit @type</em> @title', ['@type' => $node_type->label(), '@title' => $node->label()]);
|
||||
|
||||
// Go to node edit form.
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
|
|
@ -162,10 +162,10 @@ class EditorAdminTest extends WebTestBase {
|
|||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet('admin/config/content/formats/add');
|
||||
// Configure the text format name.
|
||||
$edit = array(
|
||||
$edit = [
|
||||
'name' => $format_name,
|
||||
'format' => $format_id,
|
||||
);
|
||||
];
|
||||
$edit += $this->selectUnicornEditor();
|
||||
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
|
||||
}
|
||||
|
|
@ -175,7 +175,7 @@ class EditorAdminTest extends WebTestBase {
|
|||
*/
|
||||
protected function enableUnicornEditor() {
|
||||
if (!$this->container->get('module_handler')->moduleExists('editor_test')) {
|
||||
$this->container->get('module_installer')->install(array('editor_test'));
|
||||
$this->container->get('module_installer')->install(['editor_test']);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -200,9 +200,9 @@ class EditorAdminTest extends WebTestBase {
|
|||
$this->assertNoRaw(t('This option is disabled because no modules that provide a text editor are currently enabled.'), 'Description for select absent that tells users to install a text editor module.');
|
||||
|
||||
// Select the "Unicorn Editor" editor and click the "Configure" button.
|
||||
$edit = array(
|
||||
$edit = [
|
||||
'editor[editor]' => 'unicorn',
|
||||
);
|
||||
];
|
||||
$this->drupalPostAjaxForm(NULL, $edit, 'editor_configure');
|
||||
$unicorn_setting = $this->xpath('//input[@name="editor[settings][ponies_too]" and @type="checkbox" and @checked]');
|
||||
$this->assertTrue(count($unicorn_setting), "Unicorn Editor's settings form is present.");
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\editor\Tests;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\editor\Entity\Editor;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Test access to the editor dialog forms.
|
||||
*
|
||||
* @group editor
|
||||
*/
|
||||
class EditorDialogAccessTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['editor', 'filter', 'ckeditor'];
|
||||
|
||||
/**
|
||||
* Test access to the editor image dialog.
|
||||
*/
|
||||
public function testEditorImageDialogAccess() {
|
||||
$url = Url::fromRoute('editor.image_dialog', ['editor' => 'plain_text']);
|
||||
$session = $this->assertSession();
|
||||
|
||||
// With no text editor, expect a 404.
|
||||
$this->drupalGet($url);
|
||||
$session->statusCodeEquals(404);
|
||||
|
||||
// With a text editor but without image upload settings, expect a 200, but
|
||||
// there should not be an input[type=file].
|
||||
$editor = Editor::create([
|
||||
'editor' => 'ckeditor',
|
||||
'format' => 'plain_text',
|
||||
'settings' => [
|
||||
'toolbar' => [
|
||||
'rows' => [
|
||||
[
|
||||
[
|
||||
'name' => 'Media',
|
||||
'items' => [
|
||||
'DrupalImage',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'plugins' => [],
|
||||
],
|
||||
'image_upload' => [
|
||||
'status' => FALSE,
|
||||
'scheme' => 'public',
|
||||
'directory' => 'inline-images',
|
||||
'max_size' => '',
|
||||
'max_dimensions' => [
|
||||
'width' => 0,
|
||||
'height' => 0,
|
||||
],
|
||||
],
|
||||
]);
|
||||
$editor->save();
|
||||
$this->resetAll();
|
||||
$this->drupalGet($url);
|
||||
$this->assertTrue($this->cssSelect('input[type=text][name="attributes[src]"]'), 'Image uploads disabled: input[type=text][name="attributes[src]"] is present.');
|
||||
$this->assertFalse($this->cssSelect('input[type=file]'), 'Image uploads disabled: input[type=file] is absent.');
|
||||
$session->statusCodeEquals(200);
|
||||
|
||||
// With image upload settings, expect a 200, and now there should be an
|
||||
// input[type=file].
|
||||
$editor->setImageUploadSettings(['status' => TRUE] + $editor->getImageUploadSettings())
|
||||
->save();
|
||||
$this->resetAll();
|
||||
$this->drupalGet($url);
|
||||
$this->assertFalse($this->cssSelect('input[type=text][name="attributes[src]"]'), 'Image uploads enabled: input[type=text][name="attributes[src]"] is absent.');
|
||||
$this->assertTrue($this->cssSelect('input[type=file]'), 'Image uploads enabled: input[type=file] is present.');
|
||||
$session->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ class EditorLoadingTest extends WebTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('filter', 'editor', 'editor_test', 'node');
|
||||
public static $modules = ['filter', 'editor', 'editor_test', 'node'];
|
||||
|
||||
/**
|
||||
* An untrusted user, with access to the 'plain_text' format.
|
||||
|
|
@ -51,57 +51,57 @@ class EditorLoadingTest extends WebTestBase {
|
|||
\Drupal::service('plugin.manager.editor')->clearCachedDefinitions();
|
||||
|
||||
// Add text formats.
|
||||
$filtered_html_format = FilterFormat::create(array(
|
||||
$filtered_html_format = FilterFormat::create([
|
||||
'format' => 'filtered_html',
|
||||
'name' => 'Filtered HTML',
|
||||
'weight' => 0,
|
||||
'filters' => array(),
|
||||
));
|
||||
'filters' => [],
|
||||
]);
|
||||
$filtered_html_format->save();
|
||||
$full_html_format = FilterFormat::create(array(
|
||||
$full_html_format = FilterFormat::create([
|
||||
'format' => 'full_html',
|
||||
'name' => 'Full HTML',
|
||||
'weight' => 1,
|
||||
'filters' => array(),
|
||||
));
|
||||
'filters' => [],
|
||||
]);
|
||||
$full_html_format->save();
|
||||
|
||||
// Create article node type.
|
||||
$this->drupalCreateContentType(array(
|
||||
$this->drupalCreateContentType([
|
||||
'type' => 'article',
|
||||
'name' => 'Article',
|
||||
));
|
||||
]);
|
||||
|
||||
// Create page node type, but remove the body.
|
||||
$this->drupalCreateContentType(array(
|
||||
$this->drupalCreateContentType([
|
||||
'type' => 'page',
|
||||
'name' => 'Page',
|
||||
));
|
||||
]);
|
||||
$body = FieldConfig::loadByName('node', 'page', 'body');
|
||||
$body->delete();
|
||||
|
||||
// Create a formatted text field, which uses an <input type="text">.
|
||||
FieldStorageConfig::create(array(
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => 'field_text',
|
||||
'entity_type' => 'node',
|
||||
'type' => 'text',
|
||||
))->save();
|
||||
])->save();
|
||||
|
||||
FieldConfig::create(array(
|
||||
FieldConfig::create([
|
||||
'field_name' => 'field_text',
|
||||
'entity_type' => 'node',
|
||||
'label' => 'Textfield',
|
||||
'bundle' => 'page',
|
||||
))->save();
|
||||
])->save();
|
||||
|
||||
entity_get_form_display('node', 'page', 'default')
|
||||
->setComponent('field_text')
|
||||
->save();
|
||||
|
||||
// Create 3 users, each with access to different text formats.
|
||||
$this->untrustedUser = $this->drupalCreateUser(array('create article content', 'edit any article content'));
|
||||
$this->normalUser = $this->drupalCreateUser(array('create article content', 'edit any article content', 'use text format filtered_html'));
|
||||
$this->privilegedUser = $this->drupalCreateUser(array('create article content', 'edit any article content', 'create page content', 'edit any page content', 'use text format filtered_html', 'use text format full_html'));
|
||||
$this->untrustedUser = $this->drupalCreateUser(['create article content', 'edit any article content']);
|
||||
$this->normalUser = $this->drupalCreateUser(['create article content', 'edit any article content', 'use text format filtered_html']);
|
||||
$this->privilegedUser = $this->drupalCreateUser(['create article content', 'edit any article content', 'create page content', 'edit any page content', 'use text format filtered_html', 'use text format full_html']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -112,13 +112,13 @@ class EditorLoadingTest extends WebTestBase {
|
|||
$editor = Editor::create([
|
||||
'format' => 'full_html',
|
||||
'editor' => 'unicorn',
|
||||
'image_upload' => array(
|
||||
'image_upload' => [
|
||||
'status' => FALSE,
|
||||
'scheme' => file_default_scheme(),
|
||||
'directory' => 'inline-images',
|
||||
'max_size' => '',
|
||||
'max_dimensions' => array('width' => '', 'height' => ''),
|
||||
)
|
||||
'max_dimensions' => ['width' => '', 'height' => ''],
|
||||
]
|
||||
]);
|
||||
$editor->save();
|
||||
|
||||
|
|
@ -140,13 +140,13 @@ class EditorLoadingTest extends WebTestBase {
|
|||
$this->drupalLogin($this->privilegedUser);
|
||||
$this->drupalGet('node/add/article');
|
||||
list($settings, $editor_settings_present, $editor_js_present, $body, $format_selector) = $this->getThingsToCheck('body');
|
||||
$expected = array('formats' => array('full_html' => array(
|
||||
$expected = ['formats' => ['full_html' => [
|
||||
'format' => 'full_html',
|
||||
'editor' => 'unicorn',
|
||||
'editorSettings' => array('ponyModeEnabled' => TRUE),
|
||||
'editorSettings' => ['ponyModeEnabled' => TRUE],
|
||||
'editorSupportsContentFiltering' => TRUE,
|
||||
'isXssSafe' => FALSE,
|
||||
)));
|
||||
]]];
|
||||
$this->assertTrue($editor_settings_present, "Text Editor module's JavaScript settings are on the page.");
|
||||
$this->assertIdentical($expected, $settings['editor'], "Text Editor module's JavaScript settings on the page are correct.");
|
||||
$this->assertTrue($editor_js_present, 'Text Editor JavaScript is present.');
|
||||
|
|
@ -174,13 +174,13 @@ class EditorLoadingTest extends WebTestBase {
|
|||
$this->drupalLogin($this->untrustedUser);
|
||||
$this->drupalGet('node/add/article');
|
||||
list($settings, $editor_settings_present, $editor_js_present, $body, $format_selector) = $this->getThingsToCheck('body');
|
||||
$expected = array('formats' => array('plain_text' => array(
|
||||
$expected = ['formats' => ['plain_text' => [
|
||||
'format' => 'plain_text',
|
||||
'editor' => 'unicorn',
|
||||
'editorSettings' => array('ponyModeEnabled' => TRUE),
|
||||
'editorSettings' => ['ponyModeEnabled' => TRUE],
|
||||
'editorSupportsContentFiltering' => TRUE,
|
||||
'isXssSafe' => FALSE,
|
||||
)));
|
||||
]]];
|
||||
$this->assertTrue($editor_settings_present, "Text Editor module's JavaScript settings are on the page.");
|
||||
$this->assertIdentical($expected, $settings['editor'], "Text Editor module's JavaScript settings on the page are correct.");
|
||||
$this->assertTrue($editor_js_present, 'Text Editor JavaScript is present.');
|
||||
|
|
@ -191,12 +191,12 @@ class EditorLoadingTest extends WebTestBase {
|
|||
|
||||
// Create an "article" node that uses the full_html text format, then try
|
||||
// to let the untrusted user edit it.
|
||||
$this->drupalCreateNode(array(
|
||||
$this->drupalCreateNode([
|
||||
'type' => 'article',
|
||||
'body' => array(
|
||||
array('value' => $this->randomMachineName(32), 'format' => 'full_html')
|
||||
),
|
||||
));
|
||||
'body' => [
|
||||
['value' => $this->randomMachineName(32), 'format' => 'full_html']
|
||||
],
|
||||
]);
|
||||
|
||||
// The untrusted user tries to edit content that is written in a text format
|
||||
// that (s)he is not allowed to use. The editor is still loaded. CKEditor,
|
||||
|
|
@ -220,23 +220,23 @@ class EditorLoadingTest extends WebTestBase {
|
|||
$editor = Editor::create([
|
||||
'format' => 'full_html',
|
||||
'editor' => 'unicorn',
|
||||
'image_upload' => array(
|
||||
'image_upload' => [
|
||||
'status' => FALSE,
|
||||
'scheme' => file_default_scheme(),
|
||||
'directory' => 'inline-images',
|
||||
'max_size' => '',
|
||||
'max_dimensions' => array('width' => '', 'height' => ''),
|
||||
)
|
||||
'max_dimensions' => ['width' => '', 'height' => ''],
|
||||
]
|
||||
]);
|
||||
$editor->save();
|
||||
|
||||
// Create an "page" node that uses the full_html text format.
|
||||
$this->drupalCreateNode(array(
|
||||
$this->drupalCreateNode([
|
||||
'type' => 'page',
|
||||
'field_text' => array(
|
||||
array('value' => $this->randomMachineName(32), 'format' => 'full_html')
|
||||
),
|
||||
));
|
||||
'field_text' => [
|
||||
['value' => $this->randomMachineName(32), 'format' => 'full_html']
|
||||
],
|
||||
]);
|
||||
|
||||
// Assert the unicorn editor works with textfields.
|
||||
$this->drupalLogin($this->privilegedUser);
|
||||
|
|
@ -268,7 +268,7 @@ class EditorLoadingTest extends WebTestBase {
|
|||
|
||||
protected function getThingsToCheck($field_name, $type = 'textarea') {
|
||||
$settings = $this->getDrupalSettings();
|
||||
return array(
|
||||
return [
|
||||
// JavaScript settings.
|
||||
$settings,
|
||||
// Editor.module's JS settings present.
|
||||
|
|
@ -279,7 +279,7 @@ class EditorLoadingTest extends WebTestBase {
|
|||
$this->xpath('//' . $type . '[@id="edit-' . $field_name . '-0-value"]'),
|
||||
// Format selector.
|
||||
$this->xpath('//select[contains(@class, "filter-list")]'),
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,134 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\editor\Tests;
|
||||
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests Editor module's file reference filter with private files.
|
||||
*
|
||||
* @group editor
|
||||
*/
|
||||
class EditorPrivateFileReferenceFilterTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
// Needed for the config: this is the only module in core that utilizes the
|
||||
// functionality in editor.module to be tested, and depends on that.
|
||||
'ckeditor',
|
||||
// Depends on filter.module (indirectly).
|
||||
'node',
|
||||
// Pulls in the config we're using during testing which create a text format
|
||||
// - with the filter_html_image_secure filter DISABLED,
|
||||
// - with the editor set to CKEditor,
|
||||
// - with drupalimage.image_upload.scheme set to 'private',
|
||||
// - with drupalimage.image_upload.directory set to ''.
|
||||
'editor_private_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests the editor file reference filter with private files.
|
||||
*/
|
||||
function testEditorPrivateFileReferenceFilter() {
|
||||
$author = $this->drupalCreateUser();
|
||||
$this->drupalLogin($author);
|
||||
|
||||
// Create a content type with a body field.
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
// Create a file in the 'private:// ' stream.
|
||||
$filename = 'test.png';
|
||||
$src = '/system/files/' . $filename;
|
||||
/** @var \Drupal\file\FileInterface $file */
|
||||
$file = File::create([
|
||||
'uri' => 'private://' . $filename,
|
||||
]);
|
||||
$file->setTemporary();
|
||||
$file->setOwner($author);
|
||||
// Create the file itself.
|
||||
file_put_contents($file->getFileUri(), $this->randomString());
|
||||
$file->save();
|
||||
|
||||
// The image should be visible for its author.
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// The not-yet-permanent image should NOT be visible for anonymous.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Resave the file to be permanent.
|
||||
$file->setPermanent();
|
||||
$file->save();
|
||||
|
||||
// Create some nodes to ensure file usage count does not match the ID's
|
||||
// of the nodes we are going to check.
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$this->drupalCreateNode([
|
||||
'type' => 'page',
|
||||
'uid' => $author->id(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Create a node with its body field properly pointing to the just-created
|
||||
// file.
|
||||
$published_node = $this->drupalCreateNode([
|
||||
'type' => 'page',
|
||||
'body' => [
|
||||
'value' => '<img alt="alt" data-entity-type="file" data-entity-uuid="' . $file->uuid() . '" src="' . $src . '" />',
|
||||
'format' => 'private_images',
|
||||
],
|
||||
'uid' => $author->id(),
|
||||
]);
|
||||
|
||||
// Create an unpublished node with its body field properly pointing to the
|
||||
// just-created file.
|
||||
$unpublished_node = $this->drupalCreateNode([
|
||||
'type' => 'page',
|
||||
'status' => NODE_NOT_PUBLISHED,
|
||||
'body' => [
|
||||
'value' => '<img alt="alt" data-entity-type="file" data-entity-uuid="' . $file->uuid() . '" src="' . $src . '" />',
|
||||
'format' => 'private_images',
|
||||
],
|
||||
'uid' => $author->id(),
|
||||
]);
|
||||
|
||||
// Do the actual test. The image should be visible for anonymous users,
|
||||
// because they can view the published node. Even though they can't view
|
||||
// the unpublished node.
|
||||
$this->drupalGet($published_node->toUrl());
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->drupalGet($unpublished_node->toUrl());
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
// When the published node is also unpublished, the image should also
|
||||
// become inaccessible to anonymous users.
|
||||
$published_node->setPublished(FALSE)->save();
|
||||
|
||||
$this->drupalGet($published_node->toUrl());
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Disallow anonymous users to view the entity, which then should also
|
||||
// disallow them to view the image.
|
||||
$published_node->setPublished(TRUE)->save();
|
||||
Role::load(RoleInterface::ANONYMOUS_ID)
|
||||
->revokePermission('access content')
|
||||
->save();
|
||||
$this->drupalGet($published_node->toUrl());
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ class EditorSecurityTest extends WebTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('filter', 'editor', 'editor_test', 'node');
|
||||
public static $modules = ['filter', 'editor', 'editor_test', 'node'];
|
||||
|
||||
/**
|
||||
* User with access to Restricted HTML text format without text editor.
|
||||
|
|
@ -83,74 +83,74 @@ class EditorSecurityTest extends WebTestBase {
|
|||
// With text formats 2, 3 and 5, we also associate a text editor that does
|
||||
// not guarantee XSS safety. "restricted" means the text format has XSS
|
||||
// filters on output, "unrestricted" means the opposite.
|
||||
$format = FilterFormat::create(array(
|
||||
$format = FilterFormat::create([
|
||||
'format' => 'restricted_without_editor',
|
||||
'name' => 'Restricted HTML, without text editor',
|
||||
'weight' => 0,
|
||||
'filters' => array(
|
||||
'filters' => [
|
||||
// A filter of the FilterInterface::TYPE_HTML_RESTRICTOR type.
|
||||
'filter_html' => array(
|
||||
'filter_html' => [
|
||||
'status' => 1,
|
||||
'settings' => array(
|
||||
'settings' => [
|
||||
'allowed_html' => '<h2> <h3> <h4> <h5> <h6> <p> <br> <strong> <a>',
|
||||
)
|
||||
),
|
||||
),
|
||||
));
|
||||
]
|
||||
],
|
||||
],
|
||||
]);
|
||||
$format->save();
|
||||
$format = FilterFormat::create(array(
|
||||
$format = FilterFormat::create([
|
||||
'format' => 'restricted_with_editor',
|
||||
'name' => 'Restricted HTML, with text editor',
|
||||
'weight' => 1,
|
||||
'filters' => array(
|
||||
'filters' => [
|
||||
// A filter of the FilterInterface::TYPE_HTML_RESTRICTOR type.
|
||||
'filter_html' => array(
|
||||
'filter_html' => [
|
||||
'status' => 1,
|
||||
'settings' => array(
|
||||
'settings' => [
|
||||
'allowed_html' => '<h2> <h3> <h4> <h5> <h6> <p> <br> <strong> <a>',
|
||||
)
|
||||
),
|
||||
),
|
||||
));
|
||||
]
|
||||
],
|
||||
],
|
||||
]);
|
||||
$format->save();
|
||||
$editor = Editor::create([
|
||||
'format' => 'restricted_with_editor',
|
||||
'editor' => 'unicorn',
|
||||
]);
|
||||
$editor->save();
|
||||
$format = FilterFormat::create(array(
|
||||
$format = FilterFormat::create([
|
||||
'format' => 'restricted_plus_dangerous_tag_with_editor',
|
||||
'name' => 'Restricted HTML, dangerous tag allowed, with text editor',
|
||||
'weight' => 1,
|
||||
'filters' => array(
|
||||
'filters' => [
|
||||
// A filter of the FilterInterface::TYPE_HTML_RESTRICTOR type.
|
||||
'filter_html' => array(
|
||||
'filter_html' => [
|
||||
'status' => 1,
|
||||
'settings' => array(
|
||||
'settings' => [
|
||||
'allowed_html' => '<h2> <h3> <h4> <h5> <h6> <p> <br> <strong> <a> <embed>',
|
||||
)
|
||||
),
|
||||
),
|
||||
));
|
||||
]
|
||||
],
|
||||
],
|
||||
]);
|
||||
$format->save();
|
||||
$editor = Editor::create([
|
||||
'format' => 'restricted_plus_dangerous_tag_with_editor',
|
||||
'editor' => 'unicorn',
|
||||
]);
|
||||
$editor->save();
|
||||
$format = FilterFormat::create(array(
|
||||
$format = FilterFormat::create([
|
||||
'format' => 'unrestricted_without_editor',
|
||||
'name' => 'Unrestricted HTML, without text editor',
|
||||
'weight' => 0,
|
||||
'filters' => array(),
|
||||
));
|
||||
'filters' => [],
|
||||
]);
|
||||
$format->save();
|
||||
$format = FilterFormat::create(array(
|
||||
$format = FilterFormat::create([
|
||||
'format' => 'unrestricted_with_editor',
|
||||
'name' => 'Unrestricted HTML, with text editor',
|
||||
'weight' => 1,
|
||||
'filters' => array(),
|
||||
));
|
||||
'filters' => [],
|
||||
]);
|
||||
$format->save();
|
||||
$editor = Editor::create([
|
||||
'format' => 'unrestricted_with_editor',
|
||||
|
|
@ -160,10 +160,10 @@ class EditorSecurityTest extends WebTestBase {
|
|||
|
||||
|
||||
// Create node type.
|
||||
$this->drupalCreateContentType(array(
|
||||
$this->drupalCreateContentType([
|
||||
'type' => 'article',
|
||||
'name' => 'Article',
|
||||
));
|
||||
]);
|
||||
|
||||
// Create 4 users, each with access to different text formats/editors:
|
||||
// - "untrusted": restricted_without_editor
|
||||
|
|
@ -172,22 +172,22 @@ class EditorSecurityTest extends WebTestBase {
|
|||
// - "privileged": restricted_without_editor, restricted_with_editor,
|
||||
// restricted_plus_dangerous_tag_with_editor,
|
||||
// unrestricted_without_editor and unrestricted_with_editor
|
||||
$this->untrustedUser = $this->drupalCreateUser(array(
|
||||
$this->untrustedUser = $this->drupalCreateUser([
|
||||
'create article content',
|
||||
'edit any article content',
|
||||
'use text format restricted_without_editor',
|
||||
));
|
||||
$this->normalUser = $this->drupalCreateUser(array(
|
||||
]);
|
||||
$this->normalUser = $this->drupalCreateUser([
|
||||
'create article content',
|
||||
'edit any article content',
|
||||
'use text format restricted_with_editor',
|
||||
));
|
||||
$this->trustedUser = $this->drupalCreateUser(array(
|
||||
]);
|
||||
$this->trustedUser = $this->drupalCreateUser([
|
||||
'create article content',
|
||||
'edit any article content',
|
||||
'use text format restricted_plus_dangerous_tag_with_editor',
|
||||
));
|
||||
$this->privilegedUser = $this->drupalCreateUser(array(
|
||||
]);
|
||||
$this->privilegedUser = $this->drupalCreateUser([
|
||||
'create article content',
|
||||
'edit any article content',
|
||||
'use text format restricted_without_editor',
|
||||
|
|
@ -195,25 +195,25 @@ class EditorSecurityTest extends WebTestBase {
|
|||
'use text format restricted_plus_dangerous_tag_with_editor',
|
||||
'use text format unrestricted_without_editor',
|
||||
'use text format unrestricted_with_editor',
|
||||
));
|
||||
]);
|
||||
|
||||
// Create an "article" node for each possible text format, with the same
|
||||
// sample content, to do our tests on.
|
||||
$samples = array(
|
||||
array('author' => $this->untrustedUser->id(), 'format' => 'restricted_without_editor'),
|
||||
array('author' => $this->normalUser->id(), 'format' => 'restricted_with_editor'),
|
||||
array('author' => $this->trustedUser->id(), 'format' => 'restricted_plus_dangerous_tag_with_editor'),
|
||||
array('author' => $this->privilegedUser->id(), 'format' => 'unrestricted_without_editor'),
|
||||
array('author' => $this->privilegedUser->id(), 'format' => 'unrestricted_with_editor'),
|
||||
);
|
||||
$samples = [
|
||||
['author' => $this->untrustedUser->id(), 'format' => 'restricted_without_editor'],
|
||||
['author' => $this->normalUser->id(), 'format' => 'restricted_with_editor'],
|
||||
['author' => $this->trustedUser->id(), 'format' => 'restricted_plus_dangerous_tag_with_editor'],
|
||||
['author' => $this->privilegedUser->id(), 'format' => 'unrestricted_without_editor'],
|
||||
['author' => $this->privilegedUser->id(), 'format' => 'unrestricted_with_editor'],
|
||||
];
|
||||
foreach ($samples as $sample) {
|
||||
$this->drupalCreateNode(array(
|
||||
$this->drupalCreateNode([
|
||||
'type' => 'article',
|
||||
'body' => array(
|
||||
array('value' => self::$sampleContent, 'format' => $sample['format'])
|
||||
),
|
||||
'body' => [
|
||||
['value' => self::$sampleContent, 'format' => $sample['format']]
|
||||
],
|
||||
'uid' => $sample['author']
|
||||
));
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,65 +222,65 @@ class EditorSecurityTest extends WebTestBase {
|
|||
*
|
||||
* Tests 8 scenarios. Tests only with a text editor that is not XSS-safe.
|
||||
*/
|
||||
function testInitialSecurity() {
|
||||
$expected = array(
|
||||
array(
|
||||
public function testInitialSecurity() {
|
||||
$expected = [
|
||||
[
|
||||
'node_id' => 1,
|
||||
'format' => 'restricted_without_editor',
|
||||
// No text editor => no XSS filtering.
|
||||
'value' => self::$sampleContent,
|
||||
'users' => array(
|
||||
'users' => [
|
||||
$this->untrustedUser,
|
||||
$this->privilegedUser,
|
||||
),
|
||||
),
|
||||
array(
|
||||
],
|
||||
],
|
||||
[
|
||||
'node_id' => 2,
|
||||
'format' => 'restricted_with_editor',
|
||||
// Text editor => XSS filtering.
|
||||
'value' => self::$sampleContentSecured,
|
||||
'users' => array(
|
||||
'users' => [
|
||||
$this->normalUser,
|
||||
$this->privilegedUser,
|
||||
),
|
||||
),
|
||||
array(
|
||||
],
|
||||
],
|
||||
[
|
||||
'node_id' => 3,
|
||||
'format' => 'restricted_plus_dangerous_tag_with_editor',
|
||||
// Text editor => XSS filtering.
|
||||
'value' => self::$sampleContentSecuredEmbedAllowed,
|
||||
'users' => array(
|
||||
'users' => [
|
||||
$this->trustedUser,
|
||||
$this->privilegedUser,
|
||||
),
|
||||
),
|
||||
array(
|
||||
],
|
||||
],
|
||||
[
|
||||
'node_id' => 4,
|
||||
'format' => 'unrestricted_without_editor',
|
||||
// No text editor => no XSS filtering.
|
||||
'value' => self::$sampleContent,
|
||||
'users' => array(
|
||||
'users' => [
|
||||
$this->privilegedUser,
|
||||
),
|
||||
),
|
||||
array(
|
||||
],
|
||||
],
|
||||
[
|
||||
'node_id' => 5,
|
||||
'format' => 'unrestricted_with_editor',
|
||||
// Text editor, no security filter => no XSS filtering.
|
||||
'value' => self::$sampleContent,
|
||||
'users' => array(
|
||||
'users' => [
|
||||
$this->privilegedUser,
|
||||
),
|
||||
),
|
||||
);
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Log in as each user that may edit the content, and assert the value.
|
||||
foreach ($expected as $case) {
|
||||
foreach ($case['users'] as $account) {
|
||||
$this->pass(format_string('Scenario: sample %sample_id, %format.', array(
|
||||
$this->pass(format_string('Scenario: sample %sample_id, %format.', [
|
||||
'%sample_id' => $case['node_id'],
|
||||
'%format' => $case['format'],
|
||||
)));
|
||||
]));
|
||||
$this->drupalLogin($account);
|
||||
$this->drupalGet('node/' . $case['node_id'] . '/edit');
|
||||
$dom_node = $this->xpath('//textarea[@id="edit-body-0-value"]');
|
||||
|
|
@ -302,26 +302,26 @@ class EditorSecurityTest extends WebTestBase {
|
|||
* format and contains a <script> tag to the Full HTML text format, the
|
||||
* <script> tag would be executed. Unless we apply appropriate filtering.
|
||||
*/
|
||||
function testSwitchingSecurity() {
|
||||
$expected = array(
|
||||
array(
|
||||
public function testSwitchingSecurity() {
|
||||
$expected = [
|
||||
[
|
||||
'node_id' => 1,
|
||||
'value' => self::$sampleContent, // No text editor => no XSS filtering.
|
||||
'format' => 'restricted_without_editor',
|
||||
'switch_to' => array(
|
||||
'switch_to' => [
|
||||
'restricted_with_editor' => self::$sampleContentSecured,
|
||||
// Intersection of restrictions => most strict XSS filtering.
|
||||
'restricted_plus_dangerous_tag_with_editor' => self::$sampleContentSecured,
|
||||
// No text editor => no XSS filtering.
|
||||
'unrestricted_without_editor' => FALSE,
|
||||
'unrestricted_with_editor' => self::$sampleContentSecured,
|
||||
),
|
||||
),
|
||||
array(
|
||||
],
|
||||
],
|
||||
[
|
||||
'node_id' => 2,
|
||||
'value' => self::$sampleContentSecured, // Text editor => XSS filtering.
|
||||
'format' => 'restricted_with_editor',
|
||||
'switch_to' => array(
|
||||
'switch_to' => [
|
||||
// No text editor => no XSS filtering.
|
||||
'restricted_without_editor' => FALSE,
|
||||
// Intersection of restrictions => most strict XSS filtering.
|
||||
|
|
@ -329,13 +329,13 @@ class EditorSecurityTest extends WebTestBase {
|
|||
// No text editor => no XSS filtering.
|
||||
'unrestricted_without_editor' => FALSE,
|
||||
'unrestricted_with_editor' => self::$sampleContentSecured,
|
||||
),
|
||||
),
|
||||
array(
|
||||
],
|
||||
],
|
||||
[
|
||||
'node_id' => 3,
|
||||
'value' => self::$sampleContentSecuredEmbedAllowed, // Text editor => XSS filtering.
|
||||
'format' => 'restricted_plus_dangerous_tag_with_editor',
|
||||
'switch_to' => array(
|
||||
'switch_to' => [
|
||||
// No text editor => no XSS filtering.
|
||||
'restricted_without_editor' => FALSE,
|
||||
// Intersection of restrictions => most strict XSS filtering.
|
||||
|
|
@ -344,13 +344,13 @@ class EditorSecurityTest extends WebTestBase {
|
|||
'unrestricted_without_editor' => FALSE,
|
||||
// Intersection of restrictions => most strict XSS filtering.
|
||||
'unrestricted_with_editor' => self::$sampleContentSecured,
|
||||
),
|
||||
),
|
||||
array(
|
||||
],
|
||||
],
|
||||
[
|
||||
'node_id' => 4,
|
||||
'value' => self::$sampleContent, // No text editor => no XSS filtering.
|
||||
'format' => 'unrestricted_without_editor',
|
||||
'switch_to' => array(
|
||||
'switch_to' => [
|
||||
// No text editor => no XSS filtering.
|
||||
'restricted_without_editor' => FALSE,
|
||||
'restricted_with_editor' => self::$sampleContentSecured,
|
||||
|
|
@ -360,13 +360,13 @@ class EditorSecurityTest extends WebTestBase {
|
|||
// filters: resulting content when viewed was already vulnerable, so
|
||||
// it must be intentional.
|
||||
'unrestricted_with_editor' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
],
|
||||
],
|
||||
[
|
||||
'node_id' => 5,
|
||||
'value' => self::$sampleContentSecured, // Text editor => XSS filtering.
|
||||
'format' => 'unrestricted_with_editor',
|
||||
'switch_to' => array(
|
||||
'switch_to' => [
|
||||
// From editor, no security filters to security filters, no editor: no
|
||||
// risk.
|
||||
'restricted_without_editor' => FALSE,
|
||||
|
|
@ -377,9 +377,9 @@ class EditorSecurityTest extends WebTestBase {
|
|||
// filters: resulting content when viewed was already vulnerable, so
|
||||
// it must be intentional.
|
||||
'unrestricted_without_editor' => FALSE,
|
||||
),
|
||||
),
|
||||
);
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Log in as the privileged user, and for every sample, do the following:
|
||||
// - switch to every other text format/editor
|
||||
|
|
@ -395,15 +395,15 @@ class EditorSecurityTest extends WebTestBase {
|
|||
|
||||
// Switch to every other text format/editor and verify the results.
|
||||
foreach ($case['switch_to'] as $format => $expected_filtered_value) {
|
||||
$this->pass(format_string('Scenario: sample %sample_id, switch from %original_format to %format.', array(
|
||||
$this->pass(format_string('Scenario: sample %sample_id, switch from %original_format to %format.', [
|
||||
'%sample_id' => $case['node_id'],
|
||||
'%original_format' => $case['format'],
|
||||
'%format' => $format,
|
||||
)));
|
||||
$post = array(
|
||||
]));
|
||||
$post = [
|
||||
'value' => self::$sampleContent,
|
||||
'original_format_id' => $case['format'],
|
||||
);
|
||||
];
|
||||
$response = $this->drupalPostWithFormat('editor/filter_xss/' . $format, 'json', $post);
|
||||
$this->assertResponse(200);
|
||||
$json = Json::decode($response);
|
||||
|
|
@ -415,7 +415,7 @@ class EditorSecurityTest extends WebTestBase {
|
|||
/**
|
||||
* Tests the standard text editor XSS filter being overridden.
|
||||
*/
|
||||
function testEditorXssFilterOverride() {
|
||||
public function testEditorXssFilterOverride() {
|
||||
// First: the Standard text editor XSS filter.
|
||||
$this->drupalLogin($this->normalUser);
|
||||
$this->drupalGet('node/2/edit');
|
||||
|
|
|
|||
|
|
@ -19,47 +19,47 @@ class QuickEditIntegrationLoadingTest extends WebTestBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('quickedit', 'filter', 'node', 'editor');
|
||||
public static $modules = ['quickedit', 'filter', 'node', 'editor'];
|
||||
|
||||
/**
|
||||
* The basic permissions necessary to view content and use in-place editing.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $basicPermissions = array('access content', 'create article content', 'use text format filtered_html', 'access contextual links');
|
||||
protected static $basicPermissions = ['access content', 'create article content', 'use text format filtered_html', 'access contextual links'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create a text format.
|
||||
$filtered_html_format = FilterFormat::create(array(
|
||||
$filtered_html_format = FilterFormat::create([
|
||||
'format' => 'filtered_html',
|
||||
'name' => 'Filtered HTML',
|
||||
'weight' => 0,
|
||||
'filters' => array(
|
||||
'filter_caption' => array(
|
||||
'filters' => [
|
||||
'filter_caption' => [
|
||||
'status' => 1,
|
||||
),
|
||||
),
|
||||
));
|
||||
],
|
||||
],
|
||||
]);
|
||||
$filtered_html_format->save();
|
||||
|
||||
// Create a node type.
|
||||
$this->drupalCreateContentType(array(
|
||||
$this->drupalCreateContentType([
|
||||
'type' => 'article',
|
||||
'name' => 'Article',
|
||||
));
|
||||
]);
|
||||
|
||||
// Create one node of the above node type using the above text format.
|
||||
$this->drupalCreateNode(array(
|
||||
$this->drupalCreateNode([
|
||||
'type' => 'article',
|
||||
'body' => array(
|
||||
0 => array(
|
||||
'body' => [
|
||||
0 => [
|
||||
'value' => '<p>Do you also love Drupal?</p><img src="druplicon.png" data-caption="Druplicon" />',
|
||||
'format' => 'filtered_html',
|
||||
)
|
||||
)
|
||||
));
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -70,11 +70,11 @@ class QuickEditIntegrationLoadingTest extends WebTestBase {
|
|||
// or both of the following permissions:
|
||||
// - the 'access in-place editing' permission
|
||||
// - the 'edit any article content' permission (necessary to edit node 1)
|
||||
$users = array(
|
||||
$users = [
|
||||
$this->drupalCreateUser(static::$basicPermissions),
|
||||
$this->drupalCreateUser(array_merge(static::$basicPermissions, array('edit any article content'))),
|
||||
$this->drupalCreateUser(array_merge(static::$basicPermissions, array('access in-place editing')))
|
||||
);
|
||||
$this->drupalCreateUser(array_merge(static::$basicPermissions, ['edit any article content'])),
|
||||
$this->drupalCreateUser(array_merge(static::$basicPermissions, ['access in-place editing']))
|
||||
];
|
||||
|
||||
// Now test with each of the 3 users with insufficient permissions.
|
||||
foreach ($users as $user) {
|
||||
|
|
@ -84,10 +84,17 @@ class QuickEditIntegrationLoadingTest extends WebTestBase {
|
|||
// Ensure the text is transformed.
|
||||
$this->assertRaw('<p>Do you also love Drupal?</p><figure role="group" class="caption caption-img"><img src="druplicon.png" /><figcaption>Druplicon</figcaption></figure>');
|
||||
|
||||
// Retrieving the untransformed text should result in an empty 403 response.
|
||||
$response = $this->drupalPost('editor/' . 'node/1/body/en/full', '', array(), array('query' => array(MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax')));
|
||||
// Retrieving the untransformed text should result in an 403 response and
|
||||
// return a different error message depending of the missing permission.
|
||||
$response = $this->drupalPost('editor/' . 'node/1/body/en/full', '', [], ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]);
|
||||
$this->assertResponse(403);
|
||||
$this->assertIdentical('{}', $response);
|
||||
if (!$user->hasPermission('access in-place editing')) {
|
||||
$message = "A fatal error occurred: The 'access in-place editing' permission is required.";
|
||||
$this->assertIdentical(Json::encode(['message' => $message]), $response);
|
||||
}
|
||||
else {
|
||||
$this->assertIdentical('{}', $response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +102,7 @@ class QuickEditIntegrationLoadingTest extends WebTestBase {
|
|||
* Test loading of untransformed text when a user does have access to it.
|
||||
*/
|
||||
public function testUserWithPermission() {
|
||||
$user = $this->drupalCreateUser(array_merge(static::$basicPermissions, array('edit any article content', 'access in-place editing')));
|
||||
$user = $this->drupalCreateUser(array_merge(static::$basicPermissions, ['edit any article content', 'access in-place editing']));
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet('node/1');
|
||||
|
||||
|
|
|
|||
Reference in a new issue