Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
engine.php
1<?
9
14
15Loc::loadMessages(__FILE__);
16
21class Engine
22{
23 const BLOCK_PLACE_ATTR = 'data-bx-block-editor-place';
24 const STYLIST_TAG_ATTR = 'data-bx-stylist-container';
26
27 const CONTENT_SLICE = 0;
28 const CONTENT_JSON = 1;
29
31 protected $content;
32
34 protected $document;
35
37 protected $encoding = null;
38
45 public static function isSupported($string)
46 {
47 foreach (self::getConverters() as $converter)
48 {
49 if ($converter::isValid($string))
50 {
51 return true;
52 }
53 }
54
55 return false;
56 }
57
63 public static function create(Document $document = null)
64 {
65 return new static($document);
66 }
67
72 public function __construct(Document $document = null)
73 {
74 $this->setDocument($document ?: new Document);
75 }
76
83 public function setHtml($html)
84 {
85 $this->document->loadHTML($html);
86 return $this;
87 }
88
96 {
97 $this->document = $document;
98 return $this;
99 }
100
107 public function setContent($string)
108 {
109 return $this->setBlockContent(static::createBlockContent($string));
110 }
111
118 public function setBlockContent(BlockContent $blockContent)
119 {
120 $this->content = $blockContent;
121 $this->fill();
122 return $this;
123 }
124
131 public function setEncoding($encoding = null)
132 {
133 $this->encoding = $encoding;
134 return $this;
135 }
136
137 public function getDocument()
138 {
139 return $this->document;
140 }
141
142 public function getHtml()
143 {
144 $html = $this->document->saveHTML();
145 return $html ? $html : '';
146 }
147
156 public static function fillHtmlTemplate($htmlTemplate, $content, $encoding = null)
157 {
158 $instance = static::create()->setEncoding($encoding)->setHtml($htmlTemplate)->setContent($content);
159
160 if($instance->fill())
161 {
162 return $instance->getHtml() ?: $htmlTemplate;
163 }
164 else
165 {
166 return $htmlTemplate;
167 }
168 }
169
175 public function fill()
176 {
177 // prepare blocks
178 $blocks = array();
179 $grouped = array();
180 foreach($this->content->getBlocks() as $item)
181 {
182 $grouped[$item['place']][] = $item['value'];
183 }
184
185 foreach($grouped as $place => $values)
186 {
187 $blocks[$place] = "\n" . implode("\n", $values) . "\n";
188 }
189 unset($grouped);
190
191
192 // unite styles to one string
193 $styles = '';
194 foreach($this->content->getStyles() as $item)
195 {
196 $styles .= "\n" . $item['value'];
197 }
198
199 if($styles && preg_match_all("#<style[\\s\\S]*?>([\\s\\S]*?)</style>#i", $styles, $matchesStyles))
200 {
201 $styles = '';
202 $matchesStylesCount = count($matchesStyles);
203 for($i = 0; $i < $matchesStylesCount; $i++)
204 {
205 $styles .= "\n" . $matchesStyles[1][$i];
206 }
207 }
208
209 // if nothing to replace, return content
210 if(!$styles && count($blocks) === 0)
211 {
212 return false;
213 }
214
215 // add styles block to head of document
216 if($styles)
217 {
218 $this->addStylesToDocumentHead($styles);
219 }
220
221 // fill places by blocks
222 if($blocks)
223 {
224 $this->addBlocksToDocument($blocks);
225 }
226
227 return true;
228 }
229
230 protected function addBlocksToDocument($blocks)
231 {
232 $placeList = $this->document->querySelectorAll('[' . static::BLOCK_PLACE_ATTR . ']');
233 if(empty($placeList))
234 {
235 return;
236 }
237
238 // find available places
239 $firstPlaceCode = null;
240 $bodyPlaceCode = null;
241 $placeListByCode = array();
242 foreach($placeList as $place)
243 {
244 /* @var $place \Bitrix\Main\Web\DOM\Element */
245 if (!$place || !$place->getAttributeNode(static::BLOCK_PLACE_ATTR))
246 {
247 continue;
248 }
249
250 /*
251 // remove child nodes
252 foreach($place->getChildNodesArray() as $child)
253 {
254 $place->removeChild($child);
255 }
256 */
257
258 $placeCode = $place->getAttribute(static::BLOCK_PLACE_ATTR);
259 $placeListByCode[$placeCode] = $place;
260 if(!$firstPlaceCode)
261 {
262 $firstPlaceCode = $placeCode;
263 }
264
265 if(!$bodyPlaceCode && $placeCode == static::BLOCK_PLACE_ATTR_DEF_VALUE)
266 {
267 $bodyPlaceCode = $placeCode;
268 }
269 }
270
271 // group block list by existed places
272 $blocksByExistType = array();
273 foreach($blocks as $placeCode => $blockHtml)
274 {
275 // if there is no place, find body-place or first place or skip filling place
276 if(!array_key_exists($placeCode, $placeListByCode))
277 {
278 if($bodyPlaceCode)
279 {
280 $placeCode = $bodyPlaceCode;
281 }
282 elseif($firstPlaceCode)
283 {
284 $placeCode = $firstPlaceCode;
285 }
286 else
287 {
288 continue;
289 }
290 }
291
292 $blocksByExistType[$placeCode][] = $blockHtml;
293 }
294
295 //fill existed places by blocks
296 foreach($blocksByExistType as $placeCode => $blockHtmlList)
297 {
298 if(!array_key_exists($placeCode, $placeListByCode))
299 {
300 continue;
301 }
302
303 $place = $placeListByCode[$placeCode];
304 $place->setInnerHTML(implode("\n", $blockHtmlList));
305 }
306 }
307
308 protected function addStylesToDocumentHead($styleString)
309 {
310 $headDomElement = $this->document->getHead();
311 if(!$headDomElement)
312 {
313 return;
314 }
315
316 $styleNode = end($headDomElement->querySelectorAll('style[' . self::STYLIST_TAG_ATTR . ']'));
317 if(!$styleNode)
318 {
319 $styleNode = $this->document->createElement('style');
320 $styleNode->setAttribute('type', 'text/css');
321 $styleNode->setAttribute(self::STYLIST_TAG_ATTR, 'item');
322 $headDomElement->appendChild($styleNode);
323 $styleNode->appendChild($this->document->createTextNode($styleString));
324 }
325 else
326 {
327 $styleList1 = CssParser::parseCss($styleNode->getTextContent());
328 $styleList2 = CssParser::parseCss($styleString);
329 $styleList = array_merge($styleList1, $styleList2);
330
331 $styleListByKey = array();
332 foreach($styleList as $styleItem)
333 {
334 if(!is_array($styleListByKey[$styleItem['SELECTOR']]))
335 {
336 $styleListByKey[$styleItem['SELECTOR']] = array();
337 }
338
339 $styleListByKey[$styleItem['SELECTOR']] = array_merge(
340 $styleListByKey[$styleItem['SELECTOR']],
341 $styleItem['STYLE']
342 );
343 }
344
345 $stylesString = '';
346 foreach($styleListByKey as $selector => $declarationList)
347 {
348 $stylesString .= $selector . '{' . CssParser::getDeclarationString($declarationList) . "}\n";
349 }
350
351 if($stylesString)
352 {
353 $styleNode->setInnerHTML('');
354 $styleNode->appendChild($this->document->createTextNode($stylesString));
355 }
356 }
357 }
358
366 protected static function createBlockContent($string)
367 {
368 foreach (self::getConverters() as $converter)
369 {
370 if ($converter::isValid($string))
371 {
372 return $converter::toArray($string);
373 }
374 }
375
376 throw new SystemException('Wrong content type.');
377 }
378
379 protected static function getConverters()
380 {
381 return array(
382 __NAMESPACE__ . '\JsonConverter',
383 __NAMESPACE__ . '\SliceConverter',
384 );
385 }
386}
setDocument(Document $document)
Definition engine.php:95
static create(Document $document=null)
Definition engine.php:63
__construct(Document $document=null)
Definition engine.php:72
static fillHtmlTemplate($htmlTemplate, $content, $encoding=null)
Definition engine.php:156
setBlockContent(BlockContent $blockContent)
Definition engine.php:118
static loadMessages($file)
Definition loc.php:64