From 7c6e81185883b2a13ec4927435eeea52dbaf0329 Mon Sep 17 00:00:00 2001 From: Eve Essex Date: Thu, 17 Aug 2017 15:00:36 -0400 Subject: [PATCH] better linebreak handling, more tests --- .../content2/section_list/index.styl | 3 + .../rich_text2/components/paragraph.coffee | 20 +++-- client/components/rich_text2/index.styl | 2 + .../rich_text2/test/paragraph.test.coffee | 78 +++++++++++++++++-- 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/client/apps/edit/components/content2/section_list/index.styl b/client/apps/edit/components/content2/section_list/index.styl index 3f8dd35bf..72534bf2e 100644 --- a/client/apps/edit/components/content2/section_list/index.styl +++ b/client/apps/edit/components/content2/section_list/index.styl @@ -10,6 +10,9 @@ .public-DraftEditorPlaceholder-root position absolute color gray-dark-color + top 27px + Garamond s23 + font-style italic .standard max-width standard-max-width diff --git a/client/components/rich_text2/components/paragraph.coffee b/client/components/rich_text2/components/paragraph.coffee index 65902899e..b1b009d45 100644 --- a/client/components/rich_text2/components/paragraph.coffee +++ b/client/components/rich_text2/components/paragraph.coffee @@ -1,5 +1,5 @@ # A basic paragraph component: supports bold and italic styles -# optionally allows links and linebreaks +# optionally allows links and stripping of linebreaks # or format in types 'postscript', 'caption' and 'lead paragraph' # Paragraph { @@ -9,7 +9,7 @@ # layout: article.layout # postscript: default=false # linked: default=false -# linebreaks: default=true +# stripLinebreaks: default=false # type: 'postscript' | 'caption' | 'lead paragraph' # } @@ -46,11 +46,11 @@ module.exports = React.createClass showNav: false urlValue: '' selectionTarget: null - linebreaks: @props.linebreaks or true componentDidMount: -> if $(@props.html).text().length html = Utils.standardizeSpacing @props.html + html = @stripLinebreaks(html) if @props.stripLinebreaks blocksFromHTML = @convertFromHTML(html) @setState html: html @@ -77,6 +77,7 @@ module.exports = React.createClass showNav: false convertFromHTML: (html) -> + html = @stripLinebreaks(html) if @props.stripLinebreaks blocksFromHTML = convertFromHTML({ htmlToEntity: (nodeName, node) -> if nodeName is 'a' @@ -106,7 +107,7 @@ module.exports = React.createClass return Array.from(available) handleKeyCommand: (e) -> - return 'handled' if @state.linebreaks is false and e is 'split-block' + return 'handled' if @props.stripLinebreaks is true and e is 'split-block' if e is 'link-prompt' @promptForLink() if @hasLinks() return 'handled' @@ -121,14 +122,19 @@ module.exports = React.createClass selection = Utils.getSelectionDetails(@state.editorState) @onChange RichUtils.toggleInlineStyle(@state.editorState, inlineStyle) + + stripLinebreaks: (html) -> + html = html.replace(/<\/p>

/g, '') + return html + onPaste: (text, html) -> { editorState } = @state unless html html = '

' + text + '
' html = Utils.standardizeSpacing html html = Utils.stripGoogleStyles html - unless @state.linebreaks - html = html.replace(/<\/p>

/g, '') + html = @stripLinebreaks(html) if @props.stripLinebreaks + html = html.replace(/<\/p>

/g, '') blocksFromHTML = @convertFromHTML html convertedHtml = blocksFromHTML.getBlocksAsArray().map (contentBlock) => unstyled = Utils.stripCharacterStyles contentBlock, true @@ -214,7 +220,7 @@ module.exports = React.createClass if !window.getSelection().isCollapsed location = Utils.getSelectionLocation $(ReactDOM.findDOMNode(@refs.editor)).offset() selectionTargetL = Config.inlineStyles(@props.type).length * 25 - selectionTargetL = selectionTargetL + 50 if @hasLinks() + selectionTargetL = selectionTargetL + 25 if @hasLinks() @setState showNav: true, selectionTarget: Utils.stickyControlsBox(location, -43, selectionTargetL) else @setState showNav: false diff --git a/client/components/rich_text2/index.styl b/client/components/rich_text2/index.styl index 8214e4872..e4c90d7e8 100644 --- a/client/components/rich_text2/index.styl +++ b/client/components/rich_text2/index.styl @@ -81,6 +81,8 @@ border none border-right 1px solid gray-darkest-color transition color .15s + &:last-child + border-right none &:hover color gray-color &[name='ITALIC'], diff --git a/client/components/rich_text2/test/paragraph.test.coffee b/client/components/rich_text2/test/paragraph.test.coffee index 76944e156..528e2c754 100644 --- a/client/components/rich_text2/test/paragraph.test.coffee +++ b/client/components/rich_text2/test/paragraph.test.coffee @@ -108,33 +108,99 @@ describe 'Rich Text: Paragraph', -> @component.setState.args[0][0].selectionTarget.should.eql { top: 20, left: 40 } @component.setState.args[0][0].showUrlInput.should.eql true - describe '#hasLinks', -> + describe 'Nav', -> - it 'returns true if props.linked', -> + it 'Prints Italic and Bold buttons by default', -> + @props.linked = null + component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "

")[0], => + component.setState showNav: true + $(ReactDOM.findDOMNode(component)).html().should.containEql '' + $(ReactDOM.findDOMNode(component)).html().should.not.containEql '' + + it 'Does not show bold if type is caption', -> + @props.linked = null + @props.type = 'caption' + component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "
")[0], => + component.setState showNav: true + $(ReactDOM.findDOMNode(component)).html().should.containEql '' + + it 'Can toggle bold styles', -> + @component.setState showNav: true + @component.setState = sinon.stub() + r.simulate.mouseDown r.find @component, 'BOLD' + @component.setState.args[0][0].html.should.containEql 'Illustration' + + it 'Can toggle italic styles', -> + @component.setState showNav: true + @component.setState = sinon.stub() + r.simulate.mouseDown r.find @component, 'ITALIC' + @component.setState.args[0][0].html.should.containEql 'Illustration' + + it 'Can toggle a link prompt', -> + @component.setState showNav: true + @component.setState = sinon.stub() + r.simulate.mouseDown r.find @component, 'link' + @component.setState.args[0][0].selectionTarget.should.eql { top: 20, left: 40 } + @component.setState.args[0][0].showUrlInput.should.eql true + + describe 'Links', -> + + it '#hasLinks returns true if props.linked', -> component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "
")[0], => haslinks = component.hasLinks() haslinks.should.eql true - it 'returns true if type is postscript', -> + it '#hasLinks returns true if type is postscript', -> @props.type = 'postscript' @props.linked = null component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "
")[0], => haslinks = component.hasLinks() haslinks.should.eql true - it 'returns true if type is caption', -> + it '#hasLinks returns true if type is caption', -> @props.type = 'caption' @props.linked = null component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "
")[0], => haslinks = component.hasLinks() haslinks.should.eql true - describe 'Links', -> - it '#confirmLink can save a link as html', -> @component.confirmLink('http://artsy.net') (@component.state.html.match(/ + + it 'allows linebreaks by default', -> + @props.html = '

Here one paragraph.

Here is second paragraph

' + component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "
")[0], => + $(ReactDOM.findDOMNode(component)).find('p').length.should.eql 2 + + it 'strips linebreaks if props.stripLinebreaks', -> + @props.stripLinebreaks = true + @props.html = '

Here one paragraph.

Here is second paragraph

' + component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "
")[0], => + $(ReactDOM.findDOMNode(component)).find('p').length.should.eql 1 + + it 'interrupts key command for linebreak if props.stripLinebreaks', -> + @props.stripLinebreaks = true + @props.html = '

Here one paragraph.

Here is second paragraph

' + component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "
")[0], => + keyResponse = component.handleKeyCommand('split-block') + keyResponse.should.eql 'handled' + describe '#onPaste', -> it 'calls stripGoogleStyles', ->