123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- import React from "react"
- import classnames from "classnames"
- import misago from "../../"
- import ajax from "../../services/ajax"
- import snackbar from "../../services/snackbar"
- import MisagoMarkup from "../misago-markup"
- import MarkupEditorAttachments from "./MarkupEditorAttachments"
- import MarkupEditorFooter from "./MarkupEditorFooter"
- import MarkupEditorToolbar from "./MarkupEditorToolbar"
- import uploadFile from "./uploadFile"
- class MarkupEditor extends React.Component {
- constructor(props) {
- super(props)
- this.state = {
- element: null,
- focused: false,
- loading: false,
- preview: false,
- parsed: null,
- }
- }
- showPreview = () => {
- if (this.state.loading) return
- this.setState({ loading: true, preview: true, element: null })
- ajax.post(misago.get("PARSE_MARKUP_API"), { post: this.props.value }).then(
- (data) => {
- this.setState({ loading: false, parsed: data.parsed })
- },
- (rejection) => {
- if (rejection.status === 400) {
- snackbar.error(rejection.detail)
- } else {
- snackbar.apiError(rejection)
- }
- this.setState({ loading: false, preview: false })
- }
- )
- }
- closePreview = () => {
- this.setState({ loading: false, preview: false })
- }
- onDrop = (event) => {
- event.preventDefault()
- event.stopPropagation()
- if (!event.dataTransfer.files) return
- const { onAttachmentsChange: setState } = this.props
- if (misago.get("user").acl.max_attachment_size) {
- for (let i = 0; i < event.dataTransfer.files.length; i++) {
- const file = event.dataTransfer.files[i]
- uploadFile(file, setState)
- }
- }
- }
- onPaste = (event) => {
- const { onAttachmentsChange: setState } = this.props
- const files = []
- for (let i = 0; i < event.clipboardData.items.length; i++) {
- const item = event.clipboardData.items[i]
- if (item.kind === "file") {
- files.push(item.getAsFile())
- }
- }
- if (files.length) {
- event.preventDefault()
- event.stopPropagation()
- if (misago.get("user").acl.max_attachment_size) {
- for (let i = 0; i < files.length; i++) {
- uploadFile(files[i], setState)
- }
- }
- }
- }
- render = () => (
- <div
- className={classnames("markup-editor", {
- "markup-editor-focused": this.state.focused && !this.state.preview,
- })}
- >
- <MarkupEditorToolbar
- disabled={this.props.disabled || this.state.preview}
- element={this.state.element}
- update={(value) => this.props.onChange({ target: { value } })}
- updateAttachments={this.props.onAttachmentsChange}
- />
- {this.state.preview ? (
- <div className="markup-editor-preview">
- {this.state.loading ? (
- <div className="ui-preview">
- <span className="ui-preview-text" style={{ width: "240px" }} />
- </div>
- ) : (
- <MisagoMarkup markup={this.state.parsed} />
- )}
- </div>
- ) : (
- <textarea
- className="markup-editor-textarea form-control"
- placeholder={this.props.placeholder}
- value={this.props.value}
- disabled={this.props.disabled || this.state.loading}
- rows={6}
- ref={(element) => {
- if (element && !this.state.element) {
- this.setState({ element })
- setMentions(this.props, element)
- }
- }}
- onChange={this.props.onChange}
- onDrop={this.onDrop}
- onFocus={() => this.setState({ focused: true })}
- onPaste={this.onPaste}
- onBlur={() => this.setState({ focused: false })}
- />
- )}
- {this.props.attachments.length > 0 && (
- <MarkupEditorAttachments
- attachments={this.props.attachments}
- disabled={this.props.disabled || this.state.preview}
- element={this.state.element}
- setState={this.props.onAttachmentsChange}
- update={(value) => this.props.onChange({ target: { value } })}
- />
- )}
- <MarkupEditorFooter
- preview={this.state.preview}
- canProtect={this.props.canProtect}
- isProtected={this.props.isProtected}
- disabled={this.props.disabled}
- empty={
- this.props.value.trim().length <
- misago.get("SETTINGS").post_length_min || this.state.loading
- }
- enableProtection={this.props.enableProtection}
- disableProtection={this.props.disableProtection}
- showPreview={this.showPreview}
- closePreview={this.closePreview}
- submitText={this.props.submitText}
- />
- </div>
- )
- }
- function setMentions(props, element) {
- $(element).atwho({
- at: "@",
- displayTpl: '<li><img src="${avatar}" alt="">${username}</li>',
- insertTpl: "@${username}",
- searchKey: "username",
- callbacks: {
- remoteFilter: function (query, callback) {
- $.getJSON(misago.get("MENTION_API"), { q: query }, callback)
- },
- },
- })
- $(element).on("inserted.atwho", (event, flag, query) => {
- props.onChange(event)
- })
- }
- export default MarkupEditor
|