1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace AloiaCms; |
4
|
|
|
|
5
|
|
|
use ContentParser\ContentParser; |
6
|
|
|
use Illuminate\Contracts\Filesystem\FileNotFoundException; |
7
|
|
|
use AloiaCms\Facades\BlockFacade; |
8
|
|
|
use Illuminate\Support\Collection; |
9
|
|
|
use Illuminate\Support\Facades\Config; |
10
|
|
|
use Illuminate\Support\Facades\File; |
11
|
|
|
use Illuminate\Support\Facades\Log; |
12
|
|
|
|
13
|
|
|
class InlineBlockParser |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* Convert block tags in HTML strings into block content |
17
|
|
|
* |
18
|
|
|
* @param string $html_string |
19
|
|
|
* @param bool $backward_compatible_mode |
20
|
|
|
* @return string |
21
|
|
|
*/ |
22
|
20 |
|
public function parseHtmlString(string $html_string, bool $backward_compatible_mode = false): string |
23
|
|
|
{ |
24
|
20 |
|
$tag_positions = $this->strpos_all($html_string, '==='); |
25
|
|
|
|
26
|
20 |
|
if (count($tag_positions) % 2 !== 0) { |
27
|
1 |
|
return $html_string; |
28
|
|
|
} |
29
|
|
|
|
30
|
19 |
|
$pairs = []; |
31
|
|
|
|
32
|
19 |
|
foreach ($tag_positions as $key => $position) { |
33
|
5 |
|
if ($key % 2 === 0) { |
34
|
5 |
|
$pairs[] = [$position]; |
35
|
|
|
} else { |
36
|
5 |
|
$last_index = count($pairs) - 1; |
37
|
|
|
|
38
|
5 |
|
$pairs[$last_index][] = $position; |
39
|
|
|
} |
40
|
|
|
} |
41
|
|
|
|
42
|
19 |
|
$replacements = []; |
43
|
|
|
|
44
|
19 |
|
foreach ($pairs as $key => $pair) { |
45
|
5 |
|
$tag = substr($html_string, $pair[0], $pair[1] - $pair[0] + 3); |
46
|
|
|
|
47
|
5 |
|
$block_name = trim(str_replace("===", "", $tag)); |
48
|
|
|
|
49
|
5 |
|
$replacements[$tag] = $this->getReplacementFromBlockName($tag, $block_name, $backward_compatible_mode); |
50
|
|
|
} |
51
|
|
|
|
52
|
19 |
|
return str_replace(array_keys($replacements), array_values($replacements), $html_string); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Get all occurrences of a needle in the haystack |
57
|
|
|
* |
58
|
|
|
* @param string $haystack |
59
|
|
|
* @param string $needle |
60
|
|
|
* @return array |
61
|
|
|
*/ |
62
|
20 |
|
public function strpos_all(string $haystack, string $needle): array |
63
|
|
|
{ |
64
|
20 |
|
$s = 0; |
65
|
20 |
|
$i = 0; |
66
|
|
|
|
67
|
20 |
|
while (is_integer($i)) { |
68
|
20 |
|
$i = stripos($haystack, $needle, $s); |
69
|
|
|
|
70
|
20 |
|
if (is_integer($i)) { |
71
|
6 |
|
$aStrPos[] = $i; |
72
|
6 |
|
$s = $i + strlen($needle); |
73
|
|
|
} |
74
|
|
|
} |
75
|
|
|
|
76
|
20 |
|
if (isset($aStrPos)) { |
77
|
6 |
|
return $aStrPos; |
78
|
|
|
} else { |
79
|
19 |
|
return []; |
80
|
|
|
} |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Parse the options given to the blocks and apply them as attributes to the surrounding div |
85
|
|
|
* |
86
|
|
|
* @param string $tag |
87
|
|
|
* @param string $block_name |
88
|
|
|
* @param bool $backward_compatible_mode |
89
|
|
|
* @return string |
90
|
|
|
*/ |
91
|
5 |
|
private function getReplacementFromBlockName(string $tag, string $block_name, bool $backward_compatible_mode): string |
92
|
|
|
{ |
93
|
5 |
|
$index_of_options = strpos($block_name, '['); |
94
|
|
|
|
95
|
5 |
|
$options = ''; |
96
|
|
|
|
97
|
5 |
|
$link = null; |
98
|
|
|
|
99
|
5 |
|
if ($index_of_options !== false) { |
100
|
2 |
|
$options_string = substr($block_name, $index_of_options + 1, -1); |
101
|
|
|
|
102
|
2 |
|
if (strlen($options_string) > 0) { |
103
|
2 |
|
$options = $this->blockAttributes($options_string); |
104
|
|
|
|
105
|
2 |
|
$link = $this->linkAttributes($options_string); |
106
|
|
|
|
107
|
2 |
|
$block_name = substr($block_name, 0, $index_of_options); |
108
|
|
|
} |
109
|
|
|
} |
110
|
|
|
|
111
|
5 |
|
$block_value = $backward_compatible_mode ? $this->get($block_name) : BlockFacade::get($block_name); |
|
|
|
|
112
|
|
|
|
113
|
5 |
|
if (empty($block_value)) { |
114
|
1 |
|
$block_value = $tag; |
115
|
|
|
} |
116
|
|
|
|
117
|
5 |
|
return "<div{$options}>{$this->linkTag($link)}{$block_value}{$this->linkTag($link, false)}</div>"; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Get the attributes applied to the content block |
122
|
|
|
* |
123
|
|
|
* @param string $options_string |
124
|
|
|
* @return Collection |
125
|
|
|
*/ |
126
|
2 |
|
private function wrapperAttributes(string $options_string): Collection |
127
|
|
|
{ |
128
|
2 |
|
return Collection::make(explode(',', $options_string)) |
129
|
|
|
->map(function (string $option_string) { |
130
|
2 |
|
return explode('=', $option_string); |
131
|
2 |
|
}); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Get the link attributes applied to the content block |
136
|
|
|
* |
137
|
|
|
* @param string $options_string |
138
|
|
|
* @return string |
139
|
|
|
*/ |
140
|
2 |
|
private function linkAttributes(string $options_string): string |
141
|
|
|
{ |
142
|
2 |
|
$attributes = $this->wrapperAttributes($options_string) |
143
|
|
|
->filter(function (array $option) { |
144
|
2 |
|
return in_array($option[0], ['href']); |
145
|
2 |
|
}); |
146
|
|
|
|
147
|
2 |
|
return rtrim($this->toAttributesString($attributes)); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Get the block (div) attributes applied to the content block |
152
|
|
|
* |
153
|
|
|
* @param string $options_string |
154
|
|
|
* @return string |
155
|
|
|
*/ |
156
|
2 |
|
private function blockAttributes(string $options_string): string |
157
|
|
|
{ |
158
|
2 |
|
$attributes = $this->wrapperAttributes($options_string) |
159
|
|
|
->filter(function (array $option) { |
160
|
2 |
|
return in_array($option[0], ['class', 'id', 'style']); |
161
|
2 |
|
}); |
162
|
|
|
|
163
|
2 |
|
return rtrim($this->toAttributesString($attributes)); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Generate a string from the attributes |
168
|
|
|
* |
169
|
|
|
* @param Collection $attributes |
170
|
|
|
* @return string |
171
|
|
|
*/ |
172
|
2 |
|
private function toAttributesString(Collection $attributes): string |
173
|
|
|
{ |
174
|
|
|
return $attributes |
175
|
|
|
->reduce(function (string $carry, array $option_pair) { |
176
|
2 |
|
return "{$carry}{$option_pair[0]}=\"{$option_pair[1]}\" "; |
177
|
2 |
|
}, ' '); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Generate an anchor tag from the given link attributes |
182
|
|
|
* |
183
|
|
|
* @param null|string $link |
184
|
|
|
* @param bool $open_tag |
185
|
|
|
* @return string |
186
|
|
|
*/ |
187
|
5 |
|
private function linkTag(?string $link, bool $open_tag = true): string |
188
|
|
|
{ |
189
|
5 |
|
if (!is_null($link) && !empty($link)) { |
190
|
1 |
|
return $open_tag ? "<a{$link}>" : "</a>"; |
191
|
|
|
} |
192
|
|
|
|
193
|
4 |
|
return ""; |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
|