Skip to content

Commit 3e44380

Browse files
committed
FEATURE: New link value object for new link editor
This Link can be used as node property ```yaml My.Content: properties: link: type: 'Neos\Neos\Domain\Link\Link' ui: inspector: editorOptions: anchor: true title: true targetBlank: true relNofollow: true download: true ```
1 parent 1ab38b4 commit 3e44380

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Neos.Neos.Ui package.
5+
*
6+
* (c) Contributors of the Neos Project - www.neos.io
7+
*
8+
* This package is Open Source Software. For the full copyright and license
9+
* information, please view the LICENSE file which was distributed with this
10+
* source code.
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Neos\Neos\Domain\Link;
16+
17+
use GuzzleHttp\Psr7\Uri;
18+
use Neos\Flow\Annotations as Flow;
19+
use Psr\Http\Message\UriInterface;
20+
21+
/**
22+
* Link value object modeled partially after the html spec for <a> tags.
23+
*
24+
* Note that currently the link editor can only handle and write to
25+
* the property {@see Link::$target} "_blank" | null
26+
* and to {@see Link::$rel} ["noopener"] | null
27+
*
28+
* The Link values can be accessed in Fusion the following:
29+
*
30+
* ```fusion
31+
* href = ${q(node).property("link").href}
32+
* title = ${q(node).property("link").title}
33+
* # ...
34+
* ```
35+
*
36+
* In case you need to cast the uri in {@see Link::$href} explicitly to a string
37+
* you can use: `String.toString(link.href)`
38+
*
39+
* @Flow\Proxy(false)
40+
*/
41+
final readonly class Link implements \JsonSerializable
42+
{
43+
/**
44+
* A selection of frequently used target attribute values
45+
*/
46+
public const TARGET_SELF = '_self';
47+
public const TARGET_BLANK = '_blank';
48+
49+
/**
50+
* A selection of frequently used rel attribute values
51+
*/
52+
public const REL_NOOPENER = 'noopener';
53+
public const REL_NOFOLLOW = 'nofollow';
54+
55+
/**
56+
* @param array<int, string> $rel
57+
*/
58+
private function __construct(
59+
public UriInterface $href,
60+
public ?string $title,
61+
public ?string $target,
62+
public array $rel,
63+
public bool $download
64+
) {
65+
}
66+
67+
/**
68+
* @param array<int, string> $rel
69+
*/
70+
public static function create(
71+
UriInterface $href,
72+
?string $title,
73+
?string $target,
74+
array $rel,
75+
bool $download,
76+
): self {
77+
$relMap = [];
78+
foreach ($rel as $value) {
79+
$relMap[trim(strtolower($value))] = true;
80+
}
81+
$trimmedTarget = $target !== null ? trim($target) : '';
82+
return new self(
83+
$href,
84+
$title,
85+
$trimmedTarget !== '' ? strtolower($trimmedTarget) : null,
86+
array_keys($relMap),
87+
$download
88+
);
89+
}
90+
91+
/**
92+
* @param array<string, mixed> $array
93+
*/
94+
public static function fromArray(array $array): self
95+
{
96+
return self::create(
97+
new Uri($array['href']),
98+
$array['title'] ?? null,
99+
$array['target'] ?? null,
100+
$array['rel'] ?? [],
101+
$array['download'] ?? false,
102+
);
103+
}
104+
105+
public static function fromString(string $string): self
106+
{
107+
return self::create(
108+
new Uri($string),
109+
null,
110+
null,
111+
[],
112+
false,
113+
);
114+
}
115+
116+
public function withTitle(?string $title): self
117+
{
118+
return self::create(
119+
$this->href,
120+
$title,
121+
$this->target,
122+
$this->rel,
123+
$this->download,
124+
);
125+
}
126+
127+
public function withTarget(?string $target): self
128+
{
129+
return self::create(
130+
$this->href,
131+
$this->title,
132+
$target,
133+
$this->rel,
134+
$this->download,
135+
);
136+
}
137+
138+
/**
139+
* @param array<int, string> $rel
140+
*/
141+
public function withRel(array $rel): self
142+
{
143+
return self::create(
144+
$this->href,
145+
$this->title,
146+
$this->target,
147+
$rel,
148+
$this->download,
149+
);
150+
}
151+
152+
public function withDownload(bool $download): self
153+
{
154+
return self::create(
155+
$this->href,
156+
$this->title,
157+
$this->target,
158+
$this->rel,
159+
$download,
160+
);
161+
}
162+
163+
public function jsonSerialize(): mixed
164+
{
165+
return [
166+
'href' => $this->href->__toString(),
167+
'title' => $this->title,
168+
'target' => $this->target,
169+
'rel' => $this->rel,
170+
'download' => $this->download,
171+
];
172+
}
173+
}

0 commit comments

Comments
 (0)