Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Editor.js 6.58 KiB
import { includes, some } from 'lodash'

import {
  ProseEditor,
  TOCProvider
} from 'substance'

// import Comments from './panes/Comments/CommentBoxList'
// import CommentsProvider from './panes/Comments/CommentsProvider'
import ContainerEditor from './ContainerEditor'
import Notes from './panes/Notes/Notes'
import NotesProvider from './panes/Notes/NotesProvider'
import TableOfContents from './panes/TableOfContents/TableOfContents'
// import TrackChangesProvider from './elements/track_change/TrackChangesProvider'

class Editor extends ProseEditor {
  constructor (parent, props) {
    super(parent, props)

    this.handleActions({
      'showComments': function () { this.toggleCommentsArea(true) },
      'hideComments': function () { this.toggleCommentsArea(false) },
      'trackChangesUpdate': function () { this.updateTrackChange() },
      'domSelectionRendered': function () { this.domSelectionRendered() }
    })
  }

  domSelectionRendered () {
    // TODO what to handle here????
    // console.log('rendered')
  }

  updateTrackChange () {
    this.extendProps({
      trackChanges: !this.props.trackChanges
    })

    this.props.updateTrackChangesStatus(!this.props.trackChanges)

    this.extendState({ trackChanges: !this.props.trackChanges })
  }

  willUpdateState () {}

  didMount () {
    console.log(this.editorSession)
    this.editorSession.onUpdate('document', this.rerender, this, {})
    // this.documentSession.on('didUpdate', this.documentSessionUpdated, this)
    // this.documentSession.on('fileUploadTrigger', this.handleUpload, this)
    this.extendState({ editorReady: true })
  }

  handleUpload (file, callback) {
    const { fileUpload } = this.props

    // TODO -- then / catch
    fileUpload(file).then((res, err) => {
      if (err != null) callback(null, err)
      return callback(res.file, null)
    })
  }

  render ($$) {
    const { trackChangesView } = this.state
    const canToggleTrackChanges = this.canToggleTrackChanges()

    const el = $$('div').addClass('sc-prose-editor')

    // left side: editor and toolbar
    var toolbar = this._renderToolbar($$)
    var editor = this._renderEditor($$)

    let SplitPane = this.componentRegistry.get('split-pane')
    let ScrollPane = this.componentRegistry.get('scroll-pane')
    let Overlay = this.componentRegistry.get('overlay')
    let ContextMenu = this.componentRegistry.get('context-menu') // new what does it do?
    let Dropzones = this.componentRegistry.get('dropzones') // new what does it do?

    const footerNotes = $$(Notes)

    const toc = $$(TableOfContents)

    var editorWithFooter = $$('div')
      .append(
        editor,
        footerNotes
      )

    var commentsPane = this.state.editorReady
    ? $$(Comments, {
      // TODO -- should probably remove the || {}
      comments: this.props.fragment.comments || {},
      fragment: this.props.fragment,
      update: this.props.update,
      user: this.props.user
    }).addClass('sc-comments-pane')
    : $$('div')

    var editorWithComments = $$(SplitPane, { sizeA: '100%', splitType: 'vertical' })
      .append(
        editorWithFooter,
        commentsPane
      )

    var contentPanel = $$(ScrollPane, {
      name: 'contentPanel',
      // contextMenu: 'custom',
      scrollbarPosition: 'right'
    })
    .append(editorWithComments,
      $$(Overlay),
      $$(ContextMenu),
      $$(Dropzones))
    .attr('id', 'content-panel')
    .ref('contentPanel')

    var contentPanelWithSplitPane = $$(SplitPane, { sizeA: '75%', splitType: 'vertical' })
      .append(
        contentPanel,
        toc
      )

    el.append(
      $$(SplitPane, { splitType: 'horizontal' })
        .append(
          toolbar,
          contentPanelWithSplitPane
        )
    )

    if (trackChangesView && canToggleTrackChanges) {
      el.addClass('track-changes-mode')
    }

    return el
  }

  // TODO -- use this to insert read-only mode alert
  _renderToolbar ($$) {
    const toolbar = super._renderToolbar($$)
    return toolbar
  }

  _renderEditor ($$) {
    const configurator = this.props.configurator
    const editing = this.props.disabled ? 'selection' : 'full'
    return $$(ContainerEditor, {
      editing: editing,
      editorSession: this.editorSession,
      commands: configurator.getSurfaceCommandNames(),
      containerId: 'body',
      spellcheck: 'native',
      textTypes: configurator.getTextTypes(),
      trackChanges: this.props.trackChanges,
      updateTrackChangesStatus: this.props.updateTrackChangesStatus
    }).ref('body')
  }

  getInitialState () {
    return {
      editorReady: false,
      trackChanges: this.props.trackChanges,
      trackChangesView: true
    }
  }

  canToggleTrackChanges () {
    const { user } = this.props
    const accepted = ['admin', 'production-editor', 'copy-editor']
    return some(accepted, (role) => includes(user.roles, role))
  }

  scrollTo (nodeId) {
    this.refs.contentPanel.scrollTo(nodeId)
  }

  toggleCommentsArea (show) {
    var self = this

    setTimeout(function () {
      var el = self.refs.contentPanel

      if (show && !el.hasClass('sc-has-comments')) {
        el.addClass('sc-has-comments')
      }

      if (!show && el.hasClass('sc-has-comments')) {
        el.removeClass('sc-has-comments')
      }
    })
  }

  getChildContext () {
    const oldContext = super.getChildContext()
    const doc = this.doc

    const props = {
      book: this.props.book,
      fragment: this.props.fragment,
      history: this.props.history
    }
    // toc provider
    const tocProvider = new TOCProvider(doc, {
      containerId: 'body',
      props: props
    })

    // notes provider
    const notesProvider = new NotesProvider(doc)
    // comments provider
    const commentsProvider = new CommentsProvider(doc, {
      commandManager: this.commandManager,
      comments: this.props.fragment.comments,
      containerId: this.props.containerId,
      controller: this,
      editorSession: this.editorSession,
      fragment: this.props.fragment,
      surfaceManager: this.surfaceManager,
      toggleCommentsArea: this.toggleCommentsArea,
      update: this.props.update
    })

    // TODO -- do I need all of these?
    // track changes provider
    // const trackChangesProvider = new TrackChangesProvider(doc, {
    //   commandManager: this.commandManager,
    //   containerId: this.props.containerId,
    //   controller: this,
    //   documentSession: this.documentSession,
    //   surfaceManager: this.surfaceManager,
    //   user: this.props.user
    // })

    // attach all to context
    return {
      ...oldContext,
      tocProvider,
      notesProvider,
      commentsProvider,
      trackChangesProvider
    }
  }
}

export default Editor