Commit ed87f626 authored by Ivan Doroshenko's avatar Ivan Doroshenko
Browse files

WIP - expand/collapse block content.

parent 9b4b508d
id: uw_layout_builder_sections_expandable
label: Layout builder sections (expandable groups)
migration_tags:
- Drupal 7
- Content
- Layout Builder
deriver: Drupal\uw_migrate\Plugin\migrate\UwLayoutBuilderDeriver
source:
plugin: uw_layout
expandable: true
fields:
- entity_id
id_fields:
entity_id:
type: integer
delta:
type: integer
ignore_map: true
conditions:
- field: t.entity_id
value: 82
process:
nid:
- plugin: migration_lookup
migration: uw_ct_expandable_group
source:
- entity_id
- delta
no_stub: true
- plugin: skip_on_empty
method: row
message: 'Destination node was not found.'
layout: layout
layout_settings: layout_settings
section: delta
destination:
plugin: layout_builder:section
migration_dependencies:
optional: {}
id: uw_ct_expandable_group
label: 'Expand/collapse groups'
migration_tags:
- Drupal 7
- Content
deriver: Drupal\uw_migrate\Plugin\migrate\UwContentFieldsDeriver
source:
plugin: uw_expandable_group
fields:
- entity_id
id_fields:
entity_id:
type: integer
delta:
type: integer
ignore_map: true
process:
title:
plugin: callback
callable: strip_tags
source: title
uid:
- plugin: migration_lookup
migration: uw_user
source: node_uid
no_stub: true
- plugin: default_value
default_value: 0
langcode:
plugin: default_value
source: language
default_value: "und"
status: status
moderation_state:
plugin: static_map
source: status
map:
'0': draft
'1': published
default_value: draft
created: created
changed: changed
promote: promote
sticky: sticky
revision_uid:
- plugin: migration_lookup
migration: uw_user
source: revision_uid
no_stub: true
- plugin: default_value
default_value: 0
revision_log: log
revision_timestamp: timestamp
destination:
plugin: entity:node
default_bundle: uw_ct_expand_collapse_group
......@@ -73,9 +73,22 @@ class UwContentFieldsDeriver extends DeriverBase implements ContainerDeriverInte
$values['process']['pseudo_field_uw_cta_details']['migration'] = 'uw_para_call_to_action:' . $field_name;
}
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($values);
$this->derivatives[$field_name] = $migration->getPluginDefinition();
// For some migrations, we have to split migration into 2 groups.
if (in_array($base_plugin_definition['id'], ['uw_cbl_blockquote', 'uw_cbl_copy_text'])) {
// Expandable groups content.
$values['source']['expandable'] = FALSE;
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($values);
$this->derivatives[$field_name] = $migration->getPluginDefinition();
// Non-expandable groups content.
$values['source']['expandable'] = TRUE;
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($values);
$this->derivatives[$field_name . '_expandable'] = $migration->getPluginDefinition();
}
else {
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($values);
$this->derivatives[$field_name] = $migration->getPluginDefinition();
}
}
return $this->derivatives;
......
......@@ -96,7 +96,9 @@ class UwLayoutBuilderDeriver extends DeriverBase implements ContainerDeriverInte
$values['source']['fields'][] = $value_column;
// Specify content migrations.
$values['process']['nid'][0]['migration'] = $data['content_migrations'];
if ($values['process']['nid'][0]['migration'] !== 'placeholder') {
$values['process']['nid'][0]['migration'] = $data['content_migrations'];
}
$values['migration_dependencies']['optional'] += $data['content_migrations'];
if (isset($values['process']['bid'])) {
......
......@@ -23,10 +23,11 @@ class UwContentComplete extends UwEmbeddedContent {
$iterator = parent::initializeIterator();
$content_col = $this->configuration['content_column'];
$format_col = $this->configuration['format_column'] ?? str_replace('value', 'format', $content_col);
$expandable = $this->configuration['expandable'];
$new_rows = [];
foreach ($iterator as $row) {
$layout_sections = $this->parser->getLayoutItems($row[$content_col]);
$layout_sections = $this->parser->getLayoutItems($row[$content_col], $expandable);
$delta = 0;
foreach ($layout_sections as $section_delta => $section) {
......
<?php
namespace Drupal\uw_migrate\Plugin\migrate\source;
/**
* Source plugin for retrieving expand/collapse groups from content.
*
* @MigrateSource(
* id = "uw_expandable_group",
* source_module = "system"
* )
*/
class UwExpandableGroups extends UwEmbeddedContent {
/**
* {@inheritdoc}
*/
protected function getItems($content) {
return $this->parser->getExpandableGroups($content);
}
}
......@@ -22,10 +22,12 @@ class UwLayout extends UwEmbeddedContent {
protected function initializeIterator() {
$iterator = parent::initializeIterator();
$content_col = $this->configuration['content_column'];
$expandable = $this->configuration['expandable'];
$new_rows = [];
foreach ($iterator as $row) {
$layout_sections = $this->parser->getLayoutItems($row[$content_col]);
$original_content = $row[$content_col];
$layout_sections = $this->parser->getLayoutItems($original_content, $expandable);
foreach ($layout_sections as $delta => $section) {
$new_row = $row;
......
......@@ -12,6 +12,8 @@ class UwContentParser {
use UwMigrateTrait;
const EXPANDABLE_XPATH = "//div[contains(@class, 'expandable')][not(ancestor::div[contains(@class, 'expandable')])]";
/**
* Returns a list of content sections for the given HTML string.
*
......@@ -34,7 +36,7 @@ class UwContentParser {
$parts = explode($delimiter, $content);
// Append previous section if there is some meaningful content there.
if ($this->clean($parts[0])) {
if ($this->clean($parts[0], TRUE, TRUE)) {
$sections[] = $parts[0];
}
......@@ -167,12 +169,60 @@ class UwContentParser {
return $result;
}
public function getExpandableGroups($content) {
$results = [];
$crawler = new Crawler($content);
// Get all <div class="expandable"></div> items, that are not children of
// other expandable divs.
$groups = $crawler->filterXPath(static::EXPANDABLE_XPATH);
foreach ($groups as $delta => $element) {
$expandable_group = new Crawler($element);
$title = $expandable_group->filterXPath('(//h2)[1]');
$content = $expandable_group->filterXPath("//div[@class='expandable-content']");
$results[] = [
'delta' => $delta,
// First occurrence of h2 title is supposed to be a group title.
'title' => $title ? $this->getInnerHtml($title->getNode(0)) : '',
'content' => $content ? $this->getInnerHtml($content->getNode(0)) : '',
];
}
return $results;
}
/**
* Returns a list of formatted content items and their layout settings.
*/
public function getLayoutItems($content) {
$result = [];
$layout_sections = $this->getContentSections($content, $this->getLayoutsRegex());
public function getLayoutItems($content, $expandable = NULL) {
$result = $layout_sections = [];
// If "expandable" value is provided, then either get expandable content
// or everything else, which is outside of those groups.
if ($expandable !== NULL) {
$crawler = new Crawler($content);
if ($expandable) {
// Get only "expandable" sections.
foreach ($crawler->filterXPath(static::EXPANDABLE_XPATH) as $group_delta => $element) {
$expandable_group = new Crawler($element);
$group_content = $expandable_group->filterXPath("//div[@class='expandable-content']");
$layout_sections[$group_delta] = $this->getContentSections($this->getInnerHtml($group_content->getNode(0)), $this->getLayoutsRegex());
}
}
// Remove "expandable" content sections.
else {
$crawler->filterXPath("//div[contains(@class, 'expandable')]")->each(function ($crawler) {
foreach ($crawler as $node) {
$node->parentNode->removeChild($node);
}
});
$content = $crawler->outerHtml();
$layout_sections = $this->getContentSections($content, $this->getLayoutsRegex());
}
}
else {
$layout_sections = $this->getContentSections($content, $this->getLayoutsRegex());
}
/** @var \DOMElement $element */
$section = [];
......@@ -180,7 +230,7 @@ class UwContentParser {
$layout_data = $this->getSectionData($layout_section);
// Skip if section content is empty.
if (empty($this->clean($layout_section))) {
if (empty($this->clean($layout_section, TRUE, TRUE))) {
continue;
}
......@@ -303,11 +353,15 @@ class UwContentParser {
/**
* Removes HTML tags and whitespaces from HTML snippet.
*/
protected function clean($content, $strip_tags = TRUE) {
protected function clean($content, $strip_tags = TRUE, $strip_whitespaces = FALSE) {
// Replace a commonly used non-breaking space: &nbsp.
$content = str_replace('&nbsp;', ' ', $content);
// Remove other special characters.
$content = preg_replace("/&#?[a-z0-9]{2,8};/i", '', $content);
// Remove all non-printable characters.
if ($strip_whitespaces) {
$content = preg_replace('/[\x00-\x1F\x7F]/u', '', $content);
}
if ($strip_tags) {
$allowed_tags = array_merge([
......@@ -350,6 +404,10 @@ class UwContentParser {
return trim($innerHTML);
}
protected function getOuterHtml(\DOMElement $element) {
return $element->ownerDocument->saveHTML($element);
}
/**
* Parses tweet parts from given embedded tweet code.
*/
......
......@@ -243,8 +243,25 @@ trait UwMigrateTrait {
* @see https://regex101.com/r/2FvaRw/1
*/
public function getLayoutsRegex() {
$layouts = implode('|', array_keys($this->getLayoutMapping()));
return '/<div[^>]*class="[^"]*(' . $layouts . ')[^"]*"[^>]*>[\w\W]*<\/div>/Us';
$classes = implode('|', array_keys($this->getLayoutMapping()));
return '/<div[^>]*class="[^"]*(' . $classes . ')[^"]*"[^>]*>[\w\W]*<\/div>/Us';
}
public function getLayoutsXpath($expandable = FALSE) {
$classes = array_map(function ($class) {
return "contains (@class, '" . $class . "')";
}, array_keys($this->getLayoutMapping()));
$xpath = 'div[' . implode(' or ', $classes) . ']';
// Select everything, that are not inside "expandable" items.
if ($expandable) {
$xpath = "//div[@class='expandable']//{$xpath}";
}
else {
$xpath = "{$xpath}[not(ancestor::div[@class='expandable'])]";
}
return $xpath;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment