diff --git a/README.adoc b/README.adoc index 584973a..2c569cf 100644 --- a/README.adoc +++ b/README.adoc @@ -95,6 +95,9 @@ keep the cursor visible. * Cut/copy/paste of clipboard data, including conversion between rich text and HTML. +* Focus/blur support with appropriate styling for cursors (invisible) and +selections (gray). + * Cursor user identification via color and tag (TODO). * Figures and tables (TODO). diff --git a/src/components/Editor.js b/src/components/Editor.js index d73602a..4ef21c1 100644 --- a/src/components/Editor.js +++ b/src/components/Editor.js @@ -17,7 +17,8 @@ export default React.createClass({ minFontSize: T.number.isRequired, unitsPerEm: T.number.isRequired, width: T.number.isRequired, - margin: T.number.isRequired + margin: T.number.isRequired, + initialFocus: T.bool }, //mixins: [React.addons.PureRenderMixin], diff --git a/src/components/EditorContents.js b/src/components/EditorContents.js index 2cc185a..ee61d0f 100644 --- a/src/components/EditorContents.js +++ b/src/components/EditorContents.js @@ -34,11 +34,18 @@ export default React.createClass({ minFontSize: T.number.isRequired, unitsPerEm: T.number.isRequired, width: T.number.isRequired, - margin: T.number.isRequired + margin: T.number.isRequired, + initialFocus: T.bool }, mixins: [TextReplicaMixin], + getDefaultProps() { + return { + initialFocus: true + } + }, + getInitialState() { return EditorStore.getState() }, @@ -58,7 +65,6 @@ export default React.createClass({ componentDidMount() { this.clickCount = 0 EditorStore.listen(this.onStateChange) - this.refs.input.focus() }, componentDidUpdate() { @@ -115,7 +121,7 @@ export default React.createClass({ }, _doOnSingleClick(e) { - this.refs.input.focus() + EditorActions.focusInput() let coordinates = this._mouseEventToCoordinates(e) if(!coordinates) { @@ -169,12 +175,18 @@ export default React.createClass({ // DEBUGGING --------------------------------------------------------------------------------------------------------- + _dumpState() { + console.debug('Current state contents (NOTE: state.focus always false due to debug button click):') + console.dir(this.state) + EditorActions.focusInput() + }, + _dumpReplica() { let text = this.replica.getTextRange(BASE_CHAR) console.debug('Current replica text: [' + text.map(c => c.char).join('') + ']') console.debug('Current replica contents:') console.dir(text) - this.refs.input.focus() + EditorActions.focusInput() }, _dumpPosition() { @@ -183,7 +195,7 @@ export default React.createClass({ } else { console.debug('No active position') } - this.refs.input.focus() + EditorActions.focusInput() }, _dumpCurrentLine() { @@ -214,7 +226,7 @@ export default React.createClass({ console.debug('No lines') } }) - this.refs.input.focus() + EditorActions.focusInput() }, _dumpLines() { @@ -223,7 +235,7 @@ export default React.createClass({ } else { console.debug('No lines') } - this.refs.input.focus() + EditorActions.focusInput() }, _dumpSelection() { @@ -237,17 +249,17 @@ export default React.createClass({ } else { console.debug('No active selection') } - this.refs.input.focus() + EditorActions.focusInput() }, _forceFlow() { EditorActions.replicaUpdated() - this.refs.input.focus() + EditorActions.focusInput() }, _forceRender() { this.forceUpdate(() => console.debug('Render done.')) - this.refs.input.focus() + EditorActions.focusInput() }, _togglePositionEolStart() { @@ -257,7 +269,7 @@ export default React.createClass({ console.debug('Toggling positionEolStart from ' + previous + ' to ' + !previous) return { positionEolStart: !previous } }) - this.refs.input.focus() + EditorActions.focusInput() }, // RENDERING --------------------------------------------------------------------------------------------------------- @@ -283,9 +295,24 @@ export default React.createClass({ let selectionDiv = (leftX, widthX) => { let height = Math.round(lineHeight * 10) / 10 + let selectionStyle = { + top: 0, + left: leftX, + width: widthX, + height: height + } + + if(!this.state.focus) { + selectionStyle.borderTopColor = 'rgb(0, 0, 0)' + selectionStyle.borderBottomColor = 'rgb(0, 0, 0)' + selectionStyle.backgroundColor = 'rgb(0, 0, 0)' + selectionStyle.opacity = 0.15 + selectionStyle.color = 'black' + } + return (
+ style={selectionStyle}> ) } @@ -457,7 +484,7 @@ export default React.createClass({ let position = cursorPosition ? cursorPosition.top : 0 return ( - + ) }, @@ -484,7 +511,7 @@ export default React.createClass({ top: cursorPosition.top } - if (this.state.selectionActive) { + if (this.state.selectionActive || !this.state.focus) { cursorStyle.opacity = 0 cursorStyle.visibility = 'hidden' } else { @@ -528,6 +555,7 @@ export default React.createClass({ {/*
Dump:  +         diff --git a/src/components/TextInput.js b/src/components/TextInput.js index ca0e14a..1468d2a 100644 --- a/src/components/TextInput.js +++ b/src/components/TextInput.js @@ -40,7 +40,8 @@ const ALL_CHARS = [ export default React.createClass({ propTypes: { id: T.number.isRequired, - position: T.number.isRequired + position: T.number.isRequired, + focused: T.bool.isRequired }, mixins: [React.addons.PureRenderMixin], @@ -86,11 +87,15 @@ export default React.createClass({ keyBindings.bind('alt+shift+5', this._handleKeyStrikethrough) keyBindings.bind('ctrl+.', this._handleKeySuperscript) keyBindings.bind('ctrl+,', this._handleKeySubscript) + }, - // TODO figure out tab, enter, return, pageup, pagedown, end, home, ins + componentDidUpdate() { + if(this.props.focused) { + this._focus() + } }, - focus() { + _focus() { this._checkEmptyValue() this.input.focus() @@ -291,6 +296,10 @@ export default React.createClass({ return false }, + _onInputFocusLost() { + EditorActions.inputFocusLost() + }, + _onCopy(e) { let selectionChunks = EditorActions.getSelection() @@ -327,7 +336,7 @@ export default React.createClass({ this._selectNodeContents(this.ieClipboardDiv) setTimeout(() => { emptyNode(this.ieClipboardDiv) - this.focus() + this._focus() }, 0) }, @@ -376,7 +385,7 @@ export default React.createClass({ EditorActions.insertCharsBatch(pastedChunks) } finally { emptyNode(this.ieClipboardDiv) - this.focus() + this._focus() } }, 0) }, @@ -406,7 +415,7 @@ export default React.createClass({ return (