import { includes, some } from 'lodash' import { ProseEditor, TOCProvider, Toolbar } 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' import ModalWarning from './elements/modal_warning/ModalWarning' class Editor extends ProseEditor { constructor (parent, props) { super(parent, props) this.handleActions({ 'showComments': function () { this.toggleCommentsArea(true) }, 'hideComments': function () { this.toggleCommentsArea(false) }, // TODO -- clean them up like changesNotSaved 'trackChangesUpdate': function () { this.updateTrackChange() }, 'trackChangesViewToggle': function () { this.trackChangesViewToggle() }, // 'changesNotSaved': function () { this.changesNotSaved() } 'changesNotSaved': this.changesNotSaved }) } changesNotSaved () { this.extendState({ changesNotSaved: true }) } trackChangesViewToggle () { this.extendState({ trackChangesView: !this.state.trackChangesView }) } updateTrackChange () { // TODO -- clean up this.props and this.refs this.extendProps({ trackChanges: !this.props.trackChanges }) this.props.updateTrackChangesStatus(!this.props.trackChanges) this.refs.toolbar.extendProps({trackChanges: this.props.trackChanges}) } willUpdateState () {} didMount () { this.extendState({ editorReady: true }) } render ($$) { const { trackChangesView } = this.state const canToggleTrackChanges = this.canToggleTrackChanges() const el = $$('div').addClass('sc-prose-editor') // left side: editor and toolbar let toolbar = this._renderToolbar($$) let editor = this._renderEditor($$) let SplitPane = this.componentRegistry.get('split-pane') let ScrollPane = this.componentRegistry.get('scroll-pane') let Overlay = this.componentRegistry.get('overlay') // TODO -- unnecessary // posssibly breaks book builder dnd 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 props = { book: this.props.book, fragment: this.props.fragment, history: this.props.history } const toc = $$(TableOfContents, props) 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') const 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') } const modal = $$(ModalWarning, { width: 'medium', textAlign: 'center' }) if (this.state.changesNotSaved) { return el.append(modal) } return el } // TODO -- leverage ProseEditor's this._renderToolbar maybe? _renderToolbar ($$) { let viewMode = this.props.disabled ? $$('span') .addClass('view-mode') .append('Editor is in Read-Only mode') : '' let commandStates = this.commandManager.getCommandStates() return $$('div') .addClass('se-toolbar-wrapper') .append( $$(Toolbar, { commandStates: commandStates, trackChanges: this.props.trackChanges, trackChangesView: this.state.trackChangesView, toolGroups: [ 'text', 'document', 'annotations', 'default', 'track-change-enable', 'track-change-toggle-view' ] }).ref('toolbar') ) .append(viewMode) } _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, history: this.props.history, book: this.props.book }).ref('body') } getInitialState () { return { changesNotSaved: false, editorReady: false, 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 // toc provider const tocProvider = new TOCProvider(doc, { containerId: 'body' }) // 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, editorSession: this.editorSession, surfaceManager: this.surfaceManager, user: this.props.user }) // attach all to context return { ...oldContext, tocProvider, notesProvider, commentsProvider, trackChangesProvider } } } export default Editor