diff --git a/skins/base/views/atoms/EditableText.js b/skins/base/views/atoms/EditableText.js new file mode 100644 index 0000000000..a8f55814e7 --- /dev/null +++ b/skins/base/views/atoms/EditableText.js @@ -0,0 +1,68 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +var EditableTextController = require("../../../../src/controllers/atoms/EditableText"); + +module.exports = React.createClass({ + displayName: 'EditableText', + mixins: [EditableTextController], + + onKeyUp: function(ev) { + if (ev.key == "Enter") { + this.onFinish(ev); + } else if (ev.key == "Escape") { + this.cancelEdit(); + } + }, + + onClickDiv: function() { + this.setState({ + phase: this.Phases.Edit, + }) + }, + + onFocus: function(ev) { + ev.target.setSelectionRange(0, ev.target.value.length); + }, + + onFinish: function(ev) { + this.setValue(ev.target.value); + }, + + render: function() { + var editable_el; + + if (this.state.phase == this.Phases.Display) { + editable_el =
{this.state.value}
; + } else if (this.state.phase == this.Phases.Edit) { + editable_el = ( +
+ +
+ ); + } + + return ( +
+ {editable_el} +
+ ); + } +}); diff --git a/skins/base/views/atoms/create_room/CreateRoomButton.js b/skins/base/views/atoms/create_room/CreateRoomButton.js new file mode 100644 index 0000000000..2f9ccae030 --- /dev/null +++ b/skins/base/views/atoms/create_room/CreateRoomButton.js @@ -0,0 +1,32 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +var CreateRoomButtonController = require("../../../../../src/controllers/atoms/create_room/CreateRoomButton"); + +module.exports = React.createClass({ + displayName: 'CreateRoomButton', + mixins: [CreateRoomButtonController], + + render: function() { + return ( + + ); + } +}); diff --git a/skins/base/views/atoms/create_room/Presets.js b/skins/base/views/atoms/create_room/Presets.js new file mode 100644 index 0000000000..83fe61bdbb --- /dev/null +++ b/skins/base/views/atoms/create_room/Presets.js @@ -0,0 +1,39 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +var PresetsController = require("../../../../../src/controllers/atoms/create_room/Presets"); + +module.exports = React.createClass({ + displayName: 'CreateRoomPresets', + mixins: [PresetsController], + + onValueChanged: function(ev) { + this.setState({preset: ev.target.value}) + }, + + render: function() { + return ( + + ); + } +}); diff --git a/skins/base/views/atoms/create_room/RoomNameTextbox.js b/skins/base/views/atoms/create_room/RoomNameTextbox.js new file mode 100644 index 0000000000..c358a14cb3 --- /dev/null +++ b/skins/base/views/atoms/create_room/RoomNameTextbox.js @@ -0,0 +1,36 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +var RoomNameTextboxController = require("../../../../../src/controllers/atoms/create_room/RoomNameTextbox"); + +module.exports = React.createClass({ + displayName: 'RoomNameTextbox', + mixins: [RoomNameTextboxController], + + onValueChanged: function(ev) { + this.setState({room_name: ev.target.value}) + }, + + render: function() { + return ( + + ); + } +}); diff --git a/skins/base/views/molecules/UserSelector.js b/skins/base/views/molecules/UserSelector.js new file mode 100644 index 0000000000..7517e29d0f --- /dev/null +++ b/skins/base/views/molecules/UserSelector.js @@ -0,0 +1,44 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +var UserSelectorController = require("../../../../src/controllers/molecules/UserSelector"); + +module.exports = React.createClass({ + displayName: 'UserSelector', + mixins: [UserSelectorController], + + onAddUserId: function() { + this.addUser(this.refs.user_id_input.getDOMNode().value); + }, + + render: function() { + return ( +
+ + + +
+ ); + } +}); diff --git a/skins/base/views/organisms/CreateRoom.js b/skins/base/views/organisms/CreateRoom.js new file mode 100644 index 0000000000..36f6e466e5 --- /dev/null +++ b/skins/base/views/organisms/CreateRoom.js @@ -0,0 +1,73 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +var CreateRoomController = require("../../../../src/controllers/organisms/CreateRoom"); + +var ComponentBroker = require('../../../../src/ComponentBroker'); + +var CreateRoomButton = ComponentBroker.get("atoms/create_room/CreateRoomButton"); +var RoomNameTextbox = ComponentBroker.get("atoms/create_room/RoomNameTextbox"); +var Presets = ComponentBroker.get("atoms/create_room/Presets"); +var UserSelector = ComponentBroker.get("molecules/UserSelector"); + + +module.exports = React.createClass({ + displayName: 'CreateRoom', + mixins: [CreateRoomController], + + getPreset: function() { + return this.refs.presets.getPreset(); + }, + + getName: function() { + return this.refs.name_textbox.getName(); + }, + + getInvitedUsers: function() { + return this.refs.user_selector.getUserIds(); + }, + + render: function() { + var curr_phase = this.state.phase; + if (curr_phase == this.phases.CREATING) { + return ( +
Creating...
+ ); + } else { + var error_box = ""; + if (curr_phase == this.phases.ERROR) { + error_box = ( +
+ An error occured: {this.state.error_string} +
+ ); + } + return ( +
+ + + + + {error_box} +
+ ); + } + } +}); diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js index ec0f00b6ff..9bb54fa612 100644 --- a/src/ComponentBroker.js +++ b/src/ComponentBroker.js @@ -62,6 +62,10 @@ require('../skins/base/views/atoms/LogoutButton'); require('../skins/base/views/atoms/EnableNotificationsButton'); require('../skins/base/views/atoms/MessageTimestamp'); require('../skins/base/views/atoms/VideoFeed'); +require('../skins/base/views/atoms/create_room/CreateRoomButton'); +require('../skins/base/views/atoms/create_room/RoomNameTextbox'); +require('../skins/base/views/atoms/create_room/Presets'); +require('../skins/base/views/atoms/EditableText'); require('../skins/base/views/molecules/MatrixToolbar'); require('../skins/base/views/molecules/RoomTile'); require('../skins/base/views/molecules/MessageTile'); @@ -83,6 +87,8 @@ require('../skins/base/views/organisms/RoomList'); require('../skins/base/views/organisms/RoomView'); require('../skins/base/views/templates/Login'); require('../skins/base/views/organisms/Notifier'); +require('../skins/base/views/organisms/CreateRoom'); +require('../skins/base/views/molecules/UserSelector'); // new for vector require('../skins/base/views/organisms/LeftPanel'); require('../skins/base/views/organisms/RightPanel'); diff --git a/src/controllers/atoms/EditableText.js b/src/controllers/atoms/EditableText.js new file mode 100644 index 0000000000..ac46973613 --- /dev/null +++ b/src/controllers/atoms/EditableText.js @@ -0,0 +1,68 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +module.exports = { + propTypes: { + onValueChanged: React.PropTypes.func, + initalValue: React.PropTypes.string, + }, + + Phases: { + Display: "display", + Edit: "edit", + }, + + getDefaultProps: function() { + return { + onValueChanged: function() {}, + initalValue: '', + }; + }, + + getInitialState: function() { + return { + value: this.props.initalValue, + phase: this.Phases.Display, + } + }, + + getValue: function() { + return this.state.value; + }, + + setValue: function(val) { + this.setState({ + value: val, + phase: this.Phases.Display, + }); + + this.onValueChanged(); + }, + + cancelEdit: function() { + this.setState({ + phase: this.Phases.Display, + }); + }, + + onValueChanged: function() { + this.props.onValueChanged(this.state.value); + }, +}; diff --git a/src/controllers/atoms/create_room/CreateRoomButton.js b/src/controllers/atoms/create_room/CreateRoomButton.js new file mode 100644 index 0000000000..f03dd56c97 --- /dev/null +++ b/src/controllers/atoms/create_room/CreateRoomButton.js @@ -0,0 +1,35 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +module.exports = { + propTypes: { + onCreateRoom: React.PropTypes.func, + }, + + getDefaultProps: function() { + return { + onCreateRoom: function() {}, + }; + }, + + onClick: function() { + this.props.onCreateRoom(); + }, +}; diff --git a/src/controllers/atoms/create_room/Presets.js b/src/controllers/atoms/create_room/Presets.js new file mode 100644 index 0000000000..5ff7327e5a --- /dev/null +++ b/src/controllers/atoms/create_room/Presets.js @@ -0,0 +1,41 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +module.exports = { + propTypes: { + default_preset: React.PropTypes.string + }, + + getDefaultProps: function() { + return { + default_preset: 'private_chat', + }; + }, + + getInitialState: function() { + return { + preset: this.props.default_preset, + } + }, + + getPreset: function() { + return this.state.preset; + }, +}; diff --git a/src/controllers/atoms/create_room/RoomNameTextbox.js b/src/controllers/atoms/create_room/RoomNameTextbox.js new file mode 100644 index 0000000000..e78692d992 --- /dev/null +++ b/src/controllers/atoms/create_room/RoomNameTextbox.js @@ -0,0 +1,41 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +module.exports = { + propTypes: { + default_name: React.PropTypes.string + }, + + getDefaultProps: function() { + return { + default_name: '', + }; + }, + + getInitialState: function() { + return { + room_name: this.props.default_name, + } + }, + + getName: function() { + return this.state.room_name; + }, +}; diff --git a/src/controllers/molecules/UserSelector.js b/src/controllers/molecules/UserSelector.js new file mode 100644 index 0000000000..e7e0509690 --- /dev/null +++ b/src/controllers/molecules/UserSelector.js @@ -0,0 +1,57 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +module.exports = { + propTypes: { + initially_selected: React.PropTypes.arrayOf(React.PropTypes.string), + }, + + getDefaultProps: function() { + return { + initially_selected: [], + }; + }, + + getInitialState: function() { + return { + selected_users: this.props.initially_selected, + } + }, + + addUser: function(user_id) { + if (this.state.selected_users.indexOf(user_id == -1)) { + this.setState({ + selected_users: this.state.selected_users.concat([user_id]), + }); + } + }, + + removeUser: function(user_id) { + this.setState({ + selected_users: this.state.selected_users.filter(function(e) { + return e != user_id; + }), + }); + }, + + getUserIds: function() { + return this.state.selected_users; + } +}; diff --git a/src/controllers/organisms/CreateRoom.js b/src/controllers/organisms/CreateRoom.js new file mode 100644 index 0000000000..c2112ce58f --- /dev/null +++ b/src/controllers/organisms/CreateRoom.js @@ -0,0 +1,92 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require("react"); +var MatrixClientPeg = require("../../MatrixClientPeg"); + +module.exports = { + propTypes: { + onRoomCreated: React.PropTypes.func, + }, + + phases: { + CONFIG: "CONFIG", // We're waiting for user to configure and hit create. + CREATING: "CREATING", // We're sending the request. + CREATED: "CREATED", // We successfully created the room. + ERROR: "ERROR", // There was an error while trying to create room. + }, + + getDefaultProps: function() { + return { + onRoomCreated: function() {}, + }; + }, + + getInitialState: function() { + return { + phase: this.phases.CONFIG, + error_string: "", + }; + }, + + onCreateRoom: function() { + var options = {}; + + var room_name = this.getName(); + if (room_name) { + options.name = room_name; + } + + var preset = this.getPreset(); + if (preset) { + options.preset = preset; + } + + var invited_users = this.getInvitedUsers(); + if (invited_users) { + options.invite = invited_users; + } + + var cli = MatrixClientPeg.get(); + if (!cli) { + // TODO: Error. + console.error("Cannot create room: No matrix client."); + return; + } + + var deferred = MatrixClientPeg.get().createRoom(options); + + this.setState({ + phase: this.phases.CREATING, + }); + + var self = this; + + deferred.then(function () { + self.setState({ + phase: self.phases.CREATED, + }); + self.props.onRoomCreated(); + }, function(err) { + self.setState({ + phase: self.phases.ERROR, + error_string: err.toString(), + }); + }); + } +};