Skip to content

Commit

Permalink
better linebreak handling, more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
eessex committed Aug 17, 2017
1 parent 331ba7a commit 7c6e811
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 13 deletions.
3 changes: 3 additions & 0 deletions client/apps/edit/components/content2/section_list/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 13 additions & 7 deletions client/components/rich_text2/components/paragraph.coffee
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -9,7 +9,7 @@
# layout: article.layout
# postscript: default=false
# linked: default=false
# linebreaks: default=true
# stripLinebreaks: default=false
# type: 'postscript' | 'caption' | 'lead paragraph'
# }

Expand Down Expand Up @@ -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
Expand All @@ -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'
Expand Down Expand Up @@ -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'
Expand All @@ -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><p>/g, '')
return html

onPaste: (text, html) ->
{ editorState } = @state
unless html
html = '<div>' + text + '</div>'
html = Utils.standardizeSpacing html
html = Utils.stripGoogleStyles html
unless @state.linebreaks
html = html.replace(/<\/p><p>/g, '')
html = @stripLinebreaks(html) if @props.stripLinebreaks
html = html.replace(/<\/p><p>/g, '')
blocksFromHTML = @convertFromHTML html
convertedHtml = blocksFromHTML.getBlocksAsArray().map (contentBlock) =>
unstyled = Utils.stripCharacterStyles contentBlock, true
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions client/components/rich_text2/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down
78 changes: 72 additions & 6 deletions client/components/rich_text2/test/paragraph.test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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 = $ "<div></div>")[0], =>
component.setState showNav: true
$(ReactDOM.findDOMNode(component)).html().should.containEql '<button name="ITALIC" class="ITALIC">I</button><button name="BOLD" class="BOLD">B</button>'
$(ReactDOM.findDOMNode(component)).html().should.not.containEql '<button name="link" class="link">'

it 'Shows correct buttons if type unspecified and linked is true', ->
@component.setState showNav: true
$(ReactDOM.findDOMNode(@component)).html().should.containEql '<button name="ITALIC" class="ITALIC">I</button><button name="BOLD" class="BOLD">B</button><button name="link" class="link">'

it 'Does not show italic if type is postscript', ->
@props.linked = null
@props.type = 'postscript'
component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "<div></div>")[0], =>
component.setState showNav: true
$(ReactDOM.findDOMNode(component)).html().should.containEql '<button name="BOLD" class="BOLD">B</button><button name="link" class="link">'
$(ReactDOM.findDOMNode(component)).html().should.not.containEql '<button name="ITALIC" class="ITALIC">I</button>'

it 'Does not show bold if type is caption', ->
@props.linked = null
@props.type = 'caption'
component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "<div></div>")[0], =>
component.setState showNav: true
$(ReactDOM.findDOMNode(component)).html().should.containEql '<button name="ITALIC" class="ITALIC">I</button><button name="link" class="link">'
$(ReactDOM.findDOMNode(component)).html().should.not.containEql '<button name="BOLD" class="BOLD">B</button>'

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 '<strong>Illustration</strong>'

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 '<em>Illustration</em>'

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 = $ "<div></div>")[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 = $ "<div></div>")[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 = $ "<div></div>")[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(/<a href=/g) || []).length.should.eql 2

describe 'Linebreaks', ->

it 'allows linebreaks by default', ->
@props.html = '<p>Here one paragraph.</p><p>Here is second paragraph</p>'
component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "<div></div>")[0], =>
$(ReactDOM.findDOMNode(component)).find('p').length.should.eql 2

it 'strips linebreaks if props.stripLinebreaks', ->
@props.stripLinebreaks = true
@props.html = '<p>Here one paragraph.</p><p>Here is second paragraph</p>'
component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "<div></div>")[0], =>
$(ReactDOM.findDOMNode(component)).find('p').length.should.eql 1

it 'interrupts key command for linebreak if props.stripLinebreaks', ->
@props.stripLinebreaks = true
@props.html = '<p>Here one paragraph.</p><p>Here is second paragraph</p>'
component = ReactDOM.render React.createElement(@Paragraph, @props), (@$el = $ "<div></div>")[0], =>
keyResponse = component.handleKeyCommand('split-block')
keyResponse.should.eql 'handled'

describe '#onPaste', ->

it 'calls stripGoogleStyles', ->
Expand Down

0 comments on commit 7c6e811

Please sign in to comment.