Passed
Branch scrutinizer (a800ff)
by Thomas
02:24
created

HtmlElement::removeAttr()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 1
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Sulao\HtmlQuery;
4
5
use DOMElement;
6
7
/**
8
 * Class HtmlElement
9
 *
10
 * @package Sulao\HtmlQuery
11
 */
12
class HtmlElement extends HtmlNode
13
{
14
    /**
15
     * @var DOMElement
16
     */
17
    protected $node;
18
19
    /**
20
     * HtmlElement constructor.
21
     *
22
     * @param DOMElement $node
23
     */
24
    public function __construct(DOMElement $node)
25
    {
26
        $this->node = $node;
27
    }
28
29
    /**
30
     * Get the value of an attribute
31
     *
32
     * @param string $name
33
     *
34
     * @return string|null
35
     */
36
    public function getAttr(string $name)
37
    {
38
        return $this->node->getAttribute($name);
39
    }
40
41
    /**
42
     * Set attribute.
43
     *
44
     * @param string $name
45
     * @param string $value
46
     */
47
    public function setAttr(string $name, string $value)
48
    {
49
        $this->node->setAttribute($name, $value);
50
    }
51
52
    /**
53
     * Remove an attribute.
54
     *
55
     * @param string $attributeName
56
     */
57
    public function removeAttr(string $attributeName)
58
    {
59
        $this->node->removeAttribute($attributeName);
60
    }
61
62
    /**
63
     * Remove all attributes except the specified ones.
64
     *
65
     * @param string|array $except The attribute name(s) that won't be removed
66
     */
67
    public function removeAllAttrs($except = [])
68
    {
69
        $names = [];
70
        foreach (iterator_to_array($this->node->attributes) as $attribute) {
71
            $names[] = $attribute->name;
72
        }
73
74
        foreach (array_diff($names, (array) $except) as $name) {
75
            $this->node->removeAttribute($name);
76
        }
77
    }
78
79
    /**
80
     * Determine whether the node has the given attribute.
81
     *
82
     * @param string $attributeName
83
     *
84
     * @return bool
85
     */
86
    public function hasAttr(string $attributeName)
87
    {
88
        return $this->node->hasAttribute($attributeName);
89
    }
90
91
    /**
92
     * Adds the specified class(es).
93
     *
94
     * @param string $className
95
     */
96
    public function addClass(string $className)
97
    {
98
        if (!$this->hasAttr('class')) {
99
            $this->setAttr('class', $className);
100
            return;
101
        }
102
103
        $classNames = Helper::splitClass($className);
104
        $class = (string) $this->getAttr('class');
105
        $classes = Helper::splitClass($class);
106
107
        $classArr = array_diff($classNames, $classes);
108
        if (empty($classArr)) {
109
            return;
110
        }
111
112
        $class .= ' ' . implode(' ', $classArr);
113
        $this->setAttr('class', $class);
114
    }
115
116
    /**
117
     * Determine whether the node is assigned the given class.
118
     *
119
     * @param string $className
120
     *
121
     * @return bool
122
     */
123
    public function hasClass(string $className)
124
    {
125
        if (!$this->hasAttr('class')) {
126
            return false;
127
        }
128
129
        $class = (string) $this->getAttr('class');
130
        $classes = Helper::splitClass($class);
131
132
        return in_array($className, $classes);
133
    }
134
135
    /**
136
     * Remove a single class, multiple classes, or all classes.
137
     *
138
     * @param string|null $className
139
     */
140
    public function removeClass(?string $className = null)
141
    {
142
        if (!$this->hasAttr('class')) {
143
            return;
144
        }
145
146
        if (is_null($className)) {
147
            $this->removeAttr('class');
148
            return;
149
        }
150
151
        $classNames = Helper::splitClass($className);
152
        $class = (string) $this->getAttr('class');
153
        $classes = Helper::splitClass($class);
154
155
        $classArr = array_diff($classes, $classNames);
156
        if (empty($classArr)) {
157
            $this->removeAttr('class');
158
            return;
159
        }
160
161
        $class = implode(' ', $classArr);
162
        $this->setAttr('class', $class);
163
    }
164
165
    /**
166
     * Add or remove class(es), depending on either the class's presence
167
     * or the value of the state argument.
168
     *
169
     * @param string $className
170
     * @param bool|null   $state
171
     */
172
    public function toggleClass(string $className, ?bool $state = null)
173
    {
174
        if (!is_null($state)) {
175
            if ($state) {
176
                $this->addClass($className);
177
            } else {
178
                $this->removeClass($className);
179
            }
180
            return;
181
        }
182
183
        if (!$this->hasAttr('class')) {
184
            $this->setAttr('class', $className);
185
            return;
186
        }
187
188
        $classNames = Helper::splitClass($className);
189
        $classes = Helper::splitClass((string) $this->getAttr('class'));
190
191
        $classArr = array_diff($classes, $classNames);
192
        $classArr = array_merge(
193
            $classArr,
194
            array_diff($classNames, $classes)
195
        );
196
        if (empty($classArr)) {
197
            $this->removeClass($className);
198
            return;
199
        }
200
201
        $this->setAttr('class', implode(' ', $classArr));
202
    }
203
204
    /**
205
     * Get the value of a computed style property
206
     *
207
     * @param string $name
208
     *
209
     * @return string|null
210
     */
211
    public function getCss(string $name)
212
    {
213
        $style = (string) $this->getAttr('style');
214
        $css = Helper::splitCss($style);
215
        if (!$css) {
216
            return null;
217
        }
218
219
        if (array_key_exists($name, $css)) {
220
            return $css[$name];
221
        }
222
223
        $arr = array_change_key_case($css, CASE_LOWER);
224
        $key = strtolower($name);
225
        if (array_key_exists($key, $arr)) {
226
            return $arr[$key];
227
        }
228
229
        return null;
230
    }
231
232
    /**
233
     * Set or Remove one CSS property.
234
     *
235
     * @param string      $name
236
     * @param string|null $value
237
     */
238
    public function setCss(string $name, ?string $value)
239
    {
240
        if ((string) $value === '') {
241
            $this->removeCss($name);
242
            return;
243
        }
244
245
        $style = (string) $this->getAttr('style');
246
        if (!$style) {
247
            $this->setAttr('style', $name . ': ' . $value . ';');
248
            return;
249
        }
250
251
        $css = Helper::splitCss($style);
252
        if (!array_key_exists($name, $css)) {
253
            $allKeys = array_keys($css);
254
            $arr = array_combine(
255
                $allKeys,
256
                array_map('strtolower', $allKeys)
257
            ) ?: [];
258
259
            $keys = array_keys($arr, strtolower($name));
260
            foreach ($keys as $key) {
261
                unset($css[$key]);
262
            }
263
        }
264
265
        $css[$name] = $value;
266
        $style = Helper::implodeCss($css);
267
        $this->setAttr('style', $style);
268
    }
269
270
    /**
271
     * Remove one CSS property.
272
     *
273
     * @param string $name
274
     */
275
    public function removeCss(string $name)
276
    {
277
        $style = (string) $this->getAttr('style');
278
        if (!$style) {
279
            return;
280
        }
281
282
        $css = Helper::splitCss($style);
283
        $removed = false;
284
        if (array_key_exists($name, $css)) {
285
            unset($css[$name]);
286
            $removed = true;
287
        } else {
288
            $allKeys = array_keys($css);
289
            $arr = array_combine(
290
                $allKeys,
291
                array_map('strtolower', $allKeys)
292
            ) ?: [];
293
294
            $keys = array_keys($arr, strtolower($name));
295
            foreach ($keys as $key) {
296
                unset($css[$key]);
297
                $removed = true;
298
            }
299
        }
300
301
        if ($removed) {
302
            $style = Helper::implodeCss($css);
303
            $this->setAttr('style', $style);
304
        }
305
    }
306
}
307