diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 08dfe75584..bc1758c26f 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -767,7 +767,7 @@ module.exports = React.createClass({ var deferreds = []; - if (old_name != new_name && new_name != undefined && new_name) { + if (old_name != new_name && new_name != undefined) { deferreds.push( MatrixClientPeg.get().setRoomName(this.state.room.roomId, new_name) ); @@ -900,7 +900,7 @@ module.exports = React.createClass({ }); var new_name = this.refs.header.getRoomName(); - var new_topic = this.refs.room_settings.getTopic(); + var new_topic = this.refs.header.getTopic(); var new_join_rule = this.refs.room_settings.getJoinRules(); var new_history_visibility = this.refs.room_settings.getHistoryVisibility(); var new_power_levels = this.refs.room_settings.getPowerLevels(); diff --git a/src/components/views/elements/EditableText.js b/src/components/views/elements/EditableText.js index beedfc35c8..5d509a7831 100644 --- a/src/components/views/elements/EditableText.js +++ b/src/components/views/elements/EditableText.js @@ -18,13 +18,21 @@ limitations under the License. var React = require('react'); +const KEY_TAB = 9; +const KEY_SHIFT = 16; +const KEY_WINDOWS = 91; + module.exports = React.createClass({ displayName: 'EditableText', propTypes: { onValueChanged: React.PropTypes.func, initialValue: React.PropTypes.string, label: React.PropTypes.string, - placeHolder: React.PropTypes.string, + placeholder: React.PropTypes.string, + className: React.PropTypes.string, + labelClassName: React.PropTypes.string, + placeholderClassName: React.PropTypes.string, + blurToCancel: React.PropTypes.bool, }, Phases: { @@ -32,42 +40,51 @@ module.exports = React.createClass({ Edit: "edit", }, + value: '', + placeholder: false, + getDefaultProps: function() { return { onValueChanged: function() {}, initialValue: '', - label: 'Click to set', + label: '', placeholder: '', }; }, getInitialState: function() { return { - value: this.props.initialValue, phase: this.Phases.Display, } }, componentWillReceiveProps: function(nextProps) { - this.setState({ - value: nextProps.initialValue - }); + this.value = nextProps.initialValue; + }, + + componentDidMount: function() { + this.value = this.props.initialValue; + if (this.refs.editable_div) { + this.showPlaceholder(!this.value); + } + }, + + showPlaceholder: function(show) { + if (show) { + this.refs.editable_div.textContent = this.props.placeholder; + this.refs.editable_div.setAttribute("class", this.props.className + " " + this.props.placeholderClassName); + this.placeholder = true; + this.value = ''; + } + else { + this.refs.editable_div.textContent = this.value; + this.refs.editable_div.setAttribute("class", this.props.className); + this.placeholder = false; + } }, getValue: function() { - return this.state.value; - }, - - setValue: function(val, shouldSubmit, suppressListener) { - var self = this; - this.setState({ - value: val, - phase: this.Phases.Display, - }, function() { - if (!suppressListener) { - self.onValueChanged(shouldSubmit); - } - }); + return this.value; }, edit: function() { @@ -84,61 +101,83 @@ module.exports = React.createClass({ }, onValueChanged: function(shouldSubmit) { - this.props.onValueChanged(this.state.value, shouldSubmit); + this.props.onValueChanged(this.value, shouldSubmit); + }, + + onKeyDown: function(ev) { + // console.log("keyDown: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder); + + if (this.placeholder) { + if (ev.keyCode !== KEY_SHIFT && !ev.metaKey && !ev.ctrlKey && !ev.altKey && ev.keyCode !== KEY_WINDOWS && ev.keyCode !== KEY_TAB) { + this.showPlaceholder(false); + } + } + + if (ev.key == "Enter") { + ev.stopPropagation(); + ev.preventDefault(); + } + + // console.log("keyDown: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder); }, onKeyUp: function(ev) { + // console.log("keyUp: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder); + + if (!ev.target.textContent) { + this.showPlaceholder(true); + } + else if (!this.placeholder) { + this.value = ev.target.textContent; + } + if (ev.key == "Enter") { this.onFinish(ev); } else if (ev.key == "Escape") { this.cancelEdit(); } + + // console.log("keyUp: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder); }, - onClickDiv: function() { + onClickDiv: function(ev) { this.setState({ phase: this.Phases.Edit, }) }, onFocus: function(ev) { - ev.target.setSelectionRange(0, ev.target.value.length); + //ev.target.setSelectionRange(0, ev.target.textContent.length); }, onFinish: function(ev) { - if (ev.target.value) { - this.setValue(ev.target.value, ev.key === "Enter"); - } else { - this.cancelEdit(); - } + var self = this; + this.setState({ + phase: this.Phases.Display, + }, function() { + self.onValueChanged(ev.key === "Enter"); + }); }, - onBlur: function() { - this.cancelEdit(); + onBlur: function(ev) { + if (this.props.blurToCancel) + this.cancelEdit(); + else + this.onFinish(ev) }, render: function() { var editable_el; - if (this.state.phase == this.Phases.Display) { - if (this.state.value) { - editable_el =
{this.state.value}
; - } else { - editable_el =
{this.props.label}
; - } - } else if (this.state.phase == this.Phases.Edit) { - editable_el = ( -
- -
- ); + if (this.state.phase == this.Phases.Display && (this.props.label || this.props.labelClassName) && !this.value) { + // show the label + editable_el =
{this.props.label}
; + } else { + // show the content editable div, but manually manage its contents as react and contentEditable don't play nice together + editable_el =
; } - return ( -
- {editable_el} -
- ); + return editable_el; } }); diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index cdfbc0bfc8..072397526b 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -41,6 +41,17 @@ module.exports = React.createClass({ }; }, + componentWillReceiveProps: function(newProps) { + if (newProps.editing) { + var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); + + this.setState({ + name: this.props.room.name, + topic: topic ? topic.getContent().topic : '', + }); + } + }, + onVideoClick: function(e) { dis.dispatch({ action: 'place_call', @@ -57,14 +68,20 @@ module.exports = React.createClass({ }); }, - onNameChange: function(new_name) { - if (this.props.room.name != new_name && new_name) { - MatrixClientPeg.get().setRoomName(this.props.room.roomId, new_name); - } + onNameChanged: function(value) { + this.setState({ name : value }); + }, + + onTopicChanged: function(value) { + this.setState({ topic : value }); }, getRoomName: function() { - return this.refs.name_edit.value; + return this.state.name; + }, + + getTopic: function() { + return this.state.topic; }, render: function() { @@ -76,7 +93,7 @@ module.exports = React.createClass({ if (this.props.simpleHeader) { var cancel; if (this.props.onCancelClick) { - cancel = Close + cancel = Close } header =
@@ -87,27 +104,45 @@ module.exports = React.createClass({
} else { - var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); - var name = null; var searchStatus = null; var topic_el = null; var cancel_button = null; var save_button = null; var settings_button = null; - var actual_name = this.props.room.currentState.getStateEvents('m.room.name', ''); - if (actual_name) actual_name = actual_name.getContent().name; + // var actual_name = this.props.room.currentState.getStateEvents('m.room.name', ''); + // if (actual_name) actual_name = actual_name.getContent().name; if (this.props.editing) { - name = -
- -
+ // name = + //
+ // + //
// if (topic) topic_el =
- cancel_button =
Cancel
- save_button =
Save Changes
+ + name = +
+ +
+ + topic_el = + + + save_button =
Save
+ cancel_button =
Cancel
} else { // - var searchStatus; // don't display the search count until the search completes and // gives us a valid (possibly zero) searchCount. @@ -123,7 +158,9 @@ module.exports = React.createClass({ - if (topic) topic_el =
{ topic.getContent().topic }
; + + var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); + if (topic) topic_el =
{ topic.getContent().topic }
; } var roomAvatar = null; @@ -149,6 +186,18 @@ module.exports = React.createClass({ ; } + var right_row; + if (!this.props.editing) { + right_row = +
+ { forget_button } + { leave_button } +
+ +
+
; + } + header =
@@ -160,15 +209,9 @@ module.exports = React.createClass({ { topic_el }
- {cancel_button} {save_button} -
- { forget_button } - { leave_button } -
- -
-
+ {cancel_button} + {right_row} } diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 0864dc15c7..c601858757 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -136,9 +136,6 @@ module.exports = React.createClass({ render: function() { var ChangeAvatar = sdk.getComponent('settings.ChangeAvatar'); - var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); - if (topic) topic = topic.getContent().topic; - var join_rule = this.props.room.currentState.getStateEvents('m.room.join_rules', ''); if (join_rule) join_rule = join_rule.getContent().join_rule; @@ -216,7 +213,7 @@ module.exports = React.createClass({ ./ } - var boundClick = self.onColorSchemeChanged.bind(this, i) + var boundClick = self.onColorSchemeChanged.bind(self, i) return (
-