1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Groundskeeper\Tokens\Elements; |
4
|
|
|
|
5
|
|
|
use Groundskeeper\Configuration; |
6
|
|
|
use Groundskeeper\Tokens\Element; |
7
|
|
|
use Groundskeeper\Tokens\ElementTypes\FlowContent; |
8
|
|
|
use Groundskeeper\Tokens\ElementTypes\InlineElement; |
9
|
|
|
use Groundskeeper\Tokens\ElementTypes\InteractiveContent; |
10
|
|
|
use Groundskeeper\Tokens\ElementTypes\OpenElement; |
11
|
|
|
use Groundskeeper\Tokens\ElementTypes\PhrasingContent; |
12
|
|
|
use Groundskeeper\Tokens\ElementTypes\TransparentElement; |
13
|
|
|
use Groundskeeper\Tokens\Token; |
14
|
|
|
use Psr\Log\LoggerInterface; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* "a" element |
18
|
|
|
* |
19
|
|
|
* https://html.spec.whatwg.org/multipage/semantics.html#the-a-element |
20
|
|
|
*/ |
21
|
|
|
class A extends OpenElement implements FlowContent, InteractiveContent, PhrasingContent, InlineElement, TransparentElement |
22
|
|
|
{ |
23
|
5 |
|
protected function getAllowedAttributes() |
24
|
|
|
{ |
25
|
|
|
$aAllowedAttributes = array( |
26
|
5 |
|
'/^href$/i' => Element::ATTR_URI, |
27
|
5 |
|
'/^target$/i' => Element::ATTR_CS_STRING, |
28
|
5 |
|
'/^download$/i' => Element::ATTR_CS_STRING, |
29
|
5 |
|
'/^ping$/i' => Element::ATTR_URI, |
30
|
5 |
|
'/^rel$/i' => Element::ATTR_CS_STRING, |
31
|
5 |
|
'/^hreflang$/i' => Element::ATTR_CS_STRING, |
32
|
5 |
|
'/^type$/i' => Element::ATTR_CS_STRING, |
33
|
|
|
'/^referrerpolicy$/i' => Element::ATTR_CS_STRING |
34
|
5 |
|
); |
35
|
|
|
|
36
|
5 |
|
return array_merge( |
37
|
5 |
|
$aAllowedAttributes, |
38
|
5 |
|
parent::getAllowedAttributes() |
39
|
5 |
|
); |
40
|
|
|
} |
41
|
|
|
|
42
|
5 |
|
protected function doClean(LoggerInterface $logger) |
43
|
|
|
{ |
44
|
|
|
// If the "itemprop" attribute is specified on an "a" element, then |
45
|
|
|
// the "href" attribute must also be specified. |
46
|
5 |
|
if ($this->hasAttribute('itemprop') && !$this->hasAttribute('href')) { |
47
|
1 |
|
$logger->debug('Element "a" with "itemprop" attribute requires the "href" attribute also. Adding empty "href" attribute.'); |
48
|
1 |
|
$this->addAttribute('href', ''); |
49
|
1 |
|
} |
50
|
|
|
|
51
|
5 |
|
if ($this->configuration->get('clean-strategy') != Configuration::CLEAN_STRATEGY_LENIENT) { |
52
|
|
|
// There must be no interactive content or "a" element descendants. |
53
|
5 |
|
foreach ($this->children as $child) { |
54
|
5 |
|
if ($child->getType() == Token::COMMENT) { |
55
|
1 |
|
continue; |
56
|
|
|
} |
57
|
|
|
|
58
|
5 |
|
if ($child->getType() == Token::ELEMENT && |
59
|
1 |
|
($child->getName() == 'a' || |
60
|
5 |
|
($child instanceof InteractiveContent && $child->isInteractiveContent()))) { |
61
|
1 |
|
$logger->debug('Removing ' . $child . '. Element "a" cannot contain "a" or interactive content elements.'); |
62
|
1 |
|
$this->removeChild($child); |
63
|
1 |
|
} |
64
|
5 |
|
} |
65
|
|
|
|
66
|
|
|
// The target, download, ping, rel, hreflang, type, and |
67
|
|
|
// referrerpolicy attributes must be omitted if the href |
68
|
|
|
// attribute is not present. |
69
|
5 |
|
if (!$this->hasAttribute('href')) { |
70
|
1 |
|
if ($this->hasAttribute('target') || |
71
|
1 |
|
$this->hasAttribute('download') || |
72
|
1 |
|
$this->hasAttribute('ping') || |
73
|
1 |
|
$this->hasAttribute('rel') || |
74
|
1 |
|
$this->hasAttribute('hreflang') || |
75
|
1 |
|
$this->hasAttribute('type') || |
76
|
1 |
|
$this->hasAttribute('referrerpolicy')) { |
77
|
1 |
|
$logger->debug('Removing invalid attributes. Element "a" without "href" attribute cannot contain "target", "download", "ping", "rel", "hreflang", "type", or "referrerpolicy" attributes.'); |
78
|
1 |
|
$this->removeAttribute('target'); |
79
|
1 |
|
$this->removeAttribute('download'); |
80
|
1 |
|
$this->removeAttribute('ping'); |
81
|
1 |
|
$this->removeAttribute('rel'); |
82
|
1 |
|
$this->removeAttribute('hreflang'); |
83
|
1 |
|
$this->removeAttribute('type'); |
84
|
1 |
|
$this->removeAttribute('referrerpolicy'); |
85
|
1 |
|
} |
86
|
1 |
|
} |
87
|
5 |
|
} |
88
|
|
|
|
89
|
5 |
|
return true; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
public function isInteractiveContent() |
93
|
|
|
{ |
94
|
|
|
return $this->hasAttribute('href'); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
public function isTransparentElement() |
98
|
|
|
{ |
99
|
|
|
return true; |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
|