Your IP : 216.73.217.149


Current Path : /var/www/amortar/data/www/a-mortar/bitrix/modules/intec.constructor/classes/structure/
Upload File :
Current File : /var/www/amortar/data/www/a-mortar/bitrix/modules/intec.constructor/classes/structure/Block.php

<?php
namespace intec\constructor\structure;

use intec\constructor\structure\block\Resolution;
use intec\constructor\structure\block\Resources;
use intec\Core;
use intec\core\base\InvalidParamException;
use intec\core\base\BaseObject;
use intec\core\helpers\ArrayHelper;
use intec\core\helpers\Html;
use intec\core\helpers\RegExp;
use intec\core\helpers\Type;
use intec\constructor\structure\block\Element;
use intec\constructor\structure\block\Elements;
use intec\constructor\structure\block\Resolutions;

/**
 * Class Block
 * @property integer $id Идентификатор блока.
 * @package intec\constructor\structure
 */
class Block extends BaseObject
{
    /**
     * Счетчик созданных элементов.
     * @var integer
     */
    protected static $counter = 0;

    /**
     * Уникальный идентификатор блока.
     * @var integer
     */
    protected $_id;
    /**
     * Элементы блока.
     * @var Elements
     */
    protected $_elements;
    /**
     * Разрешения блока.
     * @var Resolutions
     */
    protected $_resolutions;
    /**
     * Ресурсы блока.
     * @var Resources
     */
    protected $_resources;
    /**
     * Высота блока по умолчанию.
     * @var integer
     */
    protected $_height;

    /**
     * Класс по умолчанию.
     * @var string
     */
    public $class;

    /**
     * Создает блок из массива.
     * @param array $data
     * @param Resources $resources
     * @return static
     */
    public static function from($data, $resources)
    {
        $instance = new static($resources);

        $resolutions = ArrayHelper::getValue($data, 'resolutions');
        $elements = ArrayHelper::getValue($data, 'elements');

        if (Type::isArray($resolutions))
            foreach ($resolutions as $resolution)
                $instance->getResolutions()->add(Resolution::from($resolution, $instance));

        if (Type::isArray($elements))
            foreach ($elements as $element)
                $instance->getElements()->add(Element::from($element, $instance));

        return $instance;
    }

    /**
     * Block constructor.
     * @param Resources $resources
     */
    public function __construct($resources)
    {
        if (!($resources instanceof Resources))
            throw new InvalidParamException('Resources is not a "'.Resources::className().'" instance.');

        $this->_id = static::$counter;
        $this->_elements = new Elements();
        $this->_resolutions = new Resolutions([], true);
        $this->_resources = $resources;

        static::$counter++;
        parent::__construct([]);
    }

    /**
     * Возвращает идентификатор блока.
     * @return string
     */
    public function getId()
    {
        return $this->_id;
    }

    /**
     * Устанавливает идентификатор блока.
     * @param integer $id Новый идентификатор.
     * @return $this
     */
    public function setId($id)
    {
        $id = Type::toInteger($id);

        if ($id >= 0)
            $this->_id = $id;

        return $this;
    }

    /**
     * Возвращает элементы блока.
     * @return Elements
     */
    public function getElements()
    {
        return $this->_elements;
    }

    /**
     * Возвращает разрешения блока.
     * @return Resolutions
     */
    public function getResolutions()
    {
        return $this->_resolutions;
    }

    /**
     * Возвращает ресурсы блока.
     * @return Resources
     */
    public function getResources()
    {
        return $this->_resources;
    }

    /**
     * Возвращает структуру блока.
     * @return array
     */
    public function getStructure()
    {
        $result = [];
        $result['resolutions'] = [];
        $result['elements'] = [];

        foreach ($this->_resolutions as $resolution) {
            $result['resolutions'][] = $resolution->getStructure();
        }

        $resolutions = ['*'];
        $resolutions = ArrayHelper::merge(
            $resolutions,
            $this->_resolutions->getWidthValues()
        );

        /** @var Element $element */
        foreach ($this->_elements as $element) {
            $result['elements'][] = $element->getStructure($resolutions);
        }

        return $result;
    }

    /**
     * Собирает класс для блока.
     * @param string|null $name Класс.
     * @return string
     */
    public function makeStyleClass($name = null)
    {
        $class = !empty($this->class) ? $this->class : 'block';
        $class .= '-'.$this->getId();

        if (!empty($name))
            $class .= '-'.$name;

        return $class;
    }

    /**
     * Подключает заголовки блока.
     */
    public function includeHeaders()
    {
        Core::$app->web->css->addString($this->getStyle());

        /** @var Element $element */
        foreach ($this->_elements as $element)
            $element->includeHeaders();
    }

    /**
     * Создает стили блока.
     * @return null|string
     */
    public function getStyle()
    {
        if ($this->_resolutions->isEmpty())
            return null;

        $style = [];
        $resolutionDefault = $this->_resolutions->getMinimum();
        $width = $resolutionDefault->getWidth();
        $height = $resolutionDefault->getHeight();
        $containers = Element::getContainers();


        $style[] = '.'.$this->makeStyleClass().'{'.
            Html::cssStyleFromArray([
                'position' => 'relative',
                'display' => 'block',
                'min-width' => $width.'px',
                'z-index' => 0
            ]).
        '}';
        $style[] = '.'.$this->makeStyleClass('wrapper').'{'.
            Html::cssStyleFromArray([
                'position' => 'relative',
                'display' => 'block',
                'width' => $width !== null ? $width.'px' : null,
                'height' => $height.'px',
                'margin' => '0 auto'
            ]).
        '}';
        $style[] = '.'.$this->makeStyleClass('elements').'{'.
            Html::cssStyleFromArray([
                'position' => 'absolute',
                'display' => 'block',
                'top' => 0,
                'left' => 0,
                'width' => '100%',
                'height' => '100%'
            ]).
        '}';

        /** @var Resolution $resolution */
        foreach ($this->_resolutions as $resolution) {
            $style[] = '@media all and (min-width: '.$resolution->getWidth().'px){'.
                '.'.$this->makeStyleClass('wrapper').' {'.
                    Html::cssStyleFromArray([
                        'width' => $resolution->getWidth().'px',
                        'height' => $resolution->getHeight().'px'
                    ]).
                '}'.
            '}';
        }

        /**
         * @param Element $element
         * @param integer $id
         * @param Resolution|null $resolution
         * @return string
         */
        $getElementStyle = function ($element, $id, $resolution = null) use (&$containers, &$resolutionDefault) {
            $style = [];

            if ($resolution === null) {
                $resolution = $resolutionDefault;
                $style[] = '.'.$element->makeStyleClass($this, $id).'{'.
                    Html::cssStyleFromArray([
                        'position' => 'absolute',
                        'width' => '100%',
                        'height' => '100%',
                        '-webkit-box-direction' => 'normal',
                        '-moz-box-direction' => 'normal',
                        '-webkit-box-orient' => 'horizontal',
                        '-moz-box-orient' => 'horizontal',
                        '-webkit-flex-direction' => 'row',
                        '-ms-flex-direction' => 'row',
                        'flex-direction' => 'row',
                        '-webkit-flex-wrap' => 'nowrap',
                        '-ms-flex-wrap' => 'nowrap',
                        'flex-wrap' => 'nowrap',
                        'visibility' => 'hidden'
                    ]).
                '}';

                $style[] = '.'.$element->makeStyleClass($this, $id, 'wrapper').'{'.
                    Html::cssStyleFromArray([
                        'position' => 'relative',
                        '-webkit-box-ordinal-group' => 1,
                        '-moz-box-ordinal-group' => 1,
                        '-webkit-order' => 0,
                        '-ms-flex-order' => 0,
                        'order' => 0,
                        '-webkit-box-flex' => 0,
                        '-moz-box-flex' => 0,
                        '-webkit-flex' => '0 1 auto',
                        '-ms-flex' => '0 1 auto',
                        'flex' => '0 1 auto',
                        '-webkit-align-self' => 'auto',
                        '-ms-flex-item-align' => 'auto',
                        'align-self' => 'auto',
                        'visibility' => 'visible',
                        'z-index' => $element->order + 1
                    ]).
                '}';

                $style[] = '.'.$element->makeStyleClass($this, $id, 'wrapper-2').'{'.
                    Html::cssStyleFromArray([
                        'position' => 'relative',
                        'width' => '100%',
                        'height' => '100%',
                        '-webkit-box-sizing' => 'border-box',
                        '-moz-box-sizing' => 'border-box',
                        'box-sizing' => 'border-box'
                    ]).
                '}';

                $style[] = '.'.$element->makeStyleClass($this, $id, 'wrapper-3').'{'.
                    Html::cssStyleFromArray([
                        'position' => 'relative',
                        'width' => '100%',
                        'height' => '100%'
                    ]).
                '}';
            }

            $display = $element->getAttribute(
                'display',
                $resolution
            );
            $container = $element->getAttribute(
                'container',
                $resolution
            );
            $xAxis = $element->getAttribute(
                'xAxis',
                $resolution
            );
            $x = $element->getAttribute(
                'x',
                $resolution
            );

            if ($x != 0)
                $x .= $element->getAttribute(
                    'xMeasure',
                    $resolution
                );

            $yAxis = $element->getAttribute(
                'yAxis',
                $resolution
            );
            $y = $element->getAttribute(
                'y',
                $resolution
            );

            if ($y != 0)
                $y .= $element->getAttribute(
                    'yMeasure',
                    $resolution
                );

            $width = $element->getAttribute(
                'width',
                $resolution
            );
            $height =  $element->getAttribute(
                'height',
                $resolution
            );

            if ($width !== null) {
                $width .= $element->getAttribute(
                    'widthMeasure',
                    $resolution
                );
            } else {
                $width = 'auto';
            }

            if ($height !== null) {
                $height .= $element->getAttribute(
                    'heightMeasure',
                    $resolution
                );
            } else {
                $height = 'auto';
            }

            $indents = $element->getAttribute(
                'indents',
                $resolution
            );
            $indentTop = $element->getAttribute(
                'indentTop',
                $resolution
            );
            $indentBottom = $element->getAttribute(
                'indentBottom',
                $resolution
            );
            $indentLeft = $element->getAttribute(
                'indentLeft',
                $resolution
            );
            $indentRight = $element->getAttribute(
                'indentRight',
                $resolution
            );

            if ($indents && $indentTop !== null) {
                $indentTop .= $element->getAttribute(
                    'indentTopMeasure',
                    $resolution
                );
            } else {
                $indentTop = 0;
            }

            if ($indents && $indentBottom !== null) {
                $indentBottom .= $element->getAttribute(
                    'indentBottomMeasure',
                    $resolution
                );
            } else {
                $indentBottom = 0;
            }

            if ($indents && $indentLeft !== null) {
                $indentLeft .= $element->getAttribute(
                    'indentLeftMeasure',
                    $resolution
                );
            } else {
                $indentLeft = 0;
            }

            if ($indents && $indentRight !== null) {
                $indentRight .= $element->getAttribute(
                    'indentRightMeasure',
                    $resolution
                );
            } else {
                $indentRight = 0;
            }

            $alignment = [
                '-webkit-box-pack' => 'start',
                '-moz-box-pack' => 'start',
                '-webkit-justify-content' => 'flex-start',
                '-ms-flex-pack' => 'start',
                'justify-content' => 'flex-start',

                '-webkit-box-align' => 'start',
                '-moz-box-align' => 'start',
                '-webkit-align-items' => 'flex-start',
                '-ms-flex-align' => 'start',
                'align-items' => 'flex-start'
            ];

            if ($xAxis === Element::X_AXIS_CENTER) {
                $alignment['-webkit-box-pack'] = 'center';
                $alignment['-moz-box-pack'] = 'center';
                $alignment['-webkit-justify-content'] = 'center';
                $alignment['-ms-flex-pack'] = 'center';
                $alignment['justify-content'] = 'center';
            } else if ($xAxis === Element::X_AXIS_RIGHT) {
                $alignment['-webkit-box-pack'] = 'end';
                $alignment['-moz-box-pack'] = 'end';
                $alignment['-webkit-justify-content'] = 'flex-end';
                $alignment['-ms-flex-pack'] = 'end';
                $alignment['justify-content'] = 'flex-end';
            }

            if ($yAxis === Element::Y_AXIS_CENTER) {
                $alignment['-webkit-box-align'] = 'center';
                $alignment['-moz-box-align'] = 'center';
                $alignment['-webkit-align-items'] = 'center';
                $alignment['-ms-flex-align'] = 'center';
                $alignment['align-items'] = 'center';
            } else if ($yAxis === Element::Y_AXIS_BOTTOM) {
                $alignment['-webkit-box-align'] = 'end';
                $alignment['-moz-box-align'] = 'end';
                $alignment['-webkit-align-items'] = 'flex-end';
                $alignment['-ms-flex-align'] = 'end';
                $alignment['align-items'] = 'flex-end';
            }

            $style[] = '.'.$element->makeStyleClass($this, $id).'{'.
                Html::cssStyleFromArray($alignment).
            '}';

            $style[] = '.'.$element->makeStyleClass($this, $id, 'wrapper').'{'.
                Html::cssStyleFromArray([
                    'top' => $y,
                    'left' => $x,
                    'width' => $width,
                    'height' => $height
                ]).
            '}';

            $style[] = '.'.$element->makeStyleClass($this, $id, 'wrapper-2').'{'.
                Html::cssStyleFromArray([
                    'padding-top' => $indentTop,
                    'padding-bottom' => $indentBottom,
                    'padding-left' => $indentLeft,
                    'padding-right' => $indentRight
                ]).
            '}';

            foreach ($containers as $key => $name) {
                $style[] =
                    '.'.$this->makeStyleClass('elements').
                    '.'.$this->makeStyleClass('elements-'.$key).
                    ' .'.$element->makeStyleClass($this, $id).'{'.
                    Html::cssStyleFromArray([
                        'display' => $container == $key && $display ? [
                            '-webkit-box',
                            '-moz-box',
                            '-ms-flexbox',
                            '-webkit-flex',
                            'flex'
                        ] : 'none'
                    ]).
                '}';
            }

            return implode('', $style);
        };

        $index = 0;

        /** @var Element $element */
        foreach ($this->_elements as $element) {
            $elementStyle = $getElementStyle($element, $index);
            $elementStyle .= $element->getStyle($this, $index, null);
            $elementStyle .= $element->getStyle($this, $index, $resolutionDefault);

            $style[] = $elementStyle;

            /** @var Resolution $resolution */
            foreach ($this->_resolutions as $resolution) {
                $elementStyle = $getElementStyle($element, $index, $resolution);
                $elementStyle .= $element->getStyle($this, $index, $resolution);

                $style[] = '@media all and (min-width: '.$resolution->getWidth().'px) {'.
                    $elementStyle.
                '}';
            }

            $index++;
        }

        return implode('', $style);
    }

    /**
     * Создает верстку блока.
     * @param bool $out
     * @return string|null
     */
    public function render($out = false)
    {
        if ($this->_resolutions->isEmpty())
            return null;

        /**
         * @param Element $element
         * @param integer $id
         * @return string
         */
        $renderElement = function ($element, $id) {
            $html = [];
            $html[] = Html::beginTag('div', [
                'class' => $element->makeStyleClass($this, $id)
            ]);
            $html[] = Html::beginTag('div', [
                'class' => $element->makeStyleClass($this, $id, 'wrapper')
            ]);
            $html[] = Html::beginTag('div', [
                'class' => $element->makeStyleClass($this, $id, 'wrapper-2')
            ]);
            $html[] = Html::beginTag('div', [
                'class' => $element->makeStyleClass($this, $id, 'wrapper-3')
            ]);
            $html[] = $element->render(true, false,$this, $id);
            $html[] = Html::endTag('div');
            $html[] = Html::endTag('div');
            $html[] = Html::endTag('div');
            $html[] = Html::endTag('div');

            return implode('', $html);
        };

        $html = [];
        $html[] = Html::beginTag('div', [
            'class' => $this->makeStyleClass()
        ]);
        $html[] = Html::beginTag('div', [
            'class' => $this->makeStyleClass('wrapper')
        ]);
        $html[] = Html::beginTag('div', [
            'class' =>
                $this->makeStyleClass('elements').' '.
                $this->makeStyleClass('elements-'.Element::CONTAINER_GRID)
        ]);

        $index = 0;

        /** @var Element $element */
        foreach ($this->_elements as $element) {
            $html[] = $renderElement($element, $index);
            $index++;
        }

        $html[] = Html::endTag('div');
        $html[] = Html::endTag('div');

        $html[] = Html::beginTag('div', [
            'class' =>
                $this->makeStyleClass('elements').' '.
                $this->makeStyleClass('elements-'.Element::CONTAINER_WINDOW)
        ]);

        $index = 0;

        /** @var Element $element */
        foreach ($this->_elements as $element) {
            $html[] = $renderElement($element, $index);
            $index++;
        }

        $html[] = Html::endTag('div');
        $html[] = Html::endTag('div');
        $html = implode('', $html);

        if ($out) {
            echo $html;
        } else {
            return $html;
        }

        return null;
    }
}