aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js/components/ValueEditor
diff options
context:
space:
mode:
Diffstat (limited to 'web/src/js/components/ValueEditor')
-rwxr-xr-xweb/src/js/components/ValueEditor/ValidateEditor.jsx44
-rw-r--r--[-rwxr-xr-x]web/src/js/components/ValueEditor/ValueEditor.jsx (renamed from web/src/js/components/ValueEditor/EditorBase.jsx)89
2 files changed, 68 insertions, 65 deletions
diff --git a/web/src/js/components/ValueEditor/ValidateEditor.jsx b/web/src/js/components/ValueEditor/ValidateEditor.jsx
index 2f362986..7415c1b8 100755
--- a/web/src/js/components/ValueEditor/ValidateEditor.jsx
+++ b/web/src/js/components/ValueEditor/ValidateEditor.jsx
@@ -1,57 +1,57 @@
import React, { Component, PropTypes } from 'react'
-import ReactDOM from 'react-dom'
-import EditorBase from './EditorBase'
+import ValueEditor from './ValueEditor'
+import classnames from 'classnames'
+
export default class ValidateEditor extends Component {
static propTypes = {
content: PropTypes.string.isRequired,
+ readonly: PropTypes.bool,
onDone: PropTypes.func.isRequired,
- onInput: PropTypes.func,
- isValid: PropTypes.func,
className: PropTypes.string,
+ isValid: PropTypes.func.isRequired,
}
constructor(props) {
super(props)
- this.state = { currentContent: props.content }
+ this.state = { valid: props.isValid(props.content) }
this.onInput = this.onInput.bind(this)
this.onDone = this.onDone.bind(this)
}
componentWillReceiveProps(nextProps) {
- this.setState({ currentContent: nextProps.content })
+ this.setState({ valid: nextProps.isValid(nextProps.content) })
}
- onInput(currentContent) {
- this.setState({ currentContent })
- this.props.onInput && this.props.onInput(currentContent)
+ onInput(content) {
+ this.setState({ valid: this.props.isValid(content) })
}
onDone(content) {
- if (this.props.isValid && !this.props.isValid(content)) {
- this.refs.editor.reset()
+ if (!this.props.isValid(content)) {
+ this.editor.reset()
content = this.props.content
}
this.props.onDone(content)
}
render() {
- let className = this.props.className || ''
- if (this.props.isValid) {
- if (this.props.isValid(this.state.currentContent)) {
- className += ' has-success'
- } else {
- className += ' has-warning'
+ let className = classnames(
+ this.props.className,
+ {
+ 'has-success': this.state.valid,
+ 'has-warning': !this.state.valid
}
- }
+ )
return (
- <EditorBase
- {...this.props}
- ref="editor"
- className={className}
+ <ValueEditor
+ content={this.props.content}
+ readonly={this.props.readonly}
onDone={this.onDone}
onInput={this.onInput}
+ className={className}
+ ref={(e) => this.editor = e}
/>
)
}
diff --git a/web/src/js/components/ValueEditor/EditorBase.jsx b/web/src/js/components/ValueEditor/ValueEditor.jsx
index aa09dad5..dd9c2cde 100755..100644
--- a/web/src/js/components/ValueEditor/EditorBase.jsx
+++ b/web/src/js/components/ValueEditor/ValueEditor.jsx
@@ -1,61 +1,66 @@
import React, { Component, PropTypes } from 'react'
-import ReactDOM from 'react-dom'
-import {Key} from '../../utils.js'
+import _ from "lodash"
+import classnames from 'classnames'
-export default class EditorBase extends Component {
+import { Key } from '../../utils'
+
+export default class ValueEditor extends Component {
static propTypes = {
content: PropTypes.string.isRequired,
+ readonly: PropTypes.bool,
onDone: PropTypes.func.isRequired,
- contentToHtml: PropTypes.func,
- nodeToContent: PropTypes.func,
- onStop: PropTypes.func,
- submitOnEnter: PropTypes.bool,
className: PropTypes.string,
- tag: PropTypes.string,
+ onInput: PropTypes.func,
+ onKeyDown: PropTypes.func,
}
static defaultProps = {
- contentToHtml: content => _.escape(content),
- nodeToContent: node => node.textContent,
- submitOnEnter: true,
- className: '',
- tag: 'div',
- onStop: _.noop,
- onMouseDown: _.noop,
- onBlur: _.noop,
- onInput: _.noop,
+ onInput: () => {},
+ onKeyDown: () => {},
}
constructor(props) {
super(props)
- this.state = {editable: false}
+ this.state = { editable: false }
this.onPaste = this.onPaste.bind(this)
this.onMouseDown = this.onMouseDown.bind(this)
this.onMouseUp = this.onMouseUp.bind(this)
this.onFocus = this.onFocus.bind(this)
this.onClick = this.onClick.bind(this)
- this.stop = this.stop.bind(this)
+ this.blur = this.blur.bind(this)
this.onBlur = this.onBlur.bind(this)
this.reset = this.reset.bind(this)
this.onKeyDown = this.onKeyDown.bind(this)
this.onInput = this.onInput.bind(this)
}
- stop() {
+ blur() {
// a stop would cause a blur as a side-effect.
// but a blur event must trigger a stop as well.
// to fix this, make stop = blur and do the actual stop in the onBlur handler.
- ReactDOM.findDOMNode(this).blur()
- this.props.onStop()
+ this.input.blur()
+ }
+
+ reset() {
+ this.input.innerHTML = _.escape(this.props.content)
}
render() {
+ let className = classnames(
+ 'inline-input',
+ {
+ 'readonly': this.props.readonly,
+ 'editable': !this.props.readonly
+ },
+ this.props.className
+ )
return (
- <this.props.tag
- tabIndex="0"
- className={`inline-input ${this.props.className}`}
+ <div
+ ref={input => this.input = input}
+ tabIndex={!this.props.readonly && "0"}
+ className={className}
contentEditable={this.state.editable || undefined}
onFocus={this.onFocus}
onMouseDown={this.onMouseDown}
@@ -64,8 +69,8 @@ export default class EditorBase extends Component {
onKeyDown={this.onKeyDown}
onInput={this.onInput}
onPaste={this.onPaste}
- dangerouslySetInnerHTML={{ __html: this.props.contentToHtml(this.props.content) }}
- />
+ dangerouslySetInnerHTML={{ __html: _.escape(this.props.content) }}
+ ></div>
)
}
@@ -78,7 +83,6 @@ export default class EditorBase extends Component {
onMouseDown(e) {
this._mouseDown = true
window.addEventListener('mouseup', this.onMouseUp)
- this.props.onMouseDown(e)
}
onMouseUp() {
@@ -94,7 +98,7 @@ export default class EditorBase extends Component {
}
onFocus(e) {
- if (this._mouseDown || this._ignore_events || this.state.editable) {
+ if (this._mouseDown || this._ignore_events || this.state.editable || this.props.readonly) {
return
}
@@ -114,31 +118,29 @@ export default class EditorBase extends Component {
range = document.caretRangeFromPoint(e.clientX, e.clientY)
} else {
range = document.createRange()
- range.selectNodeContents(ReactDOM.findDOMNode(this))
+ range.selectNodeContents(this.input)
}
this._ignore_events = true
this.setState({ editable: true }, () => {
- const node = ReactDOM.findDOMNode(this)
- node.blur()
- node.focus()
+ this.input.blur()
+ this.input.focus()
this._ignore_events = false
+ range.selectNodeContents(this.input)
+ sel.removeAllRanges();
+ sel.addRange(range);
})
}
onBlur(e) {
- if (this._ignore_events) {
+ if (this._ignore_events || this.props.readonly) {
return
}
window.getSelection().removeAllRanges() //make sure that selection is cleared on blur
this.setState({ editable: false })
- this.props.onDone(this.props.nodeToContent(ReactDOM.findDOMNode(this)))
- this.props.onBlur(e)
+ this.props.onDone(this.input.textContent)
}
- reset() {
- ReactDOM.findDOMNode(this).innerHTML = this.props.contentToHtml(this.props.content)
- }
onKeyDown(e) {
e.stopPropagation()
@@ -146,20 +148,21 @@ export default class EditorBase extends Component {
case Key.ESC:
e.preventDefault()
this.reset()
- this.stop()
+ this.blur()
break
case Key.ENTER:
- if (this.props.submitOnEnter && !e.shiftKey) {
+ if (!e.shiftKey) {
e.preventDefault()
- this.stop()
+ this.blur()
}
break
default:
break
}
+ this.props.onKeyDown(e)
}
onInput() {
- this.props.onInput(this.props.nodeToContent(ReactDOM.findDOMNode(this)))
+ this.props.onInput(this.input.textContent)
}
}