# All files / composer/utils/draft-js-custom-plugins/draft-decorator CompositeNestableDecorator.js

6.9% Statements 2/29
0% Branches 0/4
0% Functions 0/13
7.41% Lines 2/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78

    1x
    1x

     /* eslint-disable react/jsx-filename-extension */

    /**
     * Custom decorator class that allows to decorate overlapping entities.
     * Matches the type definition [DraftDecoratorType](https://github.com/facebook/draft-js/
     * blob/master/src/model/decorators/DraftDecoratorType.js)
     * Modified from <https://github.com/facebook/draft-js/issues/246#issuecomment-221120915>,
     * itself modified from <https://github.com/facebook/draft-js/blob/master/src/model/
     * decorators/CompositeDraftDecorator.js>
     */

    import React from 'react';
    import { List } from 'immutable';

    const DELIMITER = ':';
    const DECORATOR_DELIMITER = ',';

    function occupySlice(targetArr, start, end, componentKey) {
      for (let ii = start; ii < end; ii++) {
        if (targetArr[ii]) {
          targetArr[ii] = targetArr[ii] + DECORATOR_DELIMITER + componentKey;
        } else {
          targetArr[ii] = componentKey;
        }
      }
    }

    class NestableDecorator {
      constructor(decorators) {
        // Copy the decorator array, since we use this array order to determine
        // precedence of decoration matching. If the array is mutated externally,
        // we don't want to be affected here.
        this.decorators = decorators.slice();

        this.componentCache = {};
      }

      getDecorations(block, contentState) {
        const decorations = Array(block.getText().length).fill(null);

        this.decorators.forEach((decorator, ii) => {
          let counter = 0;
          const strategy = decorator.strategy;

          strategy(block, (start, end) => {
            occupySlice(decorations, start, end, ii + DELIMITER + counter);
            counter++;
          }, contentState);
        });

        return List(decorations);
      }

      getComponentForKey(key) {
        if (this.componentCache[key]) return this.componentCache[key];

        const components = key.split(DECORATOR_DELIMITER)
          .map((k) => parseInt(k.split(DELIMITER)[0], 10))
          .map((k) => this.decorators[k].component);

        this.componentCache[key] = (props) => (
          components.reduce((children, Outer) => <Outer {...props}>{children}</Outer>, props.children)
        );

        return this.componentCache[key];
      }

      getPropsForKey(key) {
        const pps = key.split(DECORATOR_DELIMITER)
          .map((k) => parseInt(k.split(DELIMITER)[0], 10))
          .map((k) => this.decorators[k].props);

        return Object.assign({}, ...pps);
      }
    }

    export default NestableDecorator;