draft-js#EditorState JavaScript Examples

The following examples show how to use draft-js#EditorState. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.js    From weve with Apache License 2.0 6 votes vote down vote up
constructor() {
		super();

		this.state= {
			recipient: '', // Initialize empty recipient
			subject: '', // Initialize empty subject
			numTokens: 0, // Initialize AR tokens to send to 0
			transactionLoading: false, // Set loading status to false
			editorState: EditorState.createEmpty() // Initialize react-draft
		}
	}
Example #2
Source File: markdownInput.js    From turqV2 with GNU General Public License v3.0 6 votes vote down vote up
constructor(props) {
    super(props);
    if(this.props.initialState != null) {
      this.state = {editorState: EditorState.createWithContent(this.props.initialState)}
    } else {
      this.state = {editorState: EditorState.createEmpty()};
    }
    this.onChange = editorState => {this.setState({editorState}); this.props.onChange(editorState, this.props.name)};
    this.handleKeyCommand = this.handleKeyCommand.bind(this);
    this.toggleBlockType = this._toggleBlockType.bind(this);
    this.toggleInlineStyle = this._toggleInlineStyle.bind(this);
  }
Example #3
Source File: RichTextInputArea.js    From wix-style-react with MIT License 6 votes vote down vote up
constructor(props) {
    super(props);

    const { texts: consumerTexts } = props;

    this.state = {
      editorState: EditorState.createEmpty(decorator),
      texts: {
        toolbarButtons: {
          ...defaultTexts.toolbarButtons,
          ...consumerTexts.toolbarButtons,
        },
        insertionForm: {
          ...defaultTexts.insertionForm,
          ...consumerTexts.insertionForm,
        },
      },
    };
  }
Example #4
Source File: EditorUtilities.js    From wix-style-react with MIT License 6 votes vote down vote up
_removeEntityFromBlock = (editorState, contentBlock, entity) => {
  const contentState = editorState.getCurrentContent();
  const selectionState = editorState.getSelection();

  let selectionWithEntity = null;

  contentBlock.findEntityRanges(
    character => character.getEntity() === entity,
    (start, end) => {
      // Creates a selection state that contains the whole text that's linked to the entity
      selectionWithEntity = selectionState.merge({
        anchorOffset: start,
        focusOffset: end,
      });
    },
  );

  // Removes the linking between the text and entity
  const contentStateWithoutEntity = Modifier.applyEntity(
    contentState,
    selectionWithEntity,
    null,
  );

  const newEditorState = EditorState.push(
    editorState,
    contentStateWithoutEntity,
    'apply-entity',
  );

  return RichUtils.toggleLink(newEditorState, selectionState, null);
}
Example #5
Source File: EditorUtilities.js    From wix-style-react with MIT License 6 votes vote down vote up
_attachLinkEntityToText = (editorState, { text, url }) => {
  const contentState = editorState.getCurrentContent();
  const selectionState = editorState.getSelection();
  const contentStateWithEntity = contentState.createEntity('LINK', 'MUTABLE', {
    url,
  });
  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
  const startPosition = selectionState.getStartOffset();
  const endPosition = startPosition + text.length;

  // A key for the block that containing the start of the selection range
  const blockKey = selectionState.getStartKey();

  // Replaces the content in specified selection range with text
  const contentStateWithText = Modifier.replaceText(
    contentState,
    selectionState,
    text,
  );

  const newSelectionState = new SelectionState({
    anchorOffset: startPosition,
    anchorKey: blockKey,
    focusOffset: endPosition,
    focusKey: blockKey,
  });

  const newEditorState = EditorState.push(
    editorState,
    contentStateWithText,
    'insert-characters',
  );

  return RichUtils.toggleLink(newEditorState, newSelectionState, entityKey);
}
Example #6
Source File: insertMention.js    From spring-boot-ecommerce with Apache License 2.0 6 votes vote down vote up
export default function insertMention(editorState, mention, data, mode) {
  var entityMode = mode === 'immutable' ? 'IMMUTABLE' : 'MUTABLE';
  var selection = editorState.getSelection();
  var contentState = editorState.getCurrentContent();

  contentState.createEntity('mention', entityMode, data || mention);
  var searchWord = getSearchWord(editorState, selection);
  var begin = searchWord.begin,
      end = searchWord.end;

  var replacedContent = Modifier.replaceText(contentState, selection.merge({
    anchorOffset: begin,
    focusOffset: end
  }), mention, null, contentState.getLastCreatedEntityKey());

  var InsertSpaceContent = Modifier.insertText(replacedContent, replacedContent.getSelectionAfter(), ' ');

  var newEditorState = EditorState.push(editorState, InsertSpaceContent, 'insert-mention');
  return EditorState.forceSelection(newEditorState, InsertSpaceContent.getSelectionAfter());
}
Example #7
Source File: clearMention.js    From spring-boot-ecommerce with Apache License 2.0 6 votes vote down vote up
export default function clearMention(editorState) {
  var selection = editorState.getSelection();
  var searchWord = getSearchWord(editorState, selection);
  var begin = searchWord.begin,
      end = searchWord.end;

  var replacedContent = Modifier.replaceText(editorState.getCurrentContent(), selection.merge({
    anchorOffset: begin,
    focusOffset: end
  }), '', null);

  var InsertSpaceContent = Modifier.insertText(replacedContent, replacedContent.getSelectionAfter(), ' ');

  var newEditorState = EditorState.push(editorState, InsertSpaceContent, 'insert-mention');
  return EditorState.forceSelection(newEditorState, InsertSpaceContent.getSelectionAfter());
}
Example #8
Source File: PublicationEditor.js    From paras-landing with GNU General Public License v3.0 6 votes vote down vote up
convertTextToEditorState = (text = '') =>
	EditorState.createWithContent(
		convertFromRaw({
			entityMap: {},
			blocks: [
				{
					text: text,
					key: 'title',
					type: 'unstyled',
					entityRanges: [],
				},
			],
		})
	)
Example #9
Source File: PublicationEditor.js    From paras-landing with GNU General Public License v3.0 6 votes vote down vote up
generateEditorState = (content = null) => {
	if (!content) {
		content = {
			entityMap: {},
			blocks: [
				{
					text: '',
					key: 'foo',
					type: 'unstyled',
					entityRanges: [],
				},
			],
		}
	}
	return EditorState.createWithContent(convertFromRaw(content))
}
Example #10
Source File: editorStateUtils.js    From react-mui-draft-wysiwyg with MIT License 6 votes vote down vote up
toggleMappedInlineStyle = (editorState, styleKeys, newInlineStyle) => {
    const selection = editorState.getSelection();

    // Turn off the other mapped inline styled in selection
    const newContentState = styleKeys.reduce(
        (contentState, inlineStyle) =>
            Modifier.removeInlineStyle(contentState, selection, inlineStyle),
        editorState.getCurrentContent()
    );

    let newEditorState = EditorState.push(editorState, newContentState, 'change-inline-style');

    const currentStyle = editorState.getCurrentInlineStyle();

    if (selection.isCollapsed()) {
        newEditorState = currentStyle.reduce((state, inlineStyle) => {
            return RichUtils.toggleInlineStyle(state, inlineStyle);
        }, newEditorState);
    }
    // If the inline style is being toggled on, apply it.
    if (!currentStyle.has(newInlineStyle)) {
        newEditorState = RichUtils.toggleInlineStyle(newEditorState, newInlineStyle);
    }

    return newEditorState;
}
Example #11
Source File: index.jsx    From react-mui-draft-wysiwyg with MIT License 6 votes vote down vote up
MUIEditorState = {
    createEmpty: (config) => {
        const editorFactories = new EditorFactories(config);
        return EditorState.createEmpty(editorFactories.getCompositeDecorator());
    },
    createWithContent: (config, contentState) => {
        const editorFactories = new EditorFactories(config);
        return EditorState.createWithContent(contentState, editorFactories.getCompositeDecorator());
    },
}
Example #12
Source File: index.jsx    From react-mui-draft-wysiwyg with MIT License 6 votes vote down vote up
function UndoControl() {
    const editor = useEditor();
    const editorFocus = useEditorFocus();

    const onClick = () => {
        editor.onChange(EditorState.undo(editor.editorState));
        editorFocus();
    };

    return (
        <ButtonControl onClick={onClick} text={editor.translate('controls.undo.title')}>
            <UndoIcon />
        </ButtonControl>
    );
}
Example #13
Source File: index.jsx    From react-mui-draft-wysiwyg with MIT License 6 votes vote down vote up
function RedoControl() {
    const editor = useEditor();
    const editorFocus = useEditorFocus();

    const onClick = () => {
        editor.onChange(EditorState.redo(editor.editorState));
        editorFocus();
    };

    return (
        <ButtonControl onClick={onClick} text={editor.translate('controls.redo.title')}>
            <RedoIcon />
        </ButtonControl>
    );
}
Example #14
Source File: texteditor.js    From GitMarkonics with MIT License 6 votes vote down vote up
constructor(props) {
    super(props);
    this.state = {
      editorState: EditorState.createEmpty(),
      file: "",
      value: "unstyled",
    };
    this._shortcutHandler = this._shortcutHandler.bind(this);
    this.onChange = async (editorState) => {
      await this.setState({ editorState });
      var value = await stateToHTML(this.state.editorState.getCurrentContent());
      this.setState({ file: this.replacer(value) });
      // console.log(convertToRaw(this.state.editorState.getCurrentContent()));
    };
  }
Example #15
Source File: ScriptEditor.jsx    From Spoke with MIT License 6 votes vote down vote up
getEditorState() {
    const { scriptFields, scriptText } = this.props;

    const decorator = this.getCompositeDecorator(scriptFields);
    let editorState;
    if (scriptText) {
      editorState = EditorState.createWithContent(
        ContentState.createFromText(scriptText),
        decorator
      );
    } else {
      editorState = EditorState.createEmpty(decorator);
    }

    return editorState;
  }
Example #16
Source File: ScriptEditor.jsx    From Spoke with MIT License 6 votes vote down vote up
addCustomField(field) {
    const textToInsert = delimit(field);
    const { editorState } = this.state;
    const selection = editorState.getSelection();
    const contentState = editorState.getCurrentContent();
    const newContentState = Modifier.insertText(
      contentState,
      selection,
      textToInsert
    );
    const newEditorState = EditorState.push(
      editorState,
      newContentState,
      "insert-fragment"
    );
    this.setState({ editorState: newEditorState }, this.focus);
  }
Example #17
Source File: WYSIWYG.jsx    From saasgear with MIT License 6 votes vote down vote up
WYSIWYGEditor = ({ editorContent = '', onChange, className }) => {
  const [editorState, setEditorState] = useState(EditorState.createEmpty());

  function onEditorStateChange(state) {
    setEditorState(state);
    return onChange(draftToHtml(convertToRaw(state.getCurrentContent())));
  }

  useEffect(() => {
    if (editorContent === '') {
      setEditorState(EditorState.createEmpty());
    } else {
      const contentState = EditorState.createWithContent(
        ContentState.createFromBlockArray(htmlToDraft(editorContent)),
      );

      setEditorState(contentState);
    }
  }, [editorContent]);

  return (
    <Wrapper>
      <Editor
        editorState={editorState}
        wrapperClassName="editor-wrapper"
        editorClassName="editor"
        toolbarClassName="toolbar"
        onEditorStateChange={onEditorStateChange}
      />
    </Wrapper>
  );
}
Example #18
Source File: index.jsx    From react-mui-draft-wysiwyg with MIT License 5 votes vote down vote up
function TextAlignControl() {
    const editor = useEditor();
    const editorFocus = useEditorFocus();
    const [selectedTextAlign, setSelectedTextAlign] = React.useState(null);

    React.useEffect(() => {
        const selection = editor.editorState.getSelection();
        const currentBlock = editor.editorState
            .getCurrentContent()
            .getBlockForKey(selection.getStartKey());
        const blockData = currentBlock.getData();
        if (blockData && blockData.get('textAlign')) {
            setSelectedTextAlign(blockData.get('textAlign'));
        } else {
            setSelectedTextAlign(null);
        }
    }, [editor.editorState]);

    const toggle = (textAlign) => {
        setSelectedTextAlign(textAlign);
        const { editorState } = editor;
        const newContentState = Modifier.mergeBlockData(
            editorState.getCurrentContent(),
            editorState.getSelection(),
            { textAlign }
        );
        editor.onChange(EditorState.push(editorState, newContentState, 'change-block-data'));
        editorFocus();
    };

    return (
        <React.Fragment>
            <ButtonControl
                active={selectedTextAlign === 'left'}
                onClick={() => toggle('left')}
                text={editor.translate('controls.textAlign.actions.alignLeft')}>
                <FormatAlignLeftIcon />
            </ButtonControl>
            <ButtonControl
                active={selectedTextAlign === 'center'}
                onClick={() => toggle('center')}
                text={editor.translate('controls.textAlign.actions.alignCenter')}>
                <FormatAlignCenterIcon />
            </ButtonControl>
            <ButtonControl
                active={selectedTextAlign === 'right'}
                onClick={() => toggle('right')}
                text={editor.translate('controls.textAlign.actions.alignRight')}>
                <FormatAlignRightIcon />
            </ButtonControl>
            <ButtonControl
                active={selectedTextAlign === 'justify'}
                onClick={() => toggle('justify')}
                text={editor.translate('controls.textAlign.actions.justify')}>
                <FormatAlignJustifyIcon />
            </ButtonControl>
        </React.Fragment>
    );
}
Example #19
Source File: ScriptEditor.jsx    From Spoke with MIT License 5 votes vote down vote up
UNSAFE_componentWillReceiveProps() {
    const { scriptFields } = this.props;
    const { editorState } = this.state;
    const decorator = this.getCompositeDecorator(scriptFields);
    EditorState.set(editorState, { decorator });

    // this.setState({ editorState: this.getEditorState() })
  }
Example #20
Source File: EditorUtilities.js    From wix-style-react with MIT License 5 votes vote down vote up
keepCurrentSelection = editorState =>
  EditorState.forceSelection(editorState, editorState.getSelection())
Example #21
Source File: createImmutableMention.js    From spring-boot-ecommerce with Apache License 2.0 5 votes vote down vote up
export default function createImmutableMention() {
  var callbacks = {
    onChange: noop,
    onUpArrow: noop,
    onDownArrow: noop,
    getEditorState: noop,
    setEditorState: noop,
    handleReturn: noop,
    onBlur: noop
  };

  function _onChange(editorState) {
    var selectionState = editorState.getSelection();
    var currentContent = editorState.getCurrentContent();
    var anchorKey = selectionState.getAnchorKey();
    var currentContentBlock = currentContent.getBlockForKey(anchorKey);

    if (selectionState.isCollapsed()) {
      currentContent.createEntity('trigger', 'MUTABLE');

      var end = selectionState.getEndOffset();
      var start = end - 1;
      var selectedText = currentContentBlock.getText().slice(start, end);
      if (selectedText === '@') {
        var updatedContent = Modifier.replaceText(currentContent, selectionState.merge({
          anchorOffset: start,
          focusOffset: end
        }), '@', null, currentContent.getLastCreatedEntityKey());
        return EditorState.push(editorState, updatedContent, 'insert-mention');
      }
    }

    return editorState;
  }

  var componentProps = {
    callbacks: callbacks,
    mentionStore: mentionStore
  };
  return {
    name: 'mention',
    Suggestions: function Suggestions(props) {
      return React.createElement(_Suggestions, _extends({}, props, componentProps, {
        store: mentionStore
      }));
    },
    decorators: [{
      strategy: mentionTriggerStrategy,
      component: function component(props) {
        return React.createElement('span', _extends({}, props, { style: { color: 'red' } }));
      }
    }, {
      strategy: mentionContentStrategy,
      component: function component(props) {
        return React.createElement(MentionContentComponent, _extends({}, props, { callbacks: callbacks }));
      }
    }],
    onChange: function onChange(editorState) {
      var updatedEditorState = _onChange(editorState);
      return callbacks.onChange ? callbacks.onChange(updatedEditorState) : updatedEditorState;
    },
    callbacks: callbacks,
    'export': exportContent
  };
}
Example #22
Source File: index.jsx    From react-antd-admin-template with MIT License 5 votes vote down vote up
RichTextEditor = () => {
  const [editorState, setEditorState] = useState(EditorState.createEmpty());

  const onEditorStateChange = (editorState) => setEditorState(editorState);

  return (
    <div>
      <Card bordered={false}>
        <Editor
          editorState={editorState}
          onEditorStateChange={onEditorStateChange}
          wrapperClassName="wrapper-class"
          editorClassName="editor-class"
          toolbarClassName="toolbar-class"
          localization={{ locale: "zh" }}
        />
      </Card>
      <br />
      <Row gutter={10}>
        <Col span={12}>
          <Card
            title="同步转换HTML"
            bordered={false}
            style={{ minHeight: 200 }}
          >
            {editorState &&
              draftToHtml(convertToRaw(editorState.getCurrentContent()))}
          </Card>
        </Col>
        <Col span={12}>
          <Card
            title="同步转换MarkDown"
            bordered={false}
            style={{ minHeight: 200 }}
          >
            {editorState &&
              draftToMarkdown(convertToRaw(editorState.getCurrentContent()))}
          </Card>
        </Col>
      </Row>
    </div>
  );
}
Example #23
Source File: editorStateUtils.js    From react-mui-draft-wysiwyg with MIT License 5 votes vote down vote up
applyEntityToCurrentSelection = (editorState, entityType, mutability, entityData) => {
    const content = editorState.getCurrentContent();
    const contentWithEntity = content.createEntity(entityType, mutability, entityData);
    const entityKey = contentWithEntity.getLastCreatedEntityKey();
    const selection = editorState.getSelection();
    const contentStateWithEntity = Modifier.applyEntity(contentWithEntity, selection, entityKey);
    return EditorState.push(editorState, contentStateWithEntity, 'apply-entity');
}
Example #24
Source File: Mention.react.js    From spring-boot-ecommerce with Apache License 2.0 4 votes vote down vote up
Mention = function (_React$Component) {
  _inherits(Mention, _React$Component);

  function Mention(props) {
    _classCallCheck(this, Mention);

    var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));

    _this.onEditorChange = function (editorState) {
      var selection = editorState.getSelection();
      _this._decorator = editorState.getDecorator();
      var content = editorState.getCurrentContent();

      if (_this.props.onChange) {
        _this.setState({
          selection: selection
        }, function () {
          _this.props.onChange(content, exportContent(content));
        });
      } else {
        _this.setState({
          editorState: editorState,
          selection: selection
        });
      }
    };

    _this.onFocus = function (e) {
      if (_this.props.onFocus) {
        _this.props.onFocus(e);
      }
    };

    _this.onBlur = function (e) {
      if (_this.props.onBlur) {
        _this.props.onBlur(e);
      }
    };

    _this.onKeyDown = function (e) {
      if (_this.props.onKeyDown) {
        _this.props.onKeyDown(e);
      }
    };

    _this.reset = function () {
      /*eslint-disable*/
      _this._editor.Reset();
      /*eslint-enable*/
    };

    _this.mention = createMention({
      prefix: _this.getPrefix(props),
      tag: props.tag,
      mode: props.mode,
      mentionStyle: props.mentionStyle
    });

    _this.Suggestions = _this.mention.Suggestions;
    _this.plugins = [_this.mention];

    _this.state = {
      suggestions: props.suggestions,
      value: props.value && EditorState.createWithContent(props.value, new CompositeDecorator(_this.mention.decorators)),
      selection: SelectionState.createEmpty()
    };

    if (typeof props.defaultValue === 'string') {
      // eslint-disable-next-line
      console.warn('The property `defaultValue` now allow `EditorState` only, see http://react-component.github.io/editor-mention/examples/defaultValue.html ');
    }
    if (props.value !== undefined) {
      _this.controlledMode = true;
    }
    return _this;
  }

  Mention.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
    var suggestions = nextProps.suggestions;
    var selection = this.state.selection;

    var value = nextProps.value;
    if (value && selection) {
      value = EditorState.acceptSelection(EditorState.createWithContent(value, this._decorator), selection);
    }
    this.setState({
      suggestions: suggestions,
      value: value
    });
  };

  Mention.prototype.getPrefix = function getPrefix() {
    var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.props;

    return Array.isArray(props.prefix) ? props.prefix : [props.prefix];
  };

  Mention.prototype.render = function render() {
    var _classnames,
        _this2 = this;

    var _props = this.props,
        prefixCls = _props.prefixCls,
        style = _props.style,
        tag = _props.tag,
        multiLines = _props.multiLines,
        editorKey = _props.editorKey,
        suggestionStyle = _props.suggestionStyle,
        placeholder = _props.placeholder,
        defaultValue = _props.defaultValue,
        className = _props.className,
        notFoundContent = _props.notFoundContent,
        getSuggestionContainer = _props.getSuggestionContainer,
        readOnly = _props.readOnly,
        disabled = _props.disabled,
        placement = _props.placement,
        mode = _props.mode;
    var suggestions = this.state.suggestions;
    var Suggestions = this.Suggestions;

    var editorClass = classnames(className, (_classnames = {}, _classnames[prefixCls + '-wrapper'] = true, _classnames.readonly = readOnly, _classnames.disabled = disabled, _classnames.multilines = multiLines, _classnames));
    var editorProps = this.controlledMode ? { value: this.state.value } : {};
    var defaultValueState = defaultValue && EditorState.createWithContent(typeof defaultValue === 'string' ? ContentState.createFromText(defaultValue) : defaultValue, this._decorator);
    return React.createElement(
      'div',
      { className: editorClass, style: style, ref: function ref(wrapper) {
          return _this2._wrapper = wrapper;
        } },
      React.createElement(
        EditorCore,
        _extends({
          ref: function ref(editor) {
            return _this2._editor = editor;
          },
          prefixCls: prefixCls,
          style: style,
          multiLines: multiLines,
          editorKey: editorKey,
          plugins: this.plugins,
          defaultValue: defaultValueState,
          placeholder: placeholder,
          onFocus: this.onFocus,
          onBlur: this.onBlur,
          onKeyDown: this.onKeyDown,
          onChange: this.onEditorChange
        }, editorProps, {
          readOnly: readOnly || disabled
        }),
        React.createElement(Suggestions, {
          mode: tag ? 'immutable' : mode,
          prefix: this.getPrefix(),
          prefixCls: prefixCls,
          style: suggestionStyle,
          placement: placement,
          notFoundContent: notFoundContent,
          suggestions: suggestions,
          getSuggestionContainer: getSuggestionContainer ? function () {
            return getSuggestionContainer(_this2._wrapper);
          } : null,
          onSearchChange: this.props.onSearchChange,
          onSelect: this.props.onSelect,
          noRedup: this.props.noRedup
        })
      )
    );
  };

  return Mention;
}(React.Component)
Example #25
Source File: index.js    From spring-boot-ecommerce with Apache License 2.0 4 votes vote down vote up
EditorCore = function (_React$Component) {
    _inherits(EditorCore, _React$Component);

    function EditorCore(props) {
        _classCallCheck(this, EditorCore);

        var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));

        _this.cancelForceUpdateImmediate = function () {
            clearImmediate(_this.forceUpdateImmediate);
            _this.forceUpdateImmediate = null;
        };
        _this.handlePastedText = function (text, html) {
            var editorState = _this.state.editorState;

            if (html) {
                var contentState = editorState.getCurrentContent();
                var selection = editorState.getSelection();
                var fragment = customHTML2Content(html, contentState);
                var pastedContent = Modifier.replaceWithFragment(contentState, selection, fragment);
                var newContent = pastedContent.merge({
                    selectionBefore: selection,
                    selectionAfter: pastedContent.getSelectionAfter().set('hasFocus', true)
                });
                _this.setEditorState(EditorState.push(editorState, newContent, 'insert-fragment'), true);
                return 'handled';
            }
            return 'not-handled';
        };
        _this.plugins = List(List(props.plugins).flatten(true));
        var editorState = void 0;
        if (props.value !== undefined) {
            if (props.value instanceof EditorState) {
                editorState = props.value || EditorState.createEmpty();
            } else {
                editorState = EditorState.createEmpty();
            }
        } else {
            editorState = EditorState.createEmpty();
        }
        editorState = _this.generatorDefaultValue(editorState);
        _this.state = {
            plugins: _this.reloadPlugins(),
            editorState: editorState,
            customStyleMap: {},
            customBlockStyleMap: {},
            compositeDecorator: null
        };
        if (props.value !== undefined) {
            _this.controlledMode = true;
        }
        return _this;
    }

    EditorCore.ToEditorState = function ToEditorState(text) {
        var createEmptyContentState = ContentState.createFromText(decodeContent(text) || '');
        var editorState = EditorState.createWithContent(createEmptyContentState);
        return EditorState.forceSelection(editorState, createEmptyContentState.getSelectionAfter());
    };

    EditorCore.prototype.getDefaultValue = function getDefaultValue() {
        var _props = this.props,
            defaultValue = _props.defaultValue,
            value = _props.value;

        return value || defaultValue;
    };

    EditorCore.prototype.Reset = function Reset() {
        var defaultValue = this.getDefaultValue();
        var contentState = defaultValue ? defaultValue.getCurrentContent() : ContentState.createFromText('');
        var updatedEditorState = EditorState.push(this.state.editorState, contentState, 'remove-range');
        this.setEditorState(EditorState.forceSelection(updatedEditorState, contentState.getSelectionBefore()));
    };

    EditorCore.prototype.SetText = function SetText(text) {
        var createTextContentState = ContentState.createFromText(text || '');
        var editorState = EditorState.push(this.state.editorState, createTextContentState, 'change-block-data');
        this.setEditorState(EditorState.moveFocusToEnd(editorState), true);
    };

    EditorCore.prototype.getChildContext = function getChildContext() {
        return {
            getEditorState: this.getEditorState,
            setEditorState: this.setEditorState
        };
    };

    EditorCore.prototype.reloadPlugins = function reloadPlugins() {
        var _this2 = this;

        return this.plugins && this.plugins.size ? this.plugins.map(function (plugin) {
            // 如果插件有 callbacks 方法,则认为插件已经加载。
            if (plugin.callbacks) {
                return plugin;
            }
            // 如果插件有 constructor 方法,则构造插件
            if (plugin.hasOwnProperty('constructor')) {
                var pluginConfig = _extends(_this2.props.pluginConfig, plugin.config || {}, defaultPluginConfig);
                return plugin.constructor(pluginConfig);
            }
            // else 无效插件
            console.warn('>> 插件: [', plugin.name, '] 无效。插件或许已经过期。');
            return false;
        }).filter(function (plugin) {
            return plugin;
        }).toArray() : [];
    };

    EditorCore.prototype.componentWillMount = function componentWillMount() {
        var plugins = this.initPlugins().concat([toolbar]);
        var customStyleMap = {};
        var customBlockStyleMap = {};
        var customBlockRenderMap = Map(DefaultDraftBlockRenderMap);
        var toHTMLList = List([]);
        // initialize compositeDecorator
        var compositeDecorator = new CompositeDecorator(plugins.filter(function (plugin) {
            return plugin.decorators !== undefined;
        }).map(function (plugin) {
            return plugin.decorators;
        }).reduce(function (prev, curr) {
            return prev.concat(curr);
        }, []));
        // initialize Toolbar
        var toolbarPlugins = List(plugins.filter(function (plugin) {
            return !!plugin.component && plugin.name !== 'toolbar';
        }));
        // load inline styles...
        plugins.forEach(function (plugin) {
            var styleMap = plugin.styleMap,
                blockStyleMap = plugin.blockStyleMap,
                blockRenderMap = plugin.blockRenderMap,
                toHtml = plugin.toHtml;

            if (styleMap) {
                for (var key in styleMap) {
                    if (styleMap.hasOwnProperty(key)) {
                        customStyleMap[key] = styleMap[key];
                    }
                }
            }
            if (blockStyleMap) {
                for (var _key in blockStyleMap) {
                    if (blockStyleMap.hasOwnProperty(_key)) {
                        customBlockStyleMap[_key] = blockStyleMap[_key];
                        customBlockRenderMap = customBlockRenderMap.set(_key, {
                            element: null
                        });
                    }
                }
            }
            if (toHtml) {
                toHTMLList = toHTMLList.push(toHtml);
            }
            if (blockRenderMap) {
                for (var _key2 in blockRenderMap) {
                    if (blockRenderMap.hasOwnProperty(_key2)) {
                        customBlockRenderMap = customBlockRenderMap.set(_key2, blockRenderMap[_key2]);
                    }
                }
            }
        });
        configStore.set('customStyleMap', customStyleMap);
        configStore.set('customBlockStyleMap', customBlockStyleMap);
        configStore.set('blockRenderMap', customBlockRenderMap);
        configStore.set('customStyleFn', this.customStyleFn.bind(this));
        configStore.set('toHTMLList', toHTMLList);
        this.setState({
            toolbarPlugins: toolbarPlugins,
            compositeDecorator: compositeDecorator
        });
        this.setEditorState(EditorState.set(this.state.editorState, { decorator: compositeDecorator }), false, false);
    };

    EditorCore.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
        if (this.forceUpdateImmediate) {
            this.cancelForceUpdateImmediate();
        }
        if (this.controlledMode) {
            var decorators = nextProps.value.getDecorator();
            var editorState = decorators ? nextProps.value : EditorState.set(nextProps.value, { decorator: this.state.compositeDecorator });
            this.setState({
                editorState: editorState
            });
        }
    };

    EditorCore.prototype.componentWillUnmount = function componentWillUnmount() {
        this.cancelForceUpdateImmediate();
    };
    // 处理 value


    EditorCore.prototype.generatorDefaultValue = function generatorDefaultValue(editorState) {
        var defaultValue = this.getDefaultValue();
        if (defaultValue) {
            return defaultValue;
        }
        return editorState;
    };

    EditorCore.prototype.getStyleMap = function getStyleMap() {
        return configStore.get('customStyleMap');
    };

    EditorCore.prototype.setStyleMap = function setStyleMap(customStyleMap) {
        configStore.set('customStyleMap', customStyleMap);
        this.render();
    };

    EditorCore.prototype.initPlugins = function initPlugins() {
        var _this3 = this;

        var enableCallbacks = ['focus', 'getEditorState', 'setEditorState', 'getStyleMap', 'setStyleMap'];
        return this.getPlugins().map(function (plugin) {
            enableCallbacks.forEach(function (callbackName) {
                if (plugin.callbacks.hasOwnProperty(callbackName)) {
                    plugin.callbacks[callbackName] = _this3[callbackName].bind(_this3);
                }
            });
            return plugin;
        });
    };

    EditorCore.prototype.focusEditor = function focusEditor(ev) {
        this.refs.editor.focus(ev);
        if (this.props.readOnly) {
            this._focusDummy.focus();
        }
        if (this.props.onFocus) {
            this.props.onFocus(ev);
        }
    };

    EditorCore.prototype._focus = function _focus(ev) {
        if (!ev || !ev.nativeEvent || !ev.nativeEvent.target) {
            return;
        }
        if (document.activeElement && document.activeElement.getAttribute('contenteditable') === 'true') {
            return;
        }
        return this.focus(ev);
    };

    EditorCore.prototype.focus = function focus(ev) {
        var _this4 = this;

        var event = ev && ev.nativeEvent;
        if (event && event.target === this._editorWrapper) {
            var editorState = this.state.editorState;

            var selection = editorState.getSelection();
            if (!selection.getHasFocus()) {
                if (selection.isCollapsed()) {
                    return this.setState({
                        editorState: EditorState.moveSelectionToEnd(editorState)
                    }, function () {
                        _this4.focusEditor(ev);
                    });
                }
            }
        }
        this.focusEditor(ev);
    };

    EditorCore.prototype.getPlugins = function getPlugins() {
        return this.state.plugins.slice();
    };

    EditorCore.prototype.getEventHandler = function getEventHandler() {
        var _this5 = this;

        var enabledEvents = ['onUpArrow', 'onDownArrow', 'handleReturn', 'onFocus', 'onBlur', 'onTab', 'handlePastedText'];
        var eventHandler = {};
        enabledEvents.forEach(function (event) {
            eventHandler[event] = _this5.generatorEventHandler(event);
        });
        return eventHandler;
    };

    EditorCore.prototype.getEditorState = function getEditorState() {
        var needFocus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;

        if (needFocus) {
            this.refs.editor.focus();
        }
        return this.state.editorState;
    };

    EditorCore.prototype.setEditorState = function setEditorState(editorState) {
        var _this6 = this;

        var focusEditor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
        var triggerChange = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;

        var newEditorState = editorState;
        this.getPlugins().forEach(function (plugin) {
            if (plugin.onChange) {
                var updatedEditorState = plugin.onChange(newEditorState);
                if (updatedEditorState) {
                    newEditorState = updatedEditorState;
                }
            }
        });
        if (this.props.onChange && triggerChange) {
            this.props.onChange(newEditorState);
            // close this issue https://github.com/ant-design/ant-design/issues/5788
            // when onChange not take any effect
            // `<Editor />` won't rerender cause no props is changed.
            // add an timeout here,
            // if props.onChange not trigger componentWillReceiveProps,
            // we will force render Editor with previous editorState,
            if (this.controlledMode) {
                this.forceUpdateImmediate = setImmediate(function () {
                    return _this6.setState({
                        editorState: new EditorState(_this6.state.editorState.getImmutable())
                    });
                });
            }
        }
        if (!this.controlledMode) {
            this.setState({ editorState: newEditorState }, focusEditor ? function () {
                return setImmediate(function () {
                    return _this6.refs.editor.focus();
                });
            } : noop);
        }
    };

    EditorCore.prototype.handleKeyBinding = function handleKeyBinding(ev) {
        if (this.props.onKeyDown) {
            ev.ctrlKey = hasCommandModifier(ev);
            var keyDownResult = this.props.onKeyDown(ev);
            if (keyDownResult) {
                return keyDownResult;
            }
            return getDefaultKeyBinding(ev);
        }
        return getDefaultKeyBinding(ev);
    };

    EditorCore.prototype.handleKeyCommand = function handleKeyCommand(command) {
        if (this.props.multiLines) {
            return this.eventHandle('handleKeyBinding', command);
        }
        return command === 'split-block' ? 'handled' : 'not-handled';
    };

    EditorCore.prototype.getBlockStyle = function getBlockStyle(contentBlock) {
        var customBlockStyleMap = configStore.get('customBlockStyleMap');
        var type = contentBlock.getType();
        if (customBlockStyleMap.hasOwnProperty(type)) {
            return customBlockStyleMap[type];
        }
        return '';
    };

    EditorCore.prototype.blockRendererFn = function blockRendererFn(contentBlock) {
        var blockRenderResult = null;
        this.getPlugins().forEach(function (plugin) {
            if (plugin.blockRendererFn) {
                var result = plugin.blockRendererFn(contentBlock);
                if (result) {
                    blockRenderResult = result;
                }
            }
        });
        return blockRenderResult;
    };

    EditorCore.prototype.eventHandle = function eventHandle(eventName) {
        var _props2;

        var plugins = this.getPlugins();

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

        for (var i = 0; i < plugins.length; i++) {
            var plugin = plugins[i];
            if (plugin.callbacks[eventName] && typeof plugin.callbacks[eventName] === 'function') {
                var _plugin$callbacks;

                var result = (_plugin$callbacks = plugin.callbacks)[eventName].apply(_plugin$callbacks, args);
                if (result === true) {
                    return 'handled';
                }
            }
        }
        return this.props.hasOwnProperty(eventName) && (_props2 = this.props)[eventName].apply(_props2, args) === true ? 'handled' : 'not-handled';
    };

    EditorCore.prototype.generatorEventHandler = function generatorEventHandler(eventName) {
        var _this7 = this;

        return function () {
            for (var _len2 = arguments.length, args = Array(_len2), _key4 = 0; _key4 < _len2; _key4++) {
                args[_key4] = arguments[_key4];
            }

            return _this7.eventHandle.apply(_this7, [eventName].concat(args));
        };
    };

    EditorCore.prototype.customStyleFn = function customStyleFn(styleSet) {
        if (styleSet.size === 0) {
            return {};
        }
        var plugins = this.getPlugins();
        var resultStyle = {};
        for (var i = 0; i < plugins.length; i++) {
            if (plugins[i].customStyleFn) {
                var styled = plugins[i].customStyleFn(styleSet);
                if (styled) {
                    _extends(resultStyle, styled);
                }
            }
        }
        return resultStyle;
    };

    EditorCore.prototype.render = function render() {
        var _classnames,
            _this8 = this;

        var _props3 = this.props,
            prefixCls = _props3.prefixCls,
            toolbars = _props3.toolbars,
            style = _props3.style,
            readOnly = _props3.readOnly,
            multiLines = _props3.multiLines;
        var _state = this.state,
            editorState = _state.editorState,
            toolbarPlugins = _state.toolbarPlugins;

        var customStyleMap = configStore.get('customStyleMap');
        var blockRenderMap = configStore.get('blockRenderMap');
        var eventHandler = this.getEventHandler();
        var Toolbar = toolbar.component;
        var cls = classnames((_classnames = {}, _classnames[prefixCls + '-editor'] = true, _classnames.readonly = readOnly, _classnames.oneline = !multiLines, _classnames));
        return React.createElement(
            'div',
            { style: style, className: cls, onClick: this._focus.bind(this) },
            React.createElement(Toolbar, { editorState: editorState, prefixCls: prefixCls, className: prefixCls + '-toolbar', plugins: toolbarPlugins, toolbars: toolbars }),
            React.createElement(
                'div',
                { className: prefixCls + '-editor-wrapper', ref: function ref(ele) {
                        return _this8._editorWrapper = ele;
                    }, style: style, onClick: function onClick(ev) {
                        return ev.preventDefault();
                    } },
                React.createElement(Editor, _extends({}, this.props, eventHandler, { ref: 'editor', customStyleMap: customStyleMap, customStyleFn: this.customStyleFn.bind(this), editorState: editorState, handleKeyCommand: this.handleKeyCommand.bind(this), keyBindingFn: this.handleKeyBinding.bind(this), onChange: this.setEditorState.bind(this), blockStyleFn: this.getBlockStyle.bind(this), blockRenderMap: blockRenderMap, handlePastedText: this.handlePastedText, blockRendererFn: this.blockRendererFn.bind(this) })),
                readOnly ? React.createElement('input', { style: focusDummyStyle, ref: function ref(ele) {
                        return _this8._focusDummy = ele;
                    }, onBlur: eventHandler.onBlur }) : null,
                this.props.children
            )
        );
    };

    return EditorCore;
}(React.Component)
Example #26
Source File: index.js    From paras-landing with GNU General Public License v3.0 4 votes vote down vote up
PublicationDetailPage = ({ errorCode, pubDetail, userProfile }) => {
	const store = useStore()
	const router = useRouter()
	const toast = useToast()
	const textAreaRef = useRef(null)
	const [content, setContent] = useState(
		pubDetail?.content ? EditorState.createWithContent(convertFromRaw(pubDetail.content)) : null
	)
	const [showModal, setShowModal] = useState('')
	const [isCopied, setIsCopied] = useState(false)
	const [isDeleting, setIsDeleting] = useState(false)
	const [isComponentMounted, setIsComponentMounted] = useState(false)

	useEffect(() => {
		setIsComponentMounted(true)
	}, [])

	useEffect(() => {
		if (errorCode) {
			router.push('/publication')
		}
	}, [errorCode])

	if (errorCode) {
		return <Error />
	}

	const headMeta = {
		title: `${pubDetail.title} — Paras Publication`,
		description: pubDetail.description,
		image: parseImgUrl(pubDetail.thumbnail),
	}

	const _copyLink = () => {
		textAreaRef.current.select()
		document.execCommand('copy')

		setIsCopied(true)

		setTimeout(() => {
			setShowModal(false)
			setIsCopied(false)
		}, 1500)
	}

	const _deletePublication = async () => {
		setIsDeleting(true)
		try {
			await axios.delete(`${process.env.V2_API_URL}/publications/${pubDetail._id}`, {
				headers: {
					authorization: await WalletHelper.authToken(),
				},
			})
			setTimeout(() => {
				router.push('/publication')
			}, 1000)
		} catch (err) {
			sentryCaptureException(err)
			const msg = err.response?.data?.message || `Something went wrong, try again later`
			toast.show({
				text: <div className="font-semibold text-center text-sm">{msg}</div>,
				type: 'error',
				duration: 2500,
			})
			setIsDeleting(false)
		}
	}

	return (
		<div>
			<div className="min-h-screen bg-black">
				<div
					className="fixed inset-0 opacity-75"
					style={{
						zIndex: 0,
						backgroundImage: `url('/bg.jpg')`,
						backgroundRepeat: 'no-repeat',
						backgroundSize: 'cover',
					}}
				></div>
				<Head>
					<title>{headMeta.title}</title>
					<meta name="description" content={headMeta.description} />

					<meta name="twitter:title" content={headMeta.title} />
					<meta name="twitter:card" content="summary_large_image" />
					<meta name="twitter:site" content="@ParasHQ" />
					<meta name="twitter:url" content="https://paras.id" />
					<meta name="twitter:description" content={headMeta.description} />
					<meta name="twitter:image" content={headMeta.image} />
					<meta property="og:type" content="website" />
					<meta property="og:title" content={headMeta.title} />
					<meta property="og:site_name" content={headMeta.title} />
					<meta property="og:description" content={headMeta.description} />
					<meta property="og:url" content="https://paras.id" />
					<meta property="og:image" content={headMeta.image} />
				</Head>
				<Nav />
				{isComponentMounted && (
					<div
						className="absolute z-0 opacity-0"
						style={{
							top: `-1000`,
						}}
					>
						<input ref={textAreaRef} readOnly type="text" value={window.location.href} />
					</div>
				)}
				{showModal === 'options' && (
					<Modal close={() => setShowModal('')}>
						<div className="max-w-sm w-full px-4 py-2 bg-gray-100 m-auto rounded-md">
							<div className="py-2 cursor-pointer" onClick={() => _copyLink()}>
								{isCopied ? `Copied` : `Copy Link`}
							</div>
							<div
								className="py-2 cursor-pointer"
								onClick={() => {
									setShowModal('shareTo')
								}}
							>
								Share to...
							</div>
							{!pubDetail.isComic && store.currentUser === pubDetail.author_id && (
								<>
									<Link href={`/publication/edit/${pubDetail._id}`}>
										<div
											className="py-2 cursor-pointer"
											onClick={() => setShowModal('confirmTransfer')}
										>
											Update publication
										</div>
									</Link>
									<div
										className="py-2 cursor-pointer"
										onClick={() => setShowModal('confirmDelete')}
									>
										Delete
									</div>
								</>
							)}
						</div>
					</Modal>
				)}
				{showModal === 'confirmDelete' && (
					<Modal close={() => setShowModal('')} closeOnBgClick={true} closeOnEscape={true}>
						<div className="max-w-sm w-full p-4 bg-gray-100 m-auto rounded-md">
							<h1 className="text-2xl font-bold text-gray-900 tracking-tight">Confirm Delete</h1>
							<p className="text-gray-900 mt-2">
								You are about to delete <b>{pubDetail.title}</b>
							</p>
							<button
								className="w-full outline-none h-12 mt-4 rounded-md bg-transparent text-sm font-semibold border-2 px-4 py-2 border-primary bg-primary text-gray-100"
								type="submit"
								disabled={isDeleting}
								onClick={_deletePublication}
							>
								{isDeleting ? 'Deleting...' : 'Delete my publication'}
							</button>
						</div>
					</Modal>
				)}
				{showModal === 'shareTo' && (
					<Modal close={() => setShowModal('')}>
						<div className="max-w-sm w-full px-4 py-2 bg-gray-100 m-auto rounded-md">
							<div className="py-2 cursor-pointer">
								<TwitterShareButton
									title={`Read ${pubDetail.title} only at @ParasHQ\n\n#paras #cryptoart #digitalart #tradingcards`}
									url={window.location.href}
									className="flex items-center w-full"
								>
									<TwitterIcon
										size={24}
										className="rounded-md"
										bgStyle={{
											fill: '#11111F',
										}}
									/>
									<p className="pl-2">Twitter</p>
								</TwitterShareButton>
							</div>
							<div className="py-2 cursor-pointer">
								<FacebookShareButton
									url={window.location.href}
									className="flex items-center w-full"
								>
									<FacebookIcon
										size={24}
										className="rounded-md"
										bgStyle={{
											fill: '#11111F',
										}}
									/>
									<p className="pl-2">Facebook</p>
								</FacebookShareButton>
							</div>
						</div>
					</Modal>
				)}
				<div className="max-w-5xl relative m-auto pb-12 pt-4">
					<p className="mb-8 px-4 max-w-3xl m-auto text-gray-400">
						<Link href={`/publication`}>
							<span className="cursor-pointer">Publication</span>
						</Link>
						{' > '}
						<Link href={`/publication?type=${pubDetail.type}`}>
							<span className="cursor-pointer capitalize">{pubDetail.type}</span>
						</Link>
						{' > '}
						<span className="font-semibold text-white">{pubDetail.title}</span>
					</p>
					<h1 className="titlePublication text-4xl font-bold pb-0 text-center px-4 md:px-0">
						{pubDetail.title}
					</h1>
					<div className="m-auto max-w-3xl px-4 pt-8">
						<div className="flex justify-between">
							<div className="flex space-x-4">
								<Link href={`/${pubDetail.author_id}`}>
									<div className="w-16 h-16 rounded-full overflow-hidden bg-primary cursor-pointer">
										<img
											src={parseImgUrl(userProfile?.imgUrl, null, {
												width: `800`,
											})}
											className="object-cover"
										/>
									</div>
								</Link>
								<div className="m-auto">
									<LinkToProfile
										accountId={pubDetail.author_id}
										className="text-white font-bold hover:border-white text-xl"
									/>
									<p className="text-white m-auto text-sm">{parseDate(pubDetail.updated_at)}</p>
								</div>
							</div>
							<div>
								<IconDots
									color="#ffffff"
									className="cursor-pointer mb-1"
									onClick={() => setShowModal('options')}
								/>
							</div>
						</div>
						{content && (
							<TextEditor
								title={createEditorStateWithText(pubDetail.title)}
								hideTitle={true}
								content={content}
								setContent={setContent}
								readOnly={true}
							/>
						)}
					</div>
					{pubDetail.collection_ids && pubDetail.collection_ids.length !== 0 && (
						<div className="max-w-4xl mx-auto px-4 pt-16">
							<div className="rounded-md p-2 md:p-4">
								<h4 className="text-white font-semibold text-3xl md:mb-4 text-center">
									{pubDetail.isComic ? 'Comics' : 'Collections'}
								</h4>
								<div
									className={`flex flex-wrap ${
										pubDetail.contract_token_ids.length <= 3 && 'justify-center'
									}`}
								>
									{pubDetail.collection_ids?.map((collectionId, index) => (
										<div key={index} className="w-full md:w-1/2 lg:w-1/3 flex-shrink-0 p-4">
											<EmbeddedCollection collectionId={collectionId} pubDetail={pubDetail} />
										</div>
									))}
								</div>
							</div>
						</div>
					)}
					{pubDetail.contract_token_ids && pubDetail.contract_token_ids.length !== 0 && (
						<div className="max-w-4xl mx-auto px-4 pt-16">
							<div className=" border-2 border-dashed border-gray-800 rounded-md p-4 md:p-8">
								<h4 className="text-white font-semibold text-3xl md:mb-4 text-center">
									Digital Collectibles
								</h4>
								<div
									className={`flex flex-wrap ${
										pubDetail.contract_token_ids.length <= 3 && 'justify-center'
									}`}
								>
									{pubDetail.contract_token_ids?.map((tokenId, index) => (
										<div key={index} className="w-full md:w-1/2 lg:w-1/3 flex-shrink-0 p-8">
											<EmbeddedCard tokenId={tokenId} />
										</div>
									))}
								</div>
							</div>
						</div>
					)}
				</div>
				<Footer />
			</div>
		</div>
	)
}
Example #27
Source File: [slug].js    From paras-landing with GNU General Public License v3.0 4 votes vote down vote up
PublicationDetailPage = ({ errorCode, pubDetail, userProfile }) => {
	const store = useStore()
	const router = useRouter()
	const toast = useToast()
	const textAreaRef = useRef(null)
	const [content, setContent] = useState(
		pubDetail?.content ? EditorState.createWithContent(convertFromRaw(pubDetail.content)) : null
	)
	const [showModal, setShowModal] = useState('')
	const [isCopied, setIsCopied] = useState(false)
	const [isDeleting, setIsDeleting] = useState(false)
	const [isComponentMounted, setIsComponentMounted] = useState(false)

	useEffect(() => {
		setIsComponentMounted(true)
	}, [])

	useEffect(() => {
		if (errorCode) {
			router.push('/publication')
		}
	}, [errorCode])

	if (errorCode) {
		return <Error />
	}

	const headMeta = {
		title: `${pubDetail.title} — Paras Publication`,
		description: pubDetail.description,
		image: parseImgUrl(pubDetail.thumbnail),
	}

	const _copyLink = () => {
		textAreaRef.current.select()
		document.execCommand('copy')

		setIsCopied(true)

		setTimeout(() => {
			setShowModal(false)
			setIsCopied(false)
		}, 1500)
	}

	const _deletePublication = async () => {
		setIsDeleting(true)
		try {
			await axios.delete(`${process.env.V2_API_URL}/publications/${pubDetail._id}`, {
				headers: {
					authorization: await WalletHelper.authToken(),
				},
			})
			setTimeout(() => {
				router.push('/publication')
			}, 1000)
		} catch (err) {
			sentryCaptureException(err)
			const msg = err.response?.data?.message || 'Something went wrong, try again later.'
			toast.show({
				text: <div className="font-semibold text-center text-sm">{msg}</div>,
				type: 'error',
				duration: 2500,
			})
			setIsDeleting(false)
		}
	}

	return (
		<div>
			<div className="min-h-screen bg-black">
				<div
					className="fixed inset-0 opacity-75"
					style={{
						zIndex: 0,
						backgroundImage: `url('/bg.jpg')`,
						backgroundRepeat: 'no-repeat',
						backgroundSize: 'cover',
					}}
				></div>
				<Head>
					<title>{headMeta.title}</title>
					<meta name="description" content={headMeta.description} />

					<meta name="twitter:title" content={headMeta.title} />
					<meta name="twitter:card" content="summary_large_image" />
					<meta name="twitter:site" content="@ParasHQ" />
					<meta name="twitter:url" content="https://paras.id" />
					<meta name="twitter:description" content={headMeta.description} />
					<meta name="twitter:image" content={headMeta.image} />
					<meta property="og:type" content="website" />
					<meta property="og:title" content={headMeta.title} />
					<meta property="og:site_name" content={headMeta.title} />
					<meta property="og:description" content={headMeta.description} />
					<meta property="og:url" content="https://paras.id" />
					<meta property="og:image" content={headMeta.image} />
				</Head>
				<Nav />
				{isComponentMounted && (
					<div
						className="absolute z-0 opacity-0"
						style={{
							top: `-1000`,
						}}
					>
						<input ref={textAreaRef} readOnly type="text" value={window.location.href} />
					</div>
				)}
				{showModal === 'options' && (
					<Modal close={() => setShowModal('')}>
						<div className="max-w-sm w-full px-4 py-2 bg-gray-100 m-auto rounded-md">
							<div className="py-2 cursor-pointer" onClick={() => _copyLink()}>
								{isCopied ? `Copied` : `Copy Link`}
							</div>
							<div
								className="py-2 cursor-pointer"
								onClick={() => {
									setShowModal('shareTo')
								}}
							>
								Share to...
							</div>
							{store.currentUser === pubDetail.author_id && (
								<Link href={`/publication/edit/${pubDetail._id}`}>
									<div
										className="py-2 cursor-pointer"
										onClick={() => setShowModal('confirmTransfer')}
									>
										Update publication
									</div>
								</Link>
							)}
							{store.currentUser === pubDetail.author_id && (
								<div className="py-2 cursor-pointer" onClick={() => setShowModal('confirmDelete')}>
									Delete
								</div>
							)}
						</div>
					</Modal>
				)}
				{showModal === 'confirmDelete' && (
					<Modal close={() => setShowModal('')} closeOnBgClick={true} closeOnEscape={true}>
						<div className="max-w-sm w-full p-4 bg-gray-100 m-auto rounded-md">
							<h1 className="text-2xl font-bold text-gray-900 tracking-tight">Confirm Delete</h1>
							<p className="text-gray-900 mt-2">
								You are about to delete <b>{pubDetail.title}</b>
							</p>
							<button
								className="w-full outline-none h-12 mt-4 rounded-md bg-transparent text-sm font-semibold border-2 px-4 py-2 border-primary bg-primary text-gray-100"
								type="submit"
								disabled={isDeleting}
								onClick={_deletePublication}
							>
								{isDeleting ? 'Deleting...' : 'Delete my publication'}
							</button>
						</div>
					</Modal>
				)}
				{showModal === 'shareTo' && (
					<Modal close={() => setShowModal('')}>
						<div className="max-w-sm w-full px-4 py-2 bg-gray-100 m-auto rounded-md">
							<div className="py-2 cursor-pointer">
								<TwitterShareButton
									title={`Read ${pubDetail.title} only at @ParasHQ\n\n#paras #cryptoart #digitalart #tradingcards`}
									url={window.location.href}
									className="flex items-center w-full"
								>
									<TwitterIcon
										size={24}
										className="rounded-md"
										bgStyle={{
											fill: '#11111F',
										}}
									/>
									<p className="pl-2">Twitter</p>
								</TwitterShareButton>
							</div>
							<div className="py-2 cursor-pointer">
								<FacebookShareButton
									url={window.location.href}
									className="flex items-center w-full"
								>
									<FacebookIcon
										size={24}
										className="rounded-md"
										bgStyle={{
											fill: '#11111F',
										}}
									/>
									<p className="pl-2">Facebook</p>
								</FacebookShareButton>
							</div>
						</div>
					</Modal>
				)}
				<div className="max-w-5xl relative m-auto pb-12 pt-4">
					<p className="mb-8 px-4 max-w-3xl m-auto text-gray-400">
						<Link href={`/publication`}>
							<span className="cursor-pointer">Publication</span>
						</Link>
						{' > '}
						<Link href={`/publication?type=${pubDetail.type}`}>
							<span className="cursor-pointer capitalize">{pubDetail.type}</span>
						</Link>
						{' > '}
						<span className="font-semibold text-white">{pubDetail.title}</span>
					</p>
					<h1 className="titlePublication text-4xl font-bold pb-0 text-center px-4 md:px-0">
						{pubDetail.title}
					</h1>
					<div className="m-auto max-w-3xl px-4 pt-8">
						<div className="flex justify-between">
							<div className="flex space-x-4">
								<Link href={`/${pubDetail.author_id}`}>
									<div className="w-16 h-16 rounded-full overflow-hidden bg-primary cursor-pointer">
										<img
											src={parseImgUrl(userProfile?.imgUrl, null, {
												width: `800`,
											})}
											className="object-cover"
										/>
									</div>
								</Link>
								<div className="m-auto">
									<LinkToProfile
										accountId={pubDetail.author_id}
										className="text-white font-bold hover:border-white text-xl"
									/>
									<p className="text-white m-auto text-sm">{parseDate(pubDetail.updated_at)}</p>
								</div>
							</div>
							<div>
								<IconDots
									color="#ffffff"
									className="cursor-pointer mb-1"
									onClick={() => setShowModal('options')}
								/>
							</div>
						</div>
						{content && (
							<TextEditor
								title={createEditorStateWithText(pubDetail.title)}
								hideTitle={true}
								content={content}
								setContent={setContent}
								readOnly={true}
							/>
						)}
					</div>
					{pubDetail.contract_token_ids && pubDetail.contract_token_ids.length !== 0 && (
						<div className="max-w-4xl mx-auto px-4 pt-16">
							<div className=" border-2 border-dashed border-gray-800 rounded-md p-4 md:p-8">
								<h4 className="text-white font-semibold text-3xl md:mb-4 text-center">
									Digital Collectibles
								</h4>
								<div
									className={`flex flex-wrap ${
										pubDetail.contract_token_ids.length <= 3 && 'justify-center'
									}`}
								>
									{pubDetail.contract_token_ids?.map((tokenId, index) => (
										<div key={index} className="w-full md:w-1/2 lg:w-1/3 flex-shrink-0 p-8">
											<EmbeddedCard tokenId={tokenId} />
										</div>
									))}
								</div>
							</div>
						</div>
					)}
				</div>
				<Footer />
			</div>
		</div>
	)
}
Example #28
Source File: index.jsx    From react-mui-draft-wysiwyg with MIT License 4 votes vote down vote up
function ImageControl({ configuration, defaultConfiguration }) {
    const editor = useEditor();
    const editorFocus = useEditorFocus();
    const menuId = Math.random().toString(36).substring(8);
    const [anchorEl, setAnchorEl] = React.useState(null);
    const [isUploadDialogOpened, setIsUploadDialogOpened] = React.useState(false);
    const [isUrlDialogOpened, setIsUrlDialogOpened] = React.useState(false);
    const uploadCallback = configuration.uploadCallback || defaultConfiguration.uploadCallback;

    const imageEntityToResize = editor.resizeImageEntityKey
        ? editor.editorState.getCurrentContent().getEntity(editor.resizeImageEntityKey)
        : null;

    const handleSubmitImage = ({ imageURL, imageWidth, imageHeight }) => {
        if (imageURL === '') return;
        setIsUrlDialogOpened(false);
        setIsUploadDialogOpened(false);

        const contentState = editor.editorState.getCurrentContent();
        const contentStateWithEntity = contentState.createEntity(entities.IMAGE, 'IMMUTABLE', {
            src: imageURL,
            width: imageWidth,
            height: imageHeight,
        });
        const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
        const newEditorState = EditorState.push(
            editor.editorState,
            contentStateWithEntity,
            'apply-entity'
        );
        editor.onChange(AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' '));
        editorFocus();
    };

    const handleResizeImage = (width, height) => {
        editor.hideResizeImageDialog();
        const contentState = editor.editorState.getCurrentContent();
        const newEditorState = EditorState.push(
            editor.editorState,
            contentState.mergeEntityData(editor.resizeImageEntityKey, { width, height }),
            'apply-entity'
        );
        editor.onChange(newEditorState);
        editorFocus();
    };

    return (
        <React.Fragment>
            <ButtonControl
                onClick={(ev) => setAnchorEl(ev.currentTarget)}
                text={editor.translate('controls.image.title')}
                aria-controls={menuId}
                aria-haspopup="true">
                <ImageIcon />
            </ButtonControl>

            <Popover
                id={menuId}
                anchorEl={anchorEl}
                anchorOrigin={{
                    vertical: 'bottom',
                    horizontal: 'left',
                }}
                transformOrigin={{
                    vertical: 'top',
                    horizontal: 'left',
                }}
                keepMounted
                open={Boolean(anchorEl)}
                onClose={() => setAnchorEl(null)}>
                <List
                    component="nav"
                    aria-label={editor.translate('controls.image.labels.insertOptions')}>
                    <ListItem
                        button
                        onClick={() => {
                            setIsUploadDialogOpened(true);
                            setAnchorEl(null);
                        }}>
                        <ListItemIcon>
                            <PublishIcon />
                        </ListItemIcon>
                        <ListItemText primary={editor.translate('controls.image.actions.upload')} />
                    </ListItem>
                    <ListItem
                        button
                        onClick={() => {
                            setIsUrlDialogOpened(true);
                            setAnchorEl(null);
                        }}>
                        <ListItemIcon>
                            <LinkIcon />
                        </ListItemIcon>
                        <ListItemText primary={editor.translate('controls.image.actions.url')} />
                    </ListItem>
                </List>
            </Popover>

            <ByUrlDialog
                onSubmit={handleSubmitImage}
                onClose={() => setIsUrlDialogOpened(false)}
                open={isUrlDialogOpened}
            />

            <UploadDialog
                onSubmit={handleSubmitImage}
                onClose={() => setIsUploadDialogOpened(false)}
                open={isUploadDialogOpened}
                uploadCallback={uploadCallback}
            />

            <ResizeImageDialog
                open={editor.isResizeImageDialogVisible}
                onClose={() => editor.hideResizeImageDialog()}
                src={imageEntityToResize ? imageEntityToResize.getData().src : ''}
                originalWidth={imageEntityToResize ? imageEntityToResize.getData().width : 0}
                originalHeight={imageEntityToResize ? imageEntityToResize.getData().height : 0}
                onSave={handleResizeImage}
            />
        </React.Fragment>
    );
}
Example #29
Source File: plugin.js    From react-mui-draft-wysiwyg with MIT License 4 votes vote down vote up
EditorImage = ({ src, width, height, contentState, block }) => {
    const [anchorEl, setAnchorEl] = React.useState(null);
    const [infoAnchorEl, setInfoAnchorEl] = React.useState(null);
    const editor = useEditor();
    const editorFocus = useEditorFocus();
    const classes = useStyles();

    const showOptions = (ev) => {
        setAnchorEl(ev.currentTarget);
        setInfoAnchorEl(ev.currentTarget);
    };

    const hideOptions = () => {
        setAnchorEl(null);
        setInfoAnchorEl(null);
    };

    const imageAlign = (ev, align) => {
        ev.preventDefault();
        ev.stopPropagation();
        const imageSelection = SelectionState.createEmpty(block.getKey()).merge({
            anchorKey: block.getKey(),
            anchorOffset: 0,
            focusKey: block.getKey(),
            focusOffset: block.getLength(),
        });

        const newContentState = Modifier.setBlockData(contentState, imageSelection, {
            textAlign: align,
        });
        editor.onChange(EditorState.push(editor.editorState, newContentState, 'change-block-data'));
        editorFocus();
    };

    const removeImage = (ev) => {
        ev.preventDefault();
        ev.stopPropagation();
        const imageSelection = SelectionState.createEmpty(block.getKey()).merge({
            anchorKey: block.getKey(),
            anchorOffset: 0,
            focusKey: block.getKey(),
            focusOffset: block.getLength(),
        });

        let newContentState = Modifier.removeRange(contentState, imageSelection, 'forward');

        const blockMap = newContentState.getBlockMap().delete(block.getKey());

        const firstBlock = newContentState.getFirstBlock();

        const selectionToStart = SelectionState.createEmpty(firstBlock.getKey()).merge({
            anchorKey: firstBlock.getKey(),
            anchorOffset: 0,
            focusKey: firstBlock.getKey(),
            focusOffset: 0,
        });

        newContentState = newContentState.merge({ blockMap, selectionAfter: selectionToStart });

        editor.onChange(EditorState.push(editor.editorState, newContentState, 'remove-range'));
        editorFocus();
    };

    if (!src) return null;

    return (
        <React.Fragment>
            <img alt={src} src={src} width={width} height={height} onClick={showOptions} />
            <Popover
                open={Boolean(infoAnchorEl)}
                onClose={hideOptions}
                anchorEl={infoAnchorEl}
                anchorOrigin={{
                    vertical: 'top',
                    horizontal: 'right',
                }}
                transformOrigin={{
                    vertical: 'bottom',
                    horizontal: 'right',
                }}>
                <Typography color="textSecondary" variant="body1" className={classes.imgInfo}>
                    {width}&nbsp;x&nbsp;{height}
                </Typography>
            </Popover>
            <Popover
                open={Boolean(anchorEl)}
                onClose={hideOptions}
                anchorEl={anchorEl}
                anchorOrigin={{
                    vertical: 'bottom',
                    horizontal: 'center',
                }}
                transformOrigin={{
                    vertical: 'top',
                    horizontal: 'center',
                }}>
                <ButtonGroup
                    size="small"
                    aria-label={editor.translate('controls.image.labels.editOptions')}>
                    <Button
                        onClick={(ev) => imageAlign(ev, 'left')}
                        title={editor.translate('controls.image.actions.alignLeft')}>
                        <ArrowLeftIcon />
                        <ImageIcon />
                    </Button>
                    <Button
                        onClick={(ev) => imageAlign(ev, 'center')}
                        title={editor.translate('controls.image.actions.alignCenter')}>
                        <ArrowLeftIcon />
                        <ImageIcon />
                        <ArrowRightIcon />
                    </Button>
                    <Button
                        onClick={(ev) => imageAlign(ev, 'right')}
                        title={editor.translate('controls.image.actions.alignRight')}>
                        <ImageIcon />
                        <ArrowRightIcon />
                    </Button>
                    <Button
                        onClick={() => {
                            hideOptions();
                            editor.showResizeImageDialog(block.getEntityAt(0));
                        }}
                        title={editor.translate('controls.image.actions.resize')}>
                        <PhotoSizeSelectLargeIcon />
                    </Button>
                    <Button
                        onClick={removeImage}
                        title={editor.translate('controls.image.actions.remove')}>
                        <DeleteIcon />
                    </Button>
                </ButtonGroup>
            </Popover>
        </React.Fragment>
    );
}