Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#351 Inline editable enchancements #366

Merged
merged 2 commits into from
Jan 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 42 additions & 15 deletions modules/inline-editable/main/index.coffee
Original file line number Diff line number Diff line change
@@ -1,32 +1,59 @@
hx.userFacingText({
inlineEditable: {
enterValue: 'Enter Value'
}
})

class InlineEditable extends hx.InlineMorphSection

enterEditMode = (toggle, content) ->
hx.select(content).select('.hx-name').value(hx.select(toggle).text())
hx.select(content).select('.hx-confirm').on 'click', 'hx.inline-editable', =>
value = hx.select(content).select('.hx-name').value()
@textSelection.text(value)
@emit('change', {api: false, value: value})
this.hide()
enterEditMode = (options) -> (toggle, content) ->
value = hx.select(toggle).text()
inputSel = hx.select(content).select('.hx-name')
if value isnt options.enterValueText
inputSel.value(value)
inputSel.node().focus()

constructor: (@selector) ->
constructor: (@selector, opts) ->
# MorphSection registers the component

selection = hx.select(@selector).classed('hx-inline-editable', true)

text = selection.text()
defaultOptions = {
enterValueText: hx.userFacingText('inlineEditable', 'enterValue'),
value: selection.text()
}

options = hx.merge defaultOptions, opts

selection.text('')
@textSelection = selection.append('a').class('hx-morph-toggle').text(text)

@textSelection = selection.append('a').class('hx-morph-toggle').text(options.value || options.enterValueText)

input = hx.detached('input').class('hx-name').attr('placeholder', options.enterValueText)
confirm = hx.detached('button').class('hx-btn hx-positive hx-confirm').add(hx.detached('i').class('hx-icon hx-icon-check'))

setValue = =>
value = input.value()
@textSelection.text(value || options.enterValueText)
.classed('hx-inline-editable-no-value', !value.length)
@emit('change', { cause: 'user', value: value })
@hide()

confirm.on 'click', 'hx.inline-editable', setValue
input.on 'keydown', 'hx.inline-editable', (e) ->
if e.key is 'Enter' or e.keyCode is 13 or e.which is 13
setValue()

selection.append('div').class('hx-morph-content hx-input-group')
.add hx.detached('input').class('hx-name')
.add hx.detached('button').class('hx-btn hx-positive hx-confirm').add(hx.detached('i').class('hx-icon hx-icon-check'))
.add input
.add confirm


super(@selector, enterEditMode, ->)
super(@selector, enterEditMode(options))

value: (value) ->
if value isnt undefined
@textSelection.text(value)
@emit('change', {api: false, value: value})
@emit('change', { cause: 'api', value: value })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was broken anyway (api was always passed as false) so I updated to the cause/value mentality.

else
@textSelection.text()

Expand Down
4 changes: 4 additions & 0 deletions modules/inline-editable/main/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
.hx-input-group {
margin: -0.45em 0;
}
}

.hx-inline-editable-no-value {
font-style: italic;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making it italic when no value has been entered is probably enough of a visual cue (along with the Enter Value text) that the user should do something

}
4 changes: 3 additions & 1 deletion modules/inline-editable/module.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"component",
"morph-section",
"input-group",
"icon"
"icon",
"user-facing-text",
"util"
],
"keywords": [
"inline",
Expand Down
165 changes: 164 additions & 1 deletion modules/inline-editable/test/spec.coffee
Original file line number Diff line number Diff line change
@@ -1,2 +1,165 @@
describe 'inline-editable', ->
# ...
fixture = undefined

before ->
fixture = hx.detached('div')
hx.select('body').add(fixture)

beforeEach ->
fixture.clear()

after ->
fixture.remove()

it 'should have user facing text defined', ->
hx.userFacingText('inlineEditable', 'enterValue').should.equal('Enter Value')

it 'should use the text of the selection used to create it as the value', ->
container = fixture.append('div').text('test')
ie = new hx.InlineEditable(container.node())
ie.value().should.equal('test')

it 'should correctly set the input value', ->
container = fixture.append('div').text('test')
ie = new hx.InlineEditable(container.node())
input = container.select('.hx-name')
input.value().should.equal('')
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.value().should.equal('test')

it 'should use the value option correctly', ->
container = fixture.append('div').text('test')
ie = new hx.InlineEditable(container.node(), {
value: 'Dave'
})
ie.value().should.equal('Dave')

it 'should emit the change event when the value is updated using the api', ->
container = fixture.append('div')
ie = new hx.InlineEditable(container.node())
spy = chai.spy()
ie.on 'change', spy
ie.value('test')
spy.should.have.been.called.with({
cause: 'api',
value: 'test'
})

it 'should emit the change event when the value is updated', ->
container = fixture.append('div')
ie = new hx.InlineEditable(container.node())
spy = chai.spy()
ie.on 'change', spy
input = container.select('.hx-name')
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.value('bob')
testHelpers.fakeNodeEvent(container.select('.hx-confirm').node())()
spy.should.have.been.called.with({
cause: 'user',
value: 'bob'
})

it 'should show and focus the input when clicked', ->
container = fixture.append('div')
ie = new hx.InlineEditable(container.node())
input = container.select('.hx-name').node()
content = container.select('.hx-morph-content')
input.should.not.equal(document.activeElement)
content.style('display').should.equal('none')
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.should.equal(document.activeElement)
content.style('display').should.equal('block')

it 'should show the enterValueText when no value is provided', ->
container = fixture.append('div')
ie = new hx.InlineEditable(container.node())
container.text().should.equal('Enter Value')

it 'should use the provided enterValueText', ->
container = fixture.append('div')
ie = new hx.InlineEditable(container.node(), {
enterValueText: 'Bob'
})
container.text().should.equal('Bob')

it 'should show the enterValueText when the value is cleared', ->
container = fixture.append('div').text('test')
ie = new hx.InlineEditable(container.node())
input = container.select('.hx-name')
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.value('')
testHelpers.fakeNodeEvent(container.select('.hx-confirm').node())()
container.text().should.equal('Enter Value')

it 'should set the value when enter is pressed', ->
container = fixture.append('div')
ie = new hx.InlineEditable(container.node())
spy = chai.spy()
ie.on 'change', spy
input = container.select('.hx-name')
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.value('bob')
testHelpers.fakeNodeEvent(input.node(), 'keydown')({ key: 'Enter' })
spy.should.have.been.called.with({
cause: 'user',
value: 'bob'
})

it 'should support deprecated event values', ->
container = fixture.append('div')
ie = new hx.InlineEditable(container.node())
spy = chai.spy()
ie.on 'change', spy
input = container.select('.hx-name')
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.value('bob')
testHelpers.fakeNodeEvent(input.node(), 'keydown')({ keyCode: 13 })
spy.should.have.been.called.with({
cause: 'user',
value: 'bob'
})
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.value('steve')
testHelpers.fakeNodeEvent(input.node(), 'keydown')({ which: 13 })
spy.should.have.been.called.with({
cause: 'user',
value: 'steve'
})

it 'should allow the user to enter text', ->
container = fixture.append('div')
ie = new hx.InlineEditable(container.node())
spy = chai.spy()
ie.on 'change', spy
input = container.select('.hx-name')
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.value('bob')
testHelpers.fakeNodeEvent(input.node(), 'keydown')({})
spy.should.not.have.been.called()

it 'should show the enterValueText when the value is cleared', ->
container = fixture.append('div').text('test')
ie = new hx.InlineEditable(container.node(), {
enterValueText: 'Bob'
})
input = container.select('.hx-name')
testHelpers.fakeNodeEvent(container.select('.hx-morph-toggle').node())()
input.value('')
testHelpers.fakeNodeEvent(container.select('.hx-confirm').node())()
container.text().should.equal('Bob')

describe 'fluid', ->
it 'should return a selection', ->
(hx.inlineEditable() instanceof hx.Selection).should.equal(true)

it 'should use the value option', ->
ie = hx.inlineEditable({
value: 'Bob'
})
ie.api().value().should.equal('Bob')

it 'should use the enterValueText option', ->
ie = hx.inlineEditable({
value: 'Bob'
})
ie.api().value().should.equal('Bob')
2 changes: 1 addition & 1 deletion modules/morph-section/main/index.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class InlineMorphSection extends MorphSection
morphSection.detector = undefined
morphSection.hide()
@on 'hide', 'hx.morph-section', (data) ->
exitEditMode.call(morphSection, data.toggle, data.content)
exitEditMode?.call(morphSection, data.toggle, data.content)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you don't have to pass it through as an empty function if you don't have an exit edit mode function

hx.select(data.toggle).style('display', '')


Expand Down