"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

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

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

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

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

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

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

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

var _propTypes = _interopRequireDefault(require("prop-types"));

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

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

var _reactTinymce = _interopRequireDefault(require("react-tinymce"));

var _editorAccessibility = _interopRequireDefault(require("./editorAccessibility"));

var contentInsertion = _interopRequireWildcard(require("./contentInsertion"));

var _indicatorRegion = _interopRequireDefault(require("./indicatorRegion"));

var _indicate = _interopRequireDefault(require("../common/indicate"));

var _bridge = _interopRequireDefault(require("../bridge"));

/*
 * Copyright (C) 2018 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */
var editorWrappers = new WeakMap();

var RCEWrapper =
/*#__PURE__*/
function (_React$Component) {
  (0, _inherits2.default)(RCEWrapper, _React$Component);
  (0, _createClass2.default)(RCEWrapper, null, [{
    key: "getByEditor",
    value: function getByEditor(editor) {
      return editorWrappers.get(editor);
    }
  }]);

  function RCEWrapper(props) {
    var _this;

    (0, _classCallCheck2.default)(this, RCEWrapper);
    _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(RCEWrapper).call(this, props)); // interface consistent with editorBox

    _this.handleTextareaChange = function () {
      if (_this.isHidden()) {
        _this.setCode(_this.textareaValue());
      }
    };

    _this.get_code = _this.getCode;
    _this.set_code = _this.setCode;
    _this.insert_code = _this.insertCode; // test override points

    _this.indicator = false;
    return _this;
  } // getCode and setCode naming comes from tinyMCE
  // kind of strange but want to be consistent


  (0, _createClass2.default)(RCEWrapper, [{
    key: "getCode",
    value: function getCode() {
      return this.isHidden() ? this.textareaValue() : this.mceInstance().getContent();
    }
  }, {
    key: "setCode",
    value: function setCode(newContent) {
      this.mceInstance().setContent(newContent);
    }
  }, {
    key: "indicateEditor",
    value: function indicateEditor(element) {
      var editor = this.mceInstance();

      if (this.indicator) {
        this.indicator(editor, element);
      } else if (!this.isHidden()) {
        (0, _indicate.default)((0, _indicatorRegion.default)(editor, element));
      }
    }
  }, {
    key: "contentInserted",
    value: function contentInserted(element) {
      this.indicateEditor(element);
      this.checkImageLoadError(element);
    }
  }, {
    key: "checkImageLoadError",
    value: function checkImageLoadError(element) {
      var _this2 = this;

      if (!element || element.tagName !== "IMG") {
        return;
      }

      if (!element.complete) {
        element.onload = function () {
          return _this2.checkImageLoadError(element);
        };

        return;
      } // checking naturalWidth in a future event loop run prevents a race
      // condition between the onload callback and naturalWidth being set.


      setTimeout(function () {
        if (element.naturalWidth === 0) {
          element.style.border = "1px solid #000";
          element.style.padding = "2px";
        }
      }, 0);
    }
  }, {
    key: "insertCode",
    value: function insertCode(code) {
      var editor = this.mceInstance();
      var element = contentInsertion.insertContent(editor, code);
      this.contentInserted(element);
    }
  }, {
    key: "insertImage",
    value: function insertImage(image) {
      var _this3 = this;

      var editor = this.mceInstance();
      var element = contentInsertion.insertImage(editor, image);

      if (element && element.complete) {
        this.contentInserted(element);
      } else if (element) {
        element.onload = function () {
          return _this3.contentInserted(element);
        };

        element.onerror = function () {
          return _this3.checkImageLoadError(element);
        };
      }
    }
  }, {
    key: "insertLink",
    value: function insertLink(link) {
      var editor = this.mceInstance();
      var element = contentInsertion.insertLink(editor, link);
      this.contentInserted(element);
    }
  }, {
    key: "existingContentToLink",
    value: function existingContentToLink() {
      var editor = this.mceInstance();
      return contentInsertion.existingContentToLink(editor);
    }
  }, {
    key: "existingContentToLinkIsImg",
    value: function existingContentToLinkIsImg() {
      var editor = this.mceInstance();
      return contentInsertion.existingContentToLinkIsImg(editor);
    }
  }, {
    key: "mceInstance",
    value: function mceInstance() {
      var _this4 = this;

      var editors = this.props.tinymce.editors || [];
      return editors.filter(function (ed) {
        return ed.id === _this4.props.textareaId;
      })[0];
    }
  }, {
    key: "onTinyMCEInstance",
    value: function onTinyMCEInstance(command) {
      if (command == "mceRemoveEditor") {
        var editor = this.mceInstance();

        if (editor) {
          editor.execCommand("mceNewDocument");
        } // makes sure content can't persist past removal

      }

      this.props.tinymce.execCommand(command, false, this.props.textareaId);
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this._destroyCalled = true;
      this.onTinyMCEInstance("mceRemoveEditor");
      this.unhandleTextareaChange();
      this.props.handleUnmount && this.props.handleUnmount();
    }
  }, {
    key: "onRemove",
    value: function onRemove() {
      _reactDom.default.unmountComponentAtNode(_reactDom.default.findDOMNode(this.refs.rce));

      _bridge.default.detachEditor(this);

      this.props.onRemove && this.props.onRemove(this);
    }
  }, {
    key: "getTextarea",
    value: function getTextarea() {
      return document.getElementById(this.props.textareaId);
    }
  }, {
    key: "textareaValue",
    value: function textareaValue() {
      return this.getTextarea().value;
    }
  }, {
    key: "toggle",
    value: function toggle() {
      if (this.isHidden()) {
        this.setCode(this.textareaValue());
      }

      this.onTinyMCEInstance("mceToggleEditor");
    }
  }, {
    key: "focus",
    value: function focus() {
      this.onTinyMCEInstance("mceFocus");
    }
  }, {
    key: "is_dirty",
    value: function is_dirty() {
      var content = this.isHidden() ? this.textareaValue() : this.mceInstance().getContent();
      return content !== this.cleanInitialContent();
    }
  }, {
    key: "cleanInitialContent",
    value: function cleanInitialContent() {
      if (!this._cleanInitialContent) {
        var el = window.document.createElement("div");
        el.innerHTML = this.props.defaultContent;
        var serializer = this.mceInstance().serializer;
        this._cleanInitialContent = serializer.serialize(el, {
          getInner: true
        });
      }

      return this._cleanInitialContent;
    }
  }, {
    key: "isHidden",
    value: function isHidden() {
      return this.mceInstance().isHidden();
    }
  }, {
    key: "onFocus",
    value: function onFocus() {
      _bridge.default.focusEditor(this);

      this.props.onFocus && this.props.onFocus(this);
    }
  }, {
    key: "call",
    value: function call(methodName) {
      // since exists? has a ? and cant be a regular function just return true
      // rather than calling as a fn on the editor
      if (methodName === "exists?") {
        return true;
      }

      for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
        args[_key - 1] = arguments[_key];
      }

      return this[methodName].apply(this, args);
    }
  }, {
    key: "annotateEditor",
    value: function annotateEditor(_e, editor) {
      editor.rceWrapper = this;
    }
  }, {
    key: "accessibilizeEditor",
    value: function accessibilizeEditor(_e, editor) {
      var accessibleEditor = new _editorAccessibility.default(editor, document);
      accessibleEditor.addLabels();
      accessibleEditor.accessibilizeMenubar();
      accessibleEditor.removeStatusbarFromTabindex();
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      if (!this._destroyCalled) {
        this.destroy();
      }
    }
  }, {
    key: "wrapOptions",
    value: function wrapOptions() {
      var _this5 = this;

      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      var setupCallback = options.setup;

      options.setup = function (editor) {
        editorWrappers.set(editor, _this5);

        if (typeof setupCallback === "function") {
          setupCallback(editor);
        }
      };

      return options;
    }
  }, {
    key: "unhandleTextareaChange",
    value: function unhandleTextareaChange() {
      if (this._textareaEl) {
        this._textareaEl.removeEventListener("change", this.handleTextareaChange);
      }
    }
  }, {
    key: "registerTextareaChange",
    value: function registerTextareaChange() {
      var el = this.getTextarea();

      if (this._textareaEl !== el) {
        this.unhandleTextareaChange();
        el.addEventListener("change", this.handleTextareaChange);
        this._textareaEl = el;
      }
    }
  }, {
    key: "componentDidMount",
    value: function componentDidMount() {
      this.registerTextareaChange();
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate() {
      this.registerTextareaChange();
    }
  }, {
    key: "render",
    value: function render() {
      return _react.default.createElement(_reactTinymce.default, {
        ref: "rce",
        id: this.props.textareaId,
        tinymce: this.props.tinymce,
        className: this.props.textareaClassName,
        onPreInit: this.annotateEditor.bind(this),
        onInit: this.accessibilizeEditor.bind(this),
        onClick: this.onFocus.bind(this),
        onKeypress: this.onFocus.bind(this),
        onActivate: this.onFocus.bind(this),
        onRemove: this.onRemove.bind(this),
        content: this.props.defaultContent,
        config: this.wrapOptions(this.props.editorOptions)
      });
    }
  }]);
  RCEWrapper.displayName = "RCEWrapper";
  return RCEWrapper;
}(_react.default.Component);

exports.default = RCEWrapper;
RCEWrapper.propTypes = {
  defaultContent: _propTypes.default.string,
  language: _propTypes.default.string,
  tinymce: _propTypes.default.object,
  textareaId: _propTypes.default.string,
  textareaClassName: _propTypes.default.string,
  editorOptions: _propTypes.default.object,
  onFocus: _propTypes.default.func,
  onRemove: _propTypes.default.func,
  handleUnmount: _propTypes.default.func
};