Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bard data modifiers #6226

Merged
merged 21 commits into from Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 76 additions & 0 deletions src/Modifiers/CoreModifiers.php
Expand Up @@ -23,6 +23,8 @@
use Statamic\Facades\YAML;
use Statamic\Fields\Value;
use Statamic\Fields\Values;
use Statamic\Fieldtypes\Bard;
use Statamic\Fieldtypes\Bard\Augmentor;
use Statamic\Support\Arr;
use Statamic\Support\Html;
use Statamic\Support\Str;
Expand Down Expand Up @@ -175,6 +177,80 @@ public function backspace($value, $params)
return substr($value, 0, -$params[0]);
}

/**
* Converts a bard value to a flat array of nodes and marks.
*
* @param $value
* @return array
*/
public function bardItems($value)
{
if ($value instanceof Value) {
$value = $value->raw();
}
if (Arr::isAssoc($value)) {
$value = [$value];
}

$items = [];
while (count($value)) {
$items[] = $item = array_shift($value);
// Marks are children of the text they apply to, but having access to that node
// would be useful when working with marks, so we add the node to the mark data
array_unshift($value, ...array_map(fn ($m) => $m + ['node' => $item], $item['marks'] ?? []));
array_unshift($value, ...($item['content'] ?? []));
}

return $items;
}

/**
* Converts a bard value to plain text (excluding sets).
*
* @param $value
* @return string
*/
public function bardWords($value)
{
if ($value instanceof Value) {
$value = $value->raw();
}
if (Arr::isAssoc($value)) {
$value = [$value];
}

$text = '';
while (count($value)) {
$item = array_shift($value);
if ($item['type'] === 'text') {
$text .= ' '.($item['text'] ?? '');
}
array_unshift($value, ...($item['content'] ?? []));
}

return Stringy::collapseWhitespace($text);
}

/**
* Converts a bard value to HTML (excluding sets).
*
* @param $value
* @return string
*/
public function bardText($value)
{
if ($value instanceof Value) {
$value = $value->raw();
}
if (Arr::isAssoc($value)) {
$value = [$value];
}

$items = array_values(Arr::where($value, fn ($item) => $item['type'] !== 'set'));

return (new Augmentor(new Bard()))->augment($items);
}

public function boolString($value)
{
if ($value == true) {
Expand Down
134 changes: 134 additions & 0 deletions tests/Modifiers/BardItemsTest.php
@@ -0,0 +1,134 @@
<?php

namespace Tests\Modifiers;

use Illuminate\Support\Arr;
use Statamic\Fields\Value;
use Statamic\Fieldtypes\Bard;
use Statamic\Modifiers\Modify;
use Tests\TestCase;

class BardItemsTest extends TestCase
{
/** @test */
public function it_extracts_bard_items()
{
$data = [
[
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph with '],
['type' => 'text', 'marks' => [['type' => 'bold']], 'text' => 'bold'],
['type' => 'text', 'text' => ' text.'],
],
],
[
'type' => 'set',
'attrs' => [
'values' => [
'type' => 'image',
'image' => 'test.jpg',
'caption' => 'test',
],
],
],
];

$expected = [
[
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph with '],
['type' => 'text', 'marks' => [['type' => 'bold']], 'text' => 'bold'],
['type' => 'text', 'text' => ' text.'],
],
],
['type' => 'text', 'text' => 'This is a paragraph with '],
['type' => 'text', 'marks' => [['type' => 'bold']], 'text' => 'bold'],
['type' => 'bold', 'node' => ['type' => 'text', 'marks' => [['type' => 'bold']], 'text' => 'bold']],
['type' => 'text', 'text' => ' text.'],
[
'type' => 'set',
'attrs' => [
'values' => [
'type' => 'image',
'image' => 'test.jpg',
'caption' => 'test',
],
],
],
];

$this->assertEquals($expected, $this->modify($data));
}

/** @test */
public function it_extracts_bard_items_from_single_node()
{
$data = [
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph.'],
],
];

$expected = [
[
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph.'],
],
],
['type' => 'text', 'text' => 'This is a paragraph.'],
];

$this->assertEquals($expected, $this->modify($data));
}

/** @test */
public function it_extracts_bard_items_from_value_object()
{
$data = new Value([
[
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph.'],
],
],
], 'content', new Bard());

$expected = [
[
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph.'],
],
],
['type' => 'text', 'text' => 'This is a paragraph.'],
];

$this->assertEquals($expected, $this->modify($data));
}

/** @test */
public function it_extracts_bard_items_with_nodes_appended_to_marks()
{
$data = [
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph with '],
$node = ['type' => 'text', 'marks' => [['type' => 'bold']], 'text' => 'bold'],
['type' => 'text', 'text' => ' text.'],
],
];

$items = $this->modify($data);
$mark = Arr::first(Arr::where($items, fn ($item) => $item['type'] === 'bold'));
$this->assertEquals($node, $mark['node']);
}

public function modify($arr, ...$args)
{
return Modify::value($arr)->bard_items($args)->fetch();
}
}
88 changes: 88 additions & 0 deletions tests/Modifiers/BardTextTest.php
@@ -0,0 +1,88 @@
<?php

namespace Tests\Modifiers;

use Statamic\Fields\Value;
use Statamic\Fieldtypes\Bard;
use Statamic\Modifiers\Modify;
use Tests\TestCase;

class BardTextTest extends TestCase
{
/** @test */
public function it_extracts_bard_text()
{
$data = [
[
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph with '],
['type' => 'text', 'marks' => [['type' => 'bold']], 'text' => 'bold'],
['type' => 'text', 'text' => ' and '],
['type' => 'text', 'marks' => [['type' => 'italic']], 'text' => 'italic'],
['type' => 'text', 'text' => ' text.'],
],
],
[
'type' => 'paragraph',
],
[
'type' => 'set',
'attrs' => [
'values' => [
'type' => 'image',
'image' => 'test.jpg',
'caption' => 'test',
],
],
],
[
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'Another paragraph.'],
],
],
];

$expected = '<p>This is a paragraph with <strong>bold</strong> and <em>italic</em> text.</p><p></p><p>Another paragraph.</p>';

$this->assertEquals($expected, $this->modify($data));
}

/** @test */
public function it_extracts_bard_text_from_single_node()
{
$data = [
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph.'],
],
];

$expected = '<p>This is a paragraph.</p>';

$this->assertEquals($expected, $this->modify($data));
}

/** @test */
public function it_extracts_bard_text_from_value_object()
{
$data = new Value([
[
'type' => 'paragraph',
'content' => [
['type' => 'text', 'text' => 'This is a paragraph.'],
],
],
], 'content', new Bard());

$expected = '<p>This is a paragraph.</p>';

$this->assertEquals($expected, $this->modify($data));
}

public function modify($arr, ...$args)
{
return Modify::value($arr)->bard_text($args)->fetch();
}
}