"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = CSSPlugin;
exports.removeDialogs = void 0;

var _react = _interopRequireDefault(require("react"));

var _reactDom = _interopRequireDefault(require("react-dom"));

var _List = _interopRequireDefault(require("@material-ui/core/List"));

var _slate = require("slate");

var _immutable = _interopRequireDefault(require("immutable"));

var _ListItem = _interopRequireDefault(require("@material-ui/core/ListItem"));

var _isEmpty = _interopRequireDefault(require("lodash/isEmpty"));

var _debug = _interopRequireDefault(require("debug"));

var _icons = _interopRequireDefault(require("./icons"));

var log = (0, _debug["default"])('@pie-lib:editable-html:plugins:characters');

var removeDialogs = function removeDialogs() {
  var prevDialogs = document.querySelectorAll('.insert-css-dialog');
  log('[characters:removeDialogs]');
  prevDialogs.forEach(function (s) {
    return s.remove();
  });
};

exports.removeDialogs = removeDialogs;

var insertDialog = function insertDialog(_ref) {
  var _parentNode$data, _parentNode$data$get;

  var editorDOM = _ref.editorDOM,
      value = _ref.value,
      callback = _ref.callback,
      opts = _ref.opts,
      textNode = _ref.textNode,
      parentNode = _ref.parentNode;
  var newEl = document.createElement('div');
  log('[characters:insertDialog]');
  removeDialogs();
  newEl.className = 'insert-css-dialog';
  var popoverEl;

  var closePopOver = function closePopOver() {
    if (popoverEl) {
      popoverEl.remove();
    }
  };

  var firstCallMade = false;

  var listener = function listener(e) {
    // this will be triggered right after setting it because
    // this toolbar is added on the mousedown event
    // so right after mouseup, the click will be triggered
    if (firstCallMade) {
      var focusIsInModals = newEl.contains(e.target) || popoverEl && popoverEl.contains(e.target);
      var focusIsInEditor = editorDOM.contains(e.target);

      if (!(focusIsInModals || focusIsInEditor)) {
        handleClose();
      }
    } else {
      firstCallMade = true;
    }
  };

  var handleClose = function handleClose() {
    callback(undefined, true);
    newEl.remove();
    closePopOver();
    document.body.removeEventListener('click', listener);
  };

  var handleChange = function handleChange(name) {
    callback(name, true);
    newEl.remove();
    closePopOver();
    document.body.removeEventListener('click', listener);
  };

  var selectedText = textNode.text.slice(value.selection.anchorOffset, value.selection.focusOffset);
  var parentNodeClass = parentNode === null || parentNode === void 0 ? void 0 : (_parentNode$data = parentNode.data) === null || _parentNode$data === void 0 ? void 0 : (_parentNode$data$get = _parentNode$data.get('attributes')) === null || _parentNode$data$get === void 0 ? void 0 : _parentNode$data$get["class"];

  var createHTML = function createHTML(name) {
    var html = "<span class=\"".concat(name, "\">").concat(selectedText, "</span>");

    if (parentNode) {
      var tag;

      if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.object) === 'inline') {
        tag = 'span';
      }

      if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.object) === 'block') {
        tag = 'div';
      }

      html = "<".concat(tag, " class=\"").concat(parentNodeClass, "\">").concat(parentNode.text.slice(0, value.selection.anchorOffset)).concat(html).concat(parentNode.text.slice(value.selection.focusOffset), "</").concat(tag, ">");
    }

    return html;
  };

  var el = /*#__PURE__*/_react["default"].createElement("div", {
    style: {
      background: 'white',
      height: 500,
      padding: 20,
      overflow: 'hidden',
      display: 'flex',
      flexFlow: 'column'
    }
  }, /*#__PURE__*/_react["default"].createElement("h2", null, "Please choose a css class"), parentNodeClass && /*#__PURE__*/_react["default"].createElement("div", null, "The current parent has this class ", parentNodeClass), /*#__PURE__*/_react["default"].createElement(_List["default"], {
    component: "nav",
    style: {
      overflow: 'scroll'
    }
  }, opts.names.map(function (name, i) {
    return /*#__PURE__*/_react["default"].createElement(_ListItem["default"], {
      key: "rule-".concat(i),
      button: true,
      onClick: function onClick() {
        return handleChange(name);
      }
    }, /*#__PURE__*/_react["default"].createElement("div", {
      style: {
        marginRight: 20
      }
    }, name), /*#__PURE__*/_react["default"].createElement("div", {
      dangerouslySetInnerHTML: {
        __html: createHTML(name)
      }
    }));
  })));

  _reactDom["default"].render(el, newEl, function () {
    var cursorItem = document.querySelector("[data-key=\"".concat(value.anchorKey, "\"]"));

    if (cursorItem) {
      var bodyRect = editorDOM.parentElement.parentElement.parentElement.getBoundingClientRect();
      var boundRect = cursorItem.getBoundingClientRect();
      editorDOM.parentElement.parentElement.parentElement.appendChild(newEl); // when height of toolbar exceeds screen - can happen in scrollable contexts

      var additionalTopOffset = 0;

      if (boundRect.y < newEl.offsetHeight) {
        additionalTopOffset = newEl.offsetHeight - boundRect.y + 10;
      }

      newEl.style.maxWidth = '500px';
      newEl.style.position = 'absolute';
      newEl.style.top = 0;
      newEl.style.zIndex = 99999;
      var leftValue = "".concat(boundRect.left + Math.abs(bodyRect.left) + cursorItem.offsetWidth + 10, "px");
      var rightValue = "".concat(boundRect.x, "px");
      newEl.style.left = leftValue;
      var leftAlignedWidth = newEl.offsetWidth;
      newEl.style.left = 'unset';
      newEl.style.right = rightValue;
      var rightAlignedWidth = newEl.offsetWidth;
      newEl.style.left = 'unset';
      newEl.style.right = 'unset';

      if (leftAlignedWidth >= rightAlignedWidth) {
        newEl.style.left = leftValue;
      } else {
        newEl.style.right = rightValue;
      }

      document.body.addEventListener('click', listener);
    }
  });
};

var findParentNodeInfo = function findParentNodeInfo(value, textNode) {
  var _closestInline$nodes, _closestBlock$nodes;

  var closestInline = value.document.getClosestInline(value.selection.endKey);
  var closestBlock = value.document.getClosestBlock(value.selection.endKey);
  var nodeToUse = null;

  if (closestInline !== null && closestInline !== void 0 && (_closestInline$nodes = closestInline.nodes) !== null && _closestInline$nodes !== void 0 && _closestInline$nodes.find(function (n) {
    return n.key === textNode.key;
  })) {
    nodeToUse = closestInline;
  }

  if (closestBlock !== null && closestBlock !== void 0 && (_closestBlock$nodes = closestBlock.nodes) !== null && _closestBlock$nodes !== void 0 && _closestBlock$nodes.find(function (n) {
    return n.key === textNode.key;
  })) {
    nodeToUse = closestBlock;
  }

  return nodeToUse;
};
/**
 * Find the node that has a class attribute and return it.
 * Keeping this in case the implementation of classes needs to be changed
 * @param value
 * @param opts
 * @returns {*}
 */


var getNodeWithClass = function getNodeWithClass(value, opts) {
  var _blocksAtRange$, _inlinesAtRange$, _blockData$attributes, _inlineData$attribute;

  var blocksAtRange = value.document.getBlocksAtRangeAsArray(value.selection);
  var inlinesAtRange = value.document.getInlinesAtRangeAsArray(value.selection);
  var blockData = ((_blocksAtRange$ = blocksAtRange[0]) === null || _blocksAtRange$ === void 0 ? void 0 : _blocksAtRange$.data.toJSON()) || {};
  var inlineData = ((_inlinesAtRange$ = inlinesAtRange[0]) === null || _inlinesAtRange$ === void 0 ? void 0 : _inlinesAtRange$.data.toJSON()) || {};

  if (!((_blockData$attributes = blockData.attributes) !== null && _blockData$attributes !== void 0 && _blockData$attributes["class"]) && !((_inlineData$attribute = inlineData.attributes) !== null && _inlineData$attribute !== void 0 && _inlineData$attribute["class"])) {
    return null;
  }

  var _ref2 = blockData.attributes || {},
      blockClass = _ref2["class"];

  var _ref3 = inlineData.attributes || {},
      inlineClass = _ref3["class"];

  var inlineHasClass = opts.names.find(function (name) {
    return inlineClass.includes(name);
  });

  if (inlineHasClass) {
    return inlinesAtRange[0];
  }

  var blockHasClass = opts.names.find(function (name) {
    return blockClass.includes(name);
  });

  if (blockHasClass) {
    return blocksAtRange[0];
  }

  return null;
};
/**
 * Plugin in order to be able to add a css clas that is provided through the model
 * on a text element. Works like a mark (bold, italic etc.).
 * @param opts
 * @constructor
 */


function CSSPlugin(opts) {
  var plugin = {
    name: 'extraCSSRules',
    toolbar: {
      isMark: true,
      icon: /*#__PURE__*/_react["default"].createElement(_icons["default"], null),
      ariaLabel: 'CSS editor',
      type: 'css',
      onToggle: function onToggle(change) {
        var type = 'css';
        var hasMark = change.value.activeMarks.find(function (entry) {
          return entry.type === type;
        });

        if (hasMark) {
          change.removeMark(hasMark);
        } else {
          var newMark = _slate.Mark.create(type);

          change.addMark(newMark);
        }

        return change;
      },
      onClick: function onClick(value, onChange, getFocusedValue) {
        var type = 'css';
        var hasMark = value.activeMarks.find(function (entry) {
          return entry.type === type;
        });
        var change = value.change();

        if (hasMark) {
          change.removeMark(hasMark);
          onChange(change);
          return;
        } // keeping this if implementation needs to be changed to regular blocks instead of marks
        // let nodeWithClass = getNodeWithClass(value, opts);
        //
        // if (nodeWithClass) {
        //   const nodeAttributes = nodeWithClass.data.get('attributes');
        //
        //   opts.names.forEach((name) => {
        //     if (nodeAttributes.class.includes(name)) {
        //       nodeAttributes.class = nodeAttributes.class.replace(name, '');
        //     }
        //   });
        //
        //   // keeping only one space between classes
        //   nodeAttributes.class = nodeAttributes.class.replace(/ +/g, ' ');
        //
        //   nodeWithClass.data.set('attributes', nodeAttributes);
        //
        //   let change = value.change();
        //   change.replaceNodeByKey(nodeWithClass.key, nodeWithClass);
        //
        //   onChange(change);
        //   return;
        // }


        var editorDOM = document.querySelector("[data-key=\"".concat(value.document.key, "\"]"));
        var valueToUse = value;

        var callback = function callback(className, focus) {
          if (getFocusedValue) {
            valueToUse = getFocusedValue() || valueToUse;
          }

          if (className) {
            var _change = valueToUse.change();

            var newMark = _slate.Mark.create({
              object: 'mark',
              type: 'css',
              data: {
                attributes: {
                  "class": className
                }
              }
            });

            _change.addMark(newMark); // keeping this if implementation needs to be changed to regular blocks instead of marks
            // change = change.wrapInline({ type: 'span', data: { attributes: { class: className } } });
            //
            // // change = change.splitBlockAtRange(adaptedRange);
            // //
            // // const newBlock = change.value.document.getFurthestBlock(change.value.selection.endKey);
            // //
            // // change = change.setNodeByKey(newBlock.key, { data: { attributes: { class: className } } });
            //
            // valueToUse = change.value;
            // log('[characters:insert]: ', value);


            onChange(_change);
          }

          log('[characters:click]');

          if (focus) {
            setTimeout(function () {
              if (editorDOM) {
                editorDOM.focus();
              }
            }, 0);
          }
        };

        var textNode = value.document.getTextsAtRangeAsArray(value.selection)[0];

        if (textNode) {
          var parentNode = findParentNodeInfo(value, textNode, opts);
          insertDialog({
            editorDOM: editorDOM,
            value: valueToUse,
            callback: callback,
            opts: opts,
            textNode: textNode,
            parentNode: parentNode
          });
        }
      }
    },
    renderMark: function renderMark(props) {
      if (props.mark.type === 'css') {
        var _ref4 = props.mark || {},
            data = _ref4.data;

        var jsonData = (data === null || data === void 0 ? void 0 : data.toJSON()) || {};
        return /*#__PURE__*/_react["default"].createElement("span", jsonData.attributes, props.children);
      }
    }
  };
  return plugin;
}
//# sourceMappingURL=index.js.map