Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/fileman/lib/block/content/ |
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/fileman/lib/block/content/engine.php |
<? /** * Bitrix Framework * @package bitrix * @subpackage sender * @copyright 2001-2012 Bitrix */ namespace Bitrix\Fileman\Block\Content; use Bitrix\Main\SystemException; use Bitrix\Main\Web\DOM\Document; use Bitrix\Main\Localization\Loc; use Bitrix\Main\Web\DOM\CssParser; Loc::loadMessages(__FILE__); /** * Class Engine * @package Bitrix\Fileman\Block */ class Engine { const BLOCK_PLACE_ATTR = 'data-bx-block-editor-place'; const STYLIST_TAG_ATTR = 'data-bx-stylist-container'; const BLOCK_PLACE_ATTR_DEF_VALUE = 'body'; const CONTENT_SLICE = 0; const CONTENT_JSON = 1; /** @var BlockContent $content Block content. */ protected $content; /** @var Document $document Document. */ protected $document; /** @var string|null $encoding Encoding. */ protected $encoding = null; /** * Check string for the presence of slices. * * @param string $string String. * @return bool */ public static function isSupported($string) { foreach (self::getConverters() as $converter) { if ($converter::isValid($string)) { return true; } } return false; } /** * Create instance. * @param Document|null $document Template document. * @return static */ public static function create(Document $document = null) { return new static($document); } /** * Engine constructor. * @param Document|null $document Template document. */ public function __construct(Document $document = null) { $this->setDocument($document ?: new Document); } /** * Set html. * * @param string $html Html. * @return $this */ public function setHtml($html) { $this->document->loadHTML($html); return $this; } /** * Set document. * * @param Document $document Template document. * @return $this */ public function setDocument(Document $document) { $this->document = $document; return $this; } /** * Set content string. * * @param string $string Content string. * @return Engine */ public function setContent($string) { return $this->setBlockContent(static::createBlockContent($string)); } /** * Set block content. * * @param BlockContent $blockContent Block content. * @return $this */ public function setBlockContent(BlockContent $blockContent) { $this->content = $blockContent; $this->fill(); return $this; } /** * Set encoding. * * @param string|null $encoding Encoding. * @return $this */ public function setEncoding($encoding = null) { $this->encoding = $encoding; return $this; } public function getDocument() { return $this->document; } public function getHtml() { $html = $this->document->saveHTML(); return $html ? $html : ''; } /** * Fill HTML template by content. * * @param string $htmlTemplate Html template. * @param string $content Content. * @param string $encoding Encoding. * @return string */ public static function fillHtmlTemplate($htmlTemplate, $content, $encoding = null) { $instance = static::create()->setEncoding($encoding)->setHtml($htmlTemplate)->setContent($content); if($instance->fill()) { return $instance->getHtml() ?: $htmlTemplate; } else { return $htmlTemplate; } } /** * Fill document by content. * * @return bool */ public function fill() { // prepare blocks $blocks = array(); $grouped = array(); foreach($this->content->getBlocks() as $item) { $grouped[$item['place']][] = $item['value']; } foreach($grouped as $place => $values) { $blocks[$place] = "\n" . implode("\n", $values) . "\n"; } unset($grouped); // unite styles to one string $styles = ''; foreach($this->content->getStyles() as $item) { $styles .= "\n" . $item['value']; } if($styles && preg_match_all("#<style[\\s\\S]*?>([\\s\\S]*?)</style>#i", $styles, $matchesStyles)) { $styles = ''; $matchesStylesCount = count($matchesStyles); for($i = 0; $i < $matchesStylesCount; $i++) { $styles .= "\n" . $matchesStyles[1][$i]; } } // if nothing to replace, return content if(!$styles && count($blocks) === 0) { return false; } // add styles block to head of document if($styles) { $this->addStylesToDocumentHead($styles); } // fill places by blocks if($blocks) { $this->addBlocksToDocument($blocks); } return true; } protected function addBlocksToDocument($blocks) { $placeList = $this->document->querySelectorAll('[' . static::BLOCK_PLACE_ATTR . ']'); if(empty($placeList)) { return; } // find available places $firstPlaceCode = null; $bodyPlaceCode = null; $placeListByCode = array(); foreach($placeList as $place) { /* @var $place \Bitrix\Main\Web\DOM\Element */ if (!$place || !$place->getAttributeNode(static::BLOCK_PLACE_ATTR)) { continue; } /* // remove child nodes foreach($place->getChildNodesArray() as $child) { $place->removeChild($child); } */ $placeCode = $place->getAttribute(static::BLOCK_PLACE_ATTR); $placeListByCode[$placeCode] = $place; if(!$firstPlaceCode) { $firstPlaceCode = $placeCode; } if(!$bodyPlaceCode && $placeCode == static::BLOCK_PLACE_ATTR_DEF_VALUE) { $bodyPlaceCode = $placeCode; } } // group block list by existed places $blocksByExistType = array(); foreach($blocks as $placeCode => $blockHtml) { // if there is no place, find body-place or first place or skip filling place if(!array_key_exists($placeCode, $placeListByCode)) { if($bodyPlaceCode) { $placeCode = $bodyPlaceCode; } elseif($firstPlaceCode) { $placeCode = $firstPlaceCode; } else { continue; } } $blocksByExistType[$placeCode][] = $blockHtml; } //fill existed places by blocks foreach($blocksByExistType as $placeCode => $blockHtmlList) { if(!array_key_exists($placeCode, $placeListByCode)) { continue; } $place = $placeListByCode[$placeCode]; $place->setInnerHTML(implode("\n", $blockHtmlList)); } } protected function addStylesToDocumentHead($styleString) { $headDomElement = $this->document->getHead(); if(!$headDomElement) { return; } $styleNode = end($headDomElement->querySelectorAll('style[' . self::STYLIST_TAG_ATTR . ']')); if(!$styleNode) { $styleNode = $this->document->createElement('style'); $styleNode->setAttribute('type', 'text/css'); $styleNode->setAttribute(self::STYLIST_TAG_ATTR, 'item'); $headDomElement->appendChild($styleNode); $styleNode->appendChild($this->document->createTextNode($styleString)); } else { $styleList1 = CssParser::parseCss($styleNode->getTextContent()); $styleList2 = CssParser::parseCss($styleString); $styleList = array_merge($styleList1, $styleList2); $styleListByKey = array(); foreach($styleList as $styleItem) { if(!is_array($styleListByKey[$styleItem['SELECTOR']])) { $styleListByKey[$styleItem['SELECTOR']] = array(); } $styleListByKey[$styleItem['SELECTOR']] = array_merge( $styleListByKey[$styleItem['SELECTOR']], $styleItem['STYLE'] ); } $stylesString = ''; foreach($styleListByKey as $selector => $declarationList) { $stylesString .= $selector . '{' . CssParser::getDeclarationString($declarationList) . "}\n"; } if($stylesString) { $styleNode->setInnerHTML(''); $styleNode->appendChild($this->document->createTextNode($stylesString)); } } } /** * Parse string to array of block content. * * @param string $string String. * @return BlockContent * @throws SystemException */ protected static function createBlockContent($string) { foreach (self::getConverters() as $converter) { if ($converter::isValid($string)) { return $converter::toArray($string); } } throw new SystemException('Wrong content type.'); } protected static function getConverters() { return array( __NAMESPACE__ . '\JsonConverter', __NAMESPACE__ . '\SliceConverter', ); } }