Home Reference Source

src/components/layouts/LayoutPlaceResolver.jsx

/**
 * Created by emamoshin on 06.10.2017.
 */
import React from 'react';
import PropTypes from 'prop-types';
import isPlainObject from 'lodash.isplainobject';
import isArray from 'lodash.isarray';

/**
 * НОС парсит все children {@link Section} внутри какого-то Layout, содержимое которых будет расположено внутри {@link Place}
 * @example
 * layoutPlaceResolver(StandardWidgetLayout)
 */
const layoutPlaceResolver = LayoutComponent => {
  class LayoutComponentHOC extends React.Component {
    constructor(props) {
      super(props);
      this.getSection = this.getSection.bind(this);
      this.getParentProps = this.getParentProps.bind(this);
      this.parseSections = this.parseSections.bind(this);
    }

    /**
     * создание контекста
     * @return {{getSection: LayoutComponentHOC.getSection, getParentProps: LayoutComponentHOC.getParentProps}}
     */
    getChildContext() {
      return {
        getSection: this.getSection,
        getParentProps: this.getParentProps,
      };
    }

    /**
     * Вызов метода парсинга секций
     */
    componentWillMount() {
      this._sections = this.parseSections(this.props.children);
    }

    componentWillReceiveProps(props) {
      this._sections = this.parseSections(props.children);
    }
    /**
     * создание контекста
     * @return {{getSection: LayoutComponentHOC.getSection, getParentProps: LayoutComponentHOC.getParentProps}}
     */
    getSection(place) {
      return this._sections[place] || false;
    }

    /**
     * Парсинг всех дочерних секций
     * @param children
     * @return {*}
     */
    parseSections(children) {
      if (isPlainObject(children)) {
        if (children.type && children.type.displayName === 'Section') {
          return { [children.props.place]: children };
        }
        return {};
      } else if (isArray(children)) {
        let sections = [];
        for (let i = 0, c = children.length; i < c; i += 1) {
          sections = Object.assign(
            {},
            sections,
            this.parseSections(children[i])
          );
        }
        return sections;
      }
      return {};
    }

    /**
     * Получение родительских проспсов (передается в контекст)
     */
    getParentProps() {
      const { children, ...props } = this.props;
      return props;
    }

    /**
     * Рендер компонента-аргумента HOC
     */
    render() {
      return <LayoutComponent {...this.props} />;
    }
  }

  LayoutComponentHOC.childContextTypes = {
    getSection: PropTypes.func.isRequired,
    getParentProps: PropTypes.func.isRequired,
  };

  return LayoutComponentHOC;
};

export default layoutPlaceResolver;