editor icon indicating copy to clipboard operation
editor copied to clipboard

Feature: Wrapping Blocks

Open nilshoerrmann opened this issue 4 years ago • 2 comments

This is really a tricky request:

The editor's block model is really powerful and will allow us to move away from complex subpage setups to handle modular content. And while adding blocks is easy, layout often requires additional wrappers (e. g. a div with a specific class).

I'm actually not sure if this is something for the editor to solve or if this is something that needs to be applied to the resulting markup in a separate step but wrapping blocks would be a needed feature.

Example: a page with an interview, imagine two custom blocks, one for questions, one for answers. In the frontend output, we'd like to wrap all answer blocks until the next question (or the end of the content) in a div with the classanswer.

nilshoerrmann avatar Aug 06 '19 09:08 nilshoerrmann

I thought about adding a general block settings dialog to all blocks, which could contain a CSS class setting. Then you have full control over the final markup.

bastianallgeier avatar Aug 06 '19 11:08 bastianallgeier

I thought about adding a general block settings dialog to all blocks, which could contain a CSS class setting. Then you have full control over the final markup.

I think this is more what #28 requested. I was really thinking about wrapping multiple blocks in a div or a section or an article. These kind of wrappers can be necessary for advanced grid layouts. And after thinking about it, it might not be difficult at all to achieve this. What I am thinking about is something like this:

$page->text()->blocks()->wrap('paragraph', 'heading1', 'div', ['class' => 'example'])->html();

The method's arguments being $from, $until, $element, $attributes – the latter two being optional. It would turn these blocks …

[
    {
        "attrs": [],
        "content": "My text",
        "id": "_9obatb19c",
        "type": "paragraph"
    },
    {
        "attrs": [],
        "content": "My list",
        "id": "_5bbcu4ini",
        "type": "ul"
    },
    {
        "attrs": [],
        "content": "My heading",
        "id": "_o1vzjnx96",
        "type": "h1"
    }
]

… into:

<div class="example">
  <p>My text</p>
  <ul>
    <li>My list</li>
  </ul>
</div>
<h1>My heading</h1>

The wrap method would have to programmatically add "virtual blocks" to the editor collection. Pseudo code:

function wrap($from, $until, $element = 'div', $attributes = []) {
	while($block) {
		$isOpen = false;

		if ($block->type() === $from && !$isOpen) {
			$block->prepend({
		        attrs => [
					'element' => $element,
					'attributes' => $attributes
				],
		        content => null,
		        id => "something",
		        type => "wrapstart"
		    });
			$isOpen = true;
		}

		if ($block->type() === $until && $isOpen) {
			$block->prepend({
				attrs => [
					'element' => $element,
				],
		        content => null,
		        id => "something",
		        type => "wrapend"
		    });
			$isOpen = false;
		}
	}
}

With these blocks added virtually, the output could be generated using snippets for the opening and closing tag (using the defined attr):

editor/wrapstart.php

<<?=$attr['element']?> 
  <?php foreach($attr['attributes'] as $name => $value) ?> <?=$name?>="<?=$value?>"<?php endforeach>
>

editor/wrapend.php

</<?=$attr['element']?>>

Does that make sense?

nilshoerrmann avatar Aug 06 '19 12:08 nilshoerrmann