Skip to content
Snippets Groups Projects
Commit d2cc667e authored by Luke Leber's avatar Luke Leber
Browse files

Issue #3336274 by Luke.Leber: Add configurable option to retain inline style attributes

parent e5838c39
No related branches found
No related tags found
1 merge request!6Issue #3336274: Add configurable option to retain inline style attributes
......@@ -7,3 +7,4 @@ raw_html_strip_contextual_links: true
raw_html_strip_js_view_dom_id: true
raw_html_strip_comments: true
raw_html_highlight_style: ''
visual_html5_preserve_inline_styles: true
......@@ -28,3 +28,6 @@ diff_plus.settings:
raw_html_strip_comments:
type: boolean
label: 'Raw HTML strip comments'
visual_html5_preserve_inline_styles:
type: boolean
label: 'Visual Inline HTML5 preserve inline styles'
......@@ -52,6 +52,7 @@ abstract class DiffPlusSettingsFormBase extends FormBase {
'raw_html_strip_js_view_dom_id' => TRUE,
'raw_html_strip_comments' => TRUE,
'raw_html_highlight_style' => '',
'visual_html5_preserve_inline_styles' => TRUE,
];
}
......@@ -81,6 +82,17 @@ abstract class DiffPlusSettingsFormBase extends FormBase {
'#default_value' => $default_values['enhance_diff_ui'],
];
$form['visual_html5'] = [
'#type' => 'fieldset',
'#title' => $this->t('Customize the <em>Visual Inline (HTML5) diff display'),
];
$form['visual_html5']['visual_html5_preserve_inline_styles'] = [
'#type' => 'checkbox',
'#title' => $this->t('Preserve inline CSS styles'),
'#default_value' => $default_values['visual_html5_preserve_inline_styles'],
];
$form['raw_html'] = [
'#type' => 'fieldset',
'#title' => $this->t('Customize the <em>Raw HTML</em> diff display'),
......
......@@ -41,25 +41,78 @@ class VisualInlineHtml5DiffLayout extends VisualInlineDiffLayout {
'wbr',
];
/**
* The config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* The user data service.
*
* @var \Drupal\user\UserDataInterface
*/
protected $userData;
/**
* The account switcher service.
*
* @var \Drupal\Core\Session\AccountSwitcherInterface
*/
protected $accountSwitcher;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->htmlDiff->getConfig()->setPurifierEnabled(FALSE);
$instance->configFactory = $container->get('config.factory');
$instance->currentUser = $container->get('current_user');
$instance->userData = $container->get('user.data');
$instance->accountSwitcher = $container->get('account_switcher');
return $instance;
}
/**
* Gets the settings to render the diff with.
*
* @return array
* The settings to render the diff with.
*/
protected function getDiffSettings() {
$settings = $this->configFactory->get('diff_plus.settings')->get();
if ($this->currentUser->hasPermission('personalize diff plus settings')) {
$settings = array_replace_recursive(
$settings,
$this->userData->get('diff_plus', $this->currentUser->id(), 'settings') ?? []
);
}
return $settings;
}
/**
* Preprocesses the provided markup to provide a normalization layer.
*
* @param string $markup
* The markup to normalize.
* @param array $settings
* The diff layout settings.
*
* @return string
* The normalized markup.
*/
protected function preprocessMarkup($markup) {
protected function preprocessMarkup($markup, array $settings) {
// The diff library has issues with comments, so strip them.
$dom = Html::load($markup);
......@@ -67,6 +120,18 @@ class VisualInlineHtml5DiffLayout extends VisualInlineDiffLayout {
foreach ($xpath->query('//comment()') as $element) {
$element->parentNode->removeChild($element);
}
// Work around a bug in Xss::filter.
if ($settings['visual_html5_preserve_inline_styles']) {
$elements_with_inline_styles = $xpath->query('//*[@style]');
foreach ($elements_with_inline_styles as $element_with_inline_styles) {
$element_with_inline_styles->setAttribute(
'data-diff-plus-style',
$element_with_inline_styles->getAttribute('style')
);
}
}
return Html::serialize($dom);
}
......@@ -87,28 +152,42 @@ class VisualInlineHtml5DiffLayout extends VisualInlineDiffLayout {
);
}
$settings = $this->getDiffSettings();
// Swap out the stock visual diff with a new one.
$this->htmlDiff->setOldHtml(
$this->preprocessMarkup(
$this->htmlDiff->getOldHtml()
$this->htmlDiff->getOldHtml(),
$settings
)
);
$this->htmlDiff->setNewHtml(
$this->preprocessMarkup(
$this->htmlDiff->getNewHtml()
$this->htmlDiff->getNewHtml(),
$settings
)
);
$this->htmlDiff->build();
$markup = Xss::filter($this->htmlDiff->getDifference(), static::HTML5_TAGS);
if ($settings['visual_html5_preserve_inline_styles']) {
$dom = Html::load($markup);
$xpath = new \DOMXPath($dom);
$elements_with_inline_styles = $xpath->query('//*[@data-diff-plus-style]');
foreach ($elements_with_inline_styles as $element_with_inline_styles) {
$element_with_inline_styles->setAttribute(
'style',
$element_with_inline_styles->getAttribute('data-diff-plus-style')
);
}
$markup = Html::serialize($dom);
}
// @todo Ask the security team about whether this is 100% safe.
$build['diff']['#markup'] = Markup::create(
Xss::filter(
$this->htmlDiff->getDifference(),
static::HTML5_TAGS
),
);
$build['diff']['#markup'] = Markup::create($markup);
return $build;
}
......
......@@ -26,6 +26,7 @@ class DiffPlusDefaultSettingsFormTest extends BrowserTestBase {
'raw_html_strip_js_view_dom_id' => TRUE,
'raw_html_strip_comments' => TRUE,
'raw_html_highlight_style' => '',
'visual_html5_preserve_inline_styles' => TRUE,
];
/**
......@@ -43,6 +44,7 @@ class DiffPlusDefaultSettingsFormTest extends BrowserTestBase {
'raw_html_strip_js_view_dom_id' => FALSE,
'raw_html_strip_comments' => FALSE,
'raw_html_highlight_style' => 'github.min.css',
'visual_html5_preserve_inline_styles' => FALSE,
];
......
......@@ -26,6 +26,7 @@ class DiffPlusUserSettingsFormTest extends BrowserTestBase {
'raw_html_strip_js_view_dom_id' => TRUE,
'raw_html_strip_comments' => TRUE,
'raw_html_highlight_style' => '',
'visual_html5_preserve_inline_styles' => TRUE,
];
/**
......@@ -43,7 +44,7 @@ class DiffPlusUserSettingsFormTest extends BrowserTestBase {
'raw_html_strip_js_view_dom_id' => FALSE,
'raw_html_strip_comments' => TRUE,
'raw_html_highlight_style' => 'a11y-dark.min.css',
'visual_html5_preserve_inline_styles' => FALSE,
];
/**
......@@ -61,7 +62,7 @@ class DiffPlusUserSettingsFormTest extends BrowserTestBase {
'raw_html_strip_js_view_dom_id' => FALSE,
'raw_html_strip_comments' => FALSE,
'raw_html_highlight_style' => 'github.min.css',
'visual_html5_preserve_inline_styles' => TRUE,
];
/**
......
......@@ -73,7 +73,7 @@ class DiffPlusVisualInlineHtml5DiffLayoutTest extends WebDriverTestBase {
]);
$node->set('body', [
'value' => '<p>This is a test!</p><p>This is a test too!</p>',
'value' => '<p>This is a test!</p><p style="color:red">This is a test too!</p>',
'format' => 'unrestricted_html',
]);
$node->setNewRevision();
......@@ -83,13 +83,26 @@ class DiffPlusVisualInlineHtml5DiffLayoutTest extends WebDriverTestBase {
/**
* Test case for the Raw HTML diff layout.
*/
public function testRawHtmlLayoutPlugin() {
public function testVisualInlineHtml5LayoutPlugin() {
$this->drupalLogin($this->drupalCreateUser([], NULL, TRUE));
$this->drupalGet('/node/1/revisions/view/1/2/visual_inline_html5');
$page = $this->getSession()->getPage();
$insertion = $page->find('css', '.diffins');
static::assertSame('This is a test too!', $insertion->getText());
// Ensure that the style is not stripped by default.
static::assertNotNull($page->find('css', '[style="color:red"]'));
$this->config('diff_plus.settings')
->set('visual_html5_preserve_inline_styles', FALSE)
->save();
$this->drupalGet('/node/1/revisions/view/1/2/visual_inline_html5');
$page = $this->getSession()->getPage();
// Ensure that the style is now stripped.
static::assertNull($page->find('css', '[style="color:red"]'));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment