diff --git a/app/components/SimpleEditor/ContainerEditor.js b/app/components/SimpleEditor/ContainerEditor.js index 58f0df11df9e5db7ae7d34a2f347848ab9a8101b..c80b368df9b78b149285fccdb6655d19e9106d93 100644 --- a/app/components/SimpleEditor/ContainerEditor.js +++ b/app/components/SimpleEditor/ContainerEditor.js @@ -45,20 +45,22 @@ class ContainerEditor extends SubstanceContainerEditor { this.addTargetToLinks() } - this.props.history.listenBefore((location, callback) => { - const commandStates = this.getCommandStates() + if (this.props.history) { + this.props.history.listenBefore((location, callback) => { + const commandStates = this.getCommandStates() - if (commandStates['save'].disabled === false) { - const editor = this.getEditor() + if (commandStates['save'].disabled === false) { + const editor = this.getEditor() - editor.send('changesNotSaved') - editor.emit('send:route', location.pathname) + editor.send('changesNotSaved') + editor.emit('send:route', location.pathname) - return callback(false) - } + return callback(false) + } - return callback() - }) + return callback() + }) + } window.history.pushState(null, null, document.URL) window.addEventListener('popstate', this.controlBackButton) diff --git a/app/components/SimpleEditor/Editor.js b/app/components/SimpleEditor/Editor.js index bc9b25c2c8eb160bea5dc74692b296b4bb42f5cf..4633a5df045fd9f8482825be11e77aa48aa0bd4c 100644 --- a/app/components/SimpleEditor/Editor.js +++ b/app/components/SimpleEditor/Editor.js @@ -9,10 +9,13 @@ import { 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 { @@ -70,7 +73,7 @@ class Editor extends ProseEditor { // 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? + // let Dropzones = this.componentRegistry.get('dropzones') // new what does it do? const footerNotes = $$(Notes) @@ -111,12 +114,13 @@ class Editor extends ProseEditor { }) .append(editorWithComments, $$(Overlay), - $$(ContextMenu), - $$(Dropzones)) + $$(ContextMenu) + // $$(Dropzones) + ) .attr('id', 'content-panel') .ref('contentPanel') - var contentPanelWithSplitPane = $$(SplitPane, { sizeA: '75%', splitType: 'vertical' }) + const contentPanelWithSplitPane = $$(SplitPane, { sizeA: '75%', splitType: 'vertical' }) .append( contentPanel, toc @@ -163,10 +167,10 @@ class Editor extends ProseEditor { trackChanges: this.props.trackChanges, trackChangesView: this.state.trackChangesView, toolGroups: [ + 'text', + 'document', 'annotations', 'default', - 'document', - 'text', 'track-change-enable', 'track-change-toggle-view' ] diff --git a/app/components/SimpleEditor/SimpleEditor.scss b/app/components/SimpleEditor/SimpleEditor.scss index da9ed1141e0cd6dd8c492d28d980806489f66def..07b4ec5be3743d6d32e6a7c4c2bb484a875954c4 100644 --- a/app/components/SimpleEditor/SimpleEditor.scss +++ b/app/components/SimpleEditor/SimpleEditor.scss @@ -5,6 +5,8 @@ $fa-font-path: '~font-awesome/fonts'; @import '~substance/substance.css'; @import './elements/elements'; @import './panes/panes'; +@import './miniEditor/miniEditor'; + // grays $border: #ccc; @@ -62,7 +64,6 @@ $active-blue: #4a90e2; position: absolute; right: 0; top: 0; - .se-toolbar-wrapper .sc-toolbar { background-color: $primary; border: 1px solid $border; @@ -85,6 +86,7 @@ $active-blue: #4a90e2; height: 100%; padding: 0; position: relative; + .sc-switch-text-type { margin-left: 1px; width: 150px; @@ -94,6 +96,7 @@ $active-blue: #4a90e2; position: relative; top: 5px; } + .se-toggle { background: transparent; border: 0; diff --git a/app/components/SimpleEditor/config.js b/app/components/SimpleEditor/config.js index 0984a6ac8b65b7861de603f60bd92d5ed0cf36e3..4a0825ae6625557d29902d434c5cdc7dd8e93074 100644 --- a/app/components/SimpleEditor/config.js +++ b/app/components/SimpleEditor/config.js @@ -1,28 +1,30 @@ import { BasePackage, - BlockquotePackage, + // BlockquotePackage, CodePackage, EmphasisPackage, HeadingPackage, + LinkPackage, + // ListPackage, ParagraphPackage, PersistencePackage, ProseArticle, - LinkPackage, + SpellCheckPackage, StrongPackage, SubscriptPackage, SuperscriptPackage, - SwitchTextTypePackage, - SpellCheckPackage, - CodeblockPackage + SwitchTextTypePackage } from 'substance' +// console.log(BlockquotePackage) + // My Elements import CommentPackage from './elements/comment/CommentPackage' import ExtractPackage from './elements/extract/ExtractPackage' -import NotePackage from './elements/note/NotePackage' -import SourceNotePackage from './elements/source_note/SourceNotePackage' import ImagePackage from './elements/images/ImagePackage' import ListPackage from './elements/list/ListPackage' +import NotePackage from './elements/note/NotePackage' +import SourceNotePackage from './elements/source_note/SourceNotePackage' import TrackChangePackage from './elements/track_change/TrackChangePackage' let config = { @@ -37,10 +39,10 @@ let config = { config.import(BasePackage, { noBaseStyles: options.noBaseStyles }) + config.import(SwitchTextTypePackage) config.import(ParagraphPackage) config.import(HeadingPackage) - config.import(BlockquotePackage) config.import(EmphasisPackage) config.import(StrongPackage) config.import(SubscriptPackage) @@ -48,15 +50,15 @@ let config = { config.import(CodePackage) config.import(PersistencePackage) + // config.import(CodeblockPackage) + config.import(CommentPackage) + config.import(ExtractPackage) + config.import(ImagePackage) config.import(LinkPackage) - config.import(SpellCheckPackage) config.import(ListPackage) - config.import(CodeblockPackage) - config.import(ExtractPackage) config.import(NotePackage) config.import(SourceNotePackage) - config.import(ImagePackage) - config.import(CommentPackage) + config.import(SpellCheckPackage) config.import(TrackChangePackage) } } diff --git a/app/components/SimpleEditor/elements/extract/ExtractComponent.js b/app/components/SimpleEditor/elements/extract/ExtractComponent.js index 486d05e512b1dc4c914582448d2f63575542495d..9882c9adf5974a60757842ee6cee6c9d92d0c59e 100644 --- a/app/components/SimpleEditor/elements/extract/ExtractComponent.js +++ b/app/components/SimpleEditor/elements/extract/ExtractComponent.js @@ -2,7 +2,7 @@ import { TextBlockComponent } from 'substance' class ExtractComponent extends TextBlockComponent { didMount () { - this.addClass('sc-extract') + this.addClass('sc-blockquote') } } diff --git a/app/components/SimpleEditor/elements/note/EditNoteTool.js b/app/components/SimpleEditor/elements/note/EditNoteTool.js index 3e5e7ece23993dba906ddddf30b08413563d4eb1..34a4777823249f0156bf84cbd5bfe606213f7fba 100644 --- a/app/components/SimpleEditor/elements/note/EditNoteTool.js +++ b/app/components/SimpleEditor/elements/note/EditNoteTool.js @@ -1,49 +1,56 @@ import { each, includes, keys } from 'lodash' -import { documentHelpers, FontAwesomeIcon as Icon, Tool } from 'substance' -import PromptTextArea from './PromptTextArea' +import { documentHelpers, Tool, ProseEditorConfigurator as Configurator, + EditorSession } from 'substance' + +import MiniEditor from '../../miniEditor/miniEditor' +import config from '../../miniEditor/config' +import Importer from '../../SimpleEditorImporter' +import SimpleExporter from '../../SimpleEditorExporter' class EditNoteTool extends Tool { + + constructor (props) { + super(props) + this.saveNote = this.saveNote.bind(this) + } + render ($$) { + const miniEditorSession = this._initMiniEditor() let el = $$('div').addClass('sc-edit-note-tool') - const selected = this.getSelection() if (!selected.node) return el + el.append($$(MiniEditor, { + editorSession: miniEditorSession + })) + return el + } - const disabled = this.isEditorReadOnly() - - // TODO -- on this.getLabel add a label to package and call it save note - const icon = $$(Icon, { icon: 'fa-save' }) - .addClass('sc-save-icon') + didMount () { + this.context.editorSession.onUpdate('', this.disableTools, this) + } - const save = $$('div') - .addClass('sc-save-area') - .append(icon) - .on('click', this.saveNote) + _initMiniEditor () { + const selected = this.getSelection() + if (!selected.node) return - const noteTool = $$('div') - .addClass('sc-edit-note-tool-container') - .append( - $$(PromptTextArea, { - disabled: disabled, - path: [selected.node.id, 'note-content'], - placeholder: 'Type your note here' - }) - ) - if (!disabled) noteTool.append(save) + const configurator = new Configurator().import(config) + configurator.addImporter('html', Importer) - el.append(noteTool) + const importer = configurator.createImporter('html') + const doc = importer.importDocument(selected.node['note-content']) - // to properly adjust text area height depending on text - this.setTextAreaHeight() + const editorSession = new EditorSession(doc, { + configurator: configurator + }) - return el - } + editorSession.setSaveHandler({ + saveDocument: this.saveNote + }) - didMount () { - this.context.editorSession.onUpdate('', this.diabelTools, this) + return editorSession } - diabelTools () { + disableTools () { const selected = this.getSelection() if (!selected.node) return const commandStates = this.context.commandManager.commandStates @@ -51,15 +58,24 @@ class EditNoteTool extends Tool { const allowed = ['comment', 'redo', 'save', 'switch-text-type', 'undo', 'note'] if (!includes(allowed, key)) commandStates[key].disabled = true }) + this.rerender() } - saveNote (event) { + saveNote (source) { const selected = this.getSelection() - const noteContent = this.el.find('textarea').val() + const config = this.context.editorSession.configurator.config + const exporter = new SimpleExporter(config) + const convertedSource = exporter.exportDocument(source) const editorSession = this.context.editorSession + editorSession.transaction(function (tx, args) { const path = [selected.node.id, 'note-content'] - tx.set(path, noteContent) + tx.set(path, convertedSource) + }) + + // Return dummy Promise needed in saveDocument + return new Promise(function (resolve, reject) { + resolve() }) } @@ -68,7 +84,6 @@ class EditNoteTool extends Tool { const surface = this.context.surfaceManager.getFocusedSurface() if (!surface) return {} - const commandStates = this.context.commandManager.commandStates const session = this.context.editorSession const sel = session.getSelection() @@ -92,17 +107,6 @@ class EditNoteTool extends Tool { } } - // TODO -- duplicate code from propmt text area file in same folder?? - setTextAreaHeight () { - setTimeout(function () { - let textarea = document.querySelector('.se-note-textarea') - - if (textarea) { - textarea.style.height = (textarea.scrollHeight) + 'px' - } - }) - } - getSurface () { const surfaceManager = this.context.surfaceManager return surfaceManager.getFocusedSurface() diff --git a/app/components/SimpleEditor/elements/note/NoteComponent.js b/app/components/SimpleEditor/elements/note/NoteComponent.js index 2fc73d9246b2869d6dc86eff4f11bcf68b1109cb..a5c9825695cacc2e75c82ec82cb95fe830073e37 100644 --- a/app/components/SimpleEditor/elements/note/NoteComponent.js +++ b/app/components/SimpleEditor/elements/note/NoteComponent.js @@ -7,6 +7,7 @@ class NoteComponent extends Component { const el = $$('note') .attr('note-content', this.props.node['note-content']) .addClass('sc-note') + // .append('a') return el } diff --git a/app/components/SimpleEditor/elements/note/NoteTool.js b/app/components/SimpleEditor/elements/note/NoteTool.js index fdd2d84748921688a862b5e6b0ca96dc14c9209c..b5d712753aa16a46ff3241ab7c18c3709066a9e8 100644 --- a/app/components/SimpleEditor/elements/note/NoteTool.js +++ b/app/components/SimpleEditor/elements/note/NoteTool.js @@ -3,8 +3,11 @@ import { AnnotationTool } from 'substance' class NoteTool extends AnnotationTool { renderButton ($$) { const el = super.renderButton($$) - const readOnly = this.isSurfaceReadOnly() - if (readOnly === true) el.attr('disabled', 'true') + + // TODO -- either delete or re-introduce + // const readOnly = this.isSurfaceReadOnly() + // if (readOnly === true) el.attr('disabled', 'true') + return el } diff --git a/app/components/SimpleEditor/elements/note/note.scss b/app/components/SimpleEditor/elements/note/note.scss index 18ee7010c649834b85881724a5ab07cfe5a93fb4..fb665bad00eb8e45e56b8cd2f7161e2158d7207f 100644 --- a/app/components/SimpleEditor/elements/note/note.scss +++ b/app/components/SimpleEditor/elements/note/note.scss @@ -1,15 +1,15 @@ $gray: #eee; $red: #591818; -.hidden { - display: none; -} +// .hidden { +// display: none; +// } .sc-prose-editor { counter-reset: note; .sc-note { color: $red; + display: inline-block; // TODO -- is this correct? font-weight: bold; - display: inline-block; } .sc-note::after { diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangeControlTool.js b/app/components/SimpleEditor/elements/track_change/TrackChangeControlTool.js index 4497a5c70aa9cbda43103d704b31db3ce96f9f47..d5b1d6cdee1dc99f294c20bd7ad15be67cf40bc7 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangeControlTool.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangeControlTool.js @@ -1,7 +1,6 @@ import { Tool } from 'substance' class TrackChangeControlTool extends Tool { - renderButton ($$) { const el = super.renderButton($$) diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangeControlViewTool.js b/app/components/SimpleEditor/elements/track_change/TrackChangeControlViewTool.js index a9a01c29c00c7a116f96bf6c916696a871b2e444..9bbba4442ce36b323a9540c787c4bdf75c4a5666 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangeControlViewTool.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangeControlViewTool.js @@ -1,7 +1,6 @@ import { Tool } from 'substance' class TrackChangeControlViewTool extends Tool { - renderButton ($$) { const el = super.renderButton($$) if (this.getViewMode()) el.addClass('track-changes-view-active') diff --git a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js index 35298b373f626d0e19a9643ae5497a94a76605b8..8e7ebe93a759fec60fd4751fd5211198f647c1e1 100644 --- a/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js +++ b/app/components/SimpleEditor/elements/track_change/TrackChangesProvider.js @@ -6,7 +6,7 @@ import { findIndex, includes, keys, - last, + // last, map, maxBy, minBy, @@ -757,12 +757,12 @@ class TrackChangesProvider extends TOCProvider { } handleRedo () { - const documentSession = this.getEditorSession() - const undoneChanges = documentSession.undoneChanges - const lastChange = last(undoneChanges) - const op = last(lastChange.ops) - - const isTrack = op.path[0].split('-').slice(0, -1).join('-') === 'track-change' + // const documentSession = this.getEditorSession() + // const undoneChanges = documentSession.undoneChanges + // const lastChange = last(undoneChanges) + // const op = last(lastChange.ops) + // + // const isTrack = op.path[0].split('-').slice(0, -1).join('-') === 'track-change' } /* diff --git a/app/components/SimpleEditor/miniEditor/config.js b/app/components/SimpleEditor/miniEditor/config.js new file mode 100644 index 0000000000000000000000000000000000000000..e4157d52834d571e43ed166825a3da8c92ca3488 --- /dev/null +++ b/app/components/SimpleEditor/miniEditor/config.js @@ -0,0 +1,32 @@ +import { + BasePackage, + EmphasisPackage, + ParagraphPackage, + PersistencePackage, + ProseArticle, + StrongPackage, + SpellCheckPackage + +} from 'substance' + +let config = { + name: 'simple-editor', + configure: (config, options) => { + config.defineSchema({ + name: 'prose-article', + ArticleClass: ProseArticle, + defaultTextType: 'paragraph' + }) + + config.import(BasePackage, { + noBaseStyles: options.noBaseStyles + }) + config.import(ParagraphPackage) + config.import(EmphasisPackage) + config.import(StrongPackage) + config.import(PersistencePackage) + config.import(SpellCheckPackage) + } +} + +export default config diff --git a/app/components/SimpleEditor/miniEditor/miniEditor.js b/app/components/SimpleEditor/miniEditor/miniEditor.js new file mode 100644 index 0000000000000000000000000000000000000000..59d82c9fe090e5ff8b9eed1a5ef2abd33fa277a5 --- /dev/null +++ b/app/components/SimpleEditor/miniEditor/miniEditor.js @@ -0,0 +1,51 @@ +import { + ProseEditor, + Toolbar +} from 'substance' + +import ContainerEditor from '../ContainerEditor' + +class MiniEditor extends ProseEditor { + render ($$) { + const el = $$('div').addClass('sc-mini-editor') + let toolbar = this._renderMiniToolbar($$) + let editor = this._renderEditor($$) + let SplitPane = this.componentRegistry.get('split-pane') + let ScrollPane = this.componentRegistry.get('scroll-pane') + + const contentPanel = $$(ScrollPane, { + name: 'miniEditorContentPanel', + scrollbarPosition: 'right' + }) + .append(editor) + .attr('id', 'content-panel') + .ref('miniEditorContentPanel') + + el.append( + $$(SplitPane, { splitType: 'horizontal' }) + .append(toolbar, contentPanel) + ) + + return el + } + + _renderMiniToolbar ($$) { + let commandStates = this.commandManager.getCommandStates() + return $$('div').addClass('se-toolbar-wrapper').append( + $$(Toolbar, { + commandStates: commandStates, + toolGroups: ['document', 'annotations'] + }).ref('mini_toolbar') + ) + } + + _renderEditor ($$) { + return $$(ContainerEditor, { + editorSession: this.editorSession, + containerId: 'body', + spellcheck: 'native' + }).ref('mini_body') + } +} + +export default MiniEditor diff --git a/app/components/SimpleEditor/miniEditor/miniEditor.scss b/app/components/SimpleEditor/miniEditor/miniEditor.scss new file mode 100644 index 0000000000000000000000000000000000000000..08b488faf39b8356f7217e8a671cb707b461e226 --- /dev/null +++ b/app/components/SimpleEditor/miniEditor/miniEditor.scss @@ -0,0 +1,37 @@ +$gray: #591818; +$background: #eee; + +.sc-prose-editor .sc-mini-editor { + border: 1px solid $gray; + height: 160px; + width: 360px; + + .se-toolbar-wrapper { + .sc-toolbar { + background-color: $background; + border: 0; + + .sc-tool-group.sm-layout-horizontal > * { + margin: 0; + } + } + } + + .se-scrollable { + height: 120px; + margin-top: 0; + + .se-content { + background: $background; + color: $gray; + line-height: 20px; + margin: 0; + min-height: 110px; + + .sc-container-editor { + padding: 0; + } + + } + } +} diff --git a/app/components/SimpleEditor/panes/Comments/CommentBox.js b/app/components/SimpleEditor/panes/Comments/CommentBox.js index 453c569bb1b8bc61d384ae118e51dcb2a9d0794e..8e9fa86798ce430340c6295af51038134395acc2 100644 --- a/app/components/SimpleEditor/panes/Comments/CommentBox.js +++ b/app/components/SimpleEditor/panes/Comments/CommentBox.js @@ -15,8 +15,7 @@ class CommentBox extends Component { // TODO -- fix class names render ($$) { - const {active, entry} = this.props - + const { active, entry } = this.props let comments = this.props.comments.data if (!active) { diff --git a/app/components/SimpleEditor/panes/Notes/Notes.js b/app/components/SimpleEditor/panes/Notes/Notes.js index e153b8d8e86b32f4094b317b1971b02027a28cd7..be97a2b8c1ef5f0f95b4b4e3f69bbce187fccf1e 100644 --- a/app/components/SimpleEditor/panes/Notes/Notes.js +++ b/app/components/SimpleEditor/panes/Notes/Notes.js @@ -9,21 +9,71 @@ class Notes extends Component { render ($$) { const provider = this.getProvider() const entries = provider.getEntries() + let self = this const listItems = entries.map(function (entry, i) { + let extractedElement = '' + if (entry.content) { + extractedElement = self.parseEntryContent($$, entry.content) + return extractedElement + .attr('data-id', entry.id) + .addClass('sc-notes-footer-item') + } return $$('li') .attr('data-id', entry.id) .addClass('sc-notes-footer-item') - .append(entry.content) + .append(extractedElement) }) if (listItems.length === 0) return $$('div') - return $$('ol') .addClass('sc-notes-footer') .append(listItems) } + parseEntryContent ($$, content) { + let parser = new DOMParser() + let parsedContent = parser.parseFromString(content, 'text/html').body + let parentElement = parsedContent.childNodes[0] + let children = parentElement.childNodes + let constructedElement = $$('li') + + for (let i = 0; i < children.length; i++) { + if (children[i].nodeName === '#text') { + constructedElement.append(children[i].data) + } else { + let contructedChildElement = $$(children[i].nodeName) + // Case of nested styling, first contruct the sub child node + if (children[i].children.length === 1) { + let contructedSubChildElement = $$(children[i].children[0].nodeName) + this.assignVirtualElementClass(children[i].children[0], contructedSubChildElement) + this.assignVirtualElementClass(children[i], contructedChildElement) + + contructedSubChildElement.append(children[i].children[0].innerText) + contructedChildElement.append(contructedSubChildElement) + } else { + this.assignVirtualElementClass(children[i], contructedChildElement) + contructedChildElement.append(children[i].innerText) + } + + constructedElement.append(contructedChildElement) + } + } + + return constructedElement + } + + assignVirtualElementClass (DOMElement, virtualElement) { + switch (DOMElement.nodeName) { + case 'STRONG': + virtualElement.addClass('sc-strong') + break + case 'EM': + virtualElement.addClass('sc-emphasis') + break + } + } + getProvider () { return this.context.notesProvider } diff --git a/app/components/SimpleEditor/panes/TableOfContents/TableOfContents.js b/app/components/SimpleEditor/panes/TableOfContents/TableOfContents.js index fd109a1ff7f2bf7dcd9719a20149a9647a264c48..f60ffc5a7b53ae3447fc8c616c8185f6c434f94f 100644 --- a/app/components/SimpleEditor/panes/TableOfContents/TableOfContents.js +++ b/app/components/SimpleEditor/panes/TableOfContents/TableOfContents.js @@ -12,6 +12,7 @@ class TableOfContents extends Toc { this.rerender() }) + // this.on('toc:updated', this.reComputeEntries, this) } // TODO better way? after editor's initial render ,every change in the document is not