From e7d4ef74d0f46a765eb4a52c6e83740a29237f1d Mon Sep 17 00:00:00 2001 From: wmwragg Date: Thu, 1 Sep 2016 16:45:24 +0100 Subject: [PATCH 01/48] Placeholder for one to one chat dialog and functionality --- src/components/structures/MatrixChat.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 84575b9e4f..d4b3df93bd 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -357,6 +357,9 @@ module.exports = React.createClass({ this._setPage(this.PageTypes.RoomDirectory); this.notifyNewScreen('directory'); break; + case 'view_one_to_one_chat': + this._oneToOneChat(); + break; case 'notifier_enabled': this.forceUpdate(); break; @@ -493,6 +496,15 @@ module.exports = React.createClass({ } }, + _oneToOneChat: function() { + // TODO: Create a OneToOneChatChatDialog + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Unimplemented Feature", + description: "The OnToOneChatDialog is not yet implemented" + }); + }, + // update scrollStateMap according to the current scroll state of the // room view. _updateScrollMap: function() { From 4c05edb71be15923ebc45d3b971dd9306f2abd97 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Fri, 2 Sep 2016 15:47:40 +0100 Subject: [PATCH 02/48] Refactor of the RoomTooltip, so that it is easier to use, and also works with Safari --- src/components/views/rooms/RoomList.js | 9 ++++----- src/components/views/rooms/RoomTile.js | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 206bf8504e..98fcb92b06 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -77,6 +77,7 @@ module.exports = React.createClass({ switch (payload.action) { case 'view_tooltip': this.tooltip = payload.tooltip; + this.tooltipParent = payload.parent; this._repositionTooltip(); if (this.tooltip) this.tooltip.style.display = 'block'; break; @@ -275,11 +276,9 @@ module.exports = React.createClass({ }, _repositionTooltip: function(e) { - // We access the parent of the parent, as the tooltip is inside a container - // Needs refactoring into a better multipurpose tooltip - if (this.tooltip && this.tooltip.parentElement && this.tooltip.parentElement.parentElement) { - var scroll = ReactDOM.findDOMNode(this); - this.tooltip.style.top = (3 + scroll.parentElement.offsetTop + this.tooltip.parentElement.parentElement.offsetTop - this._getScrollNode().scrollTop) + "px"; + if (this.tooltip && this.tooltipParent) { + this.tooltip.style.top = this.tooltipParent.getBoundingClientRect().top + "px"; + this.tooltip.style.left = this.tooltipParent.getBoundingClientRect().right + "px"; } }, diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index b646b12e76..de0735f755 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -248,7 +248,7 @@ module.exports = React.createClass({ } else if (this.state.hover) { var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - label = ; + label = ; } var incomingCallBox; From bffefd92618a3f23815ede3865c56a07583026d5 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Fri, 2 Sep 2016 18:41:44 +0100 Subject: [PATCH 03/48] Tweak of the RoomTooltip to use DOM element for the parent rather than a React component --- src/components/views/rooms/RoomTile.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index de0735f755..7c6e3a3ad0 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -17,6 +17,7 @@ limitations under the License. 'use strict'; var React = require('react'); +var ReactDOM = require("react-dom"); var classNames = require('classnames'); var dis = require("../../../dispatcher"); var MatrixClientPeg = require('../../../MatrixClientPeg'); @@ -75,6 +76,10 @@ module.exports = React.createClass({ MatrixClientPeg.get().on("accountData", this.onAccountData); }, + componentDidMount: function() { + this.componentElement = ReactDOM.findDOMNode(this); + }, + componentWillUnmount: function() { var cli = MatrixClientPeg.get(); if (cli) { @@ -248,7 +253,7 @@ module.exports = React.createClass({ } else if (this.state.hover) { var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - label = ; + label = ; } var incomingCallBox; From 405dcf76eb49c7a9954eddecaaa7600833e02306 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Sat, 3 Sep 2016 12:44:55 +0100 Subject: [PATCH 04/48] Further tweaks to the tooltip to better handle its position, and simplify it's use --- src/components/views/rooms/RoomList.js | 13 +++++-------- src/components/views/rooms/RoomTile.js | 6 +----- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 98fcb92b06..084aac378c 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -77,9 +77,6 @@ module.exports = React.createClass({ switch (payload.action) { case 'view_tooltip': this.tooltip = payload.tooltip; - this.tooltipParent = payload.parent; - this._repositionTooltip(); - if (this.tooltip) this.tooltip.style.display = 'block'; break; case 'call_state': var call = CallHandler.getCall(payload.room_id); @@ -270,15 +267,15 @@ module.exports = React.createClass({ }, _whenScrolling: function(e) { - this._repositionTooltip(e); + this._hideTooltip(e); this._repositionIncomingCallBox(e, false); this._updateStickyHeaders(false); }, - _repositionTooltip: function(e) { - if (this.tooltip && this.tooltipParent) { - this.tooltip.style.top = this.tooltipParent.getBoundingClientRect().top + "px"; - this.tooltip.style.left = this.tooltipParent.getBoundingClientRect().right + "px"; + _hideTooltip: function(e) { + // Hide tooltip when scrolling, as we'll no longer be over the one we were on + if (this.tooltip && this.tooltip.style.display !== "none") { + this.tooltip.style.display = "none"; } }, diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 7c6e3a3ad0..d1eb76bf3b 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -76,10 +76,6 @@ module.exports = React.createClass({ MatrixClientPeg.get().on("accountData", this.onAccountData); }, - componentDidMount: function() { - this.componentElement = ReactDOM.findDOMNode(this); - }, - componentWillUnmount: function() { var cli = MatrixClientPeg.get(); if (cli) { @@ -253,7 +249,7 @@ module.exports = React.createClass({ } else if (this.state.hover) { var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - label = ; + label = ; } var incomingCallBox; From 03e74f48f89ced0927f6db9c14ecf435d22e0f02 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Sat, 3 Sep 2016 13:44:44 +0100 Subject: [PATCH 05/48] Positioned Tooltip better --- src/components/views/rooms/RoomTile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index d1eb76bf3b..792a14bb51 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -249,7 +249,7 @@ module.exports = React.createClass({ } else if (this.state.hover) { var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - label = ; + label = ; } var incomingCallBox; From 721baf8d42df77762ba8fb6972c530994f3e05c9 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Sun, 4 Sep 2016 07:42:09 +0100 Subject: [PATCH 06/48] Tolltip tweak to not require the passing in of the parent --- src/components/views/rooms/RoomTile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 792a14bb51..c6b13e9ad7 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -249,7 +249,7 @@ module.exports = React.createClass({ } else if (this.state.hover) { var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - label = ; + tooltip = ; } var incomingCallBox; From f9ab2fa95795edd77babe990e909a8da50276e20 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Sun, 4 Sep 2016 08:01:04 +0100 Subject: [PATCH 07/48] When zoomed in, the sticky headers should correctly position themselves --- src/components/views/rooms/RoomList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 084aac378c..91a32f51ac 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -324,7 +324,7 @@ module.exports = React.createClass({ var scrollArea = this._getScrollNode(); // Use the offset of the top of the scroll area from the window // as this is used to calculate the CSS fixed top position for the stickies - var scrollAreaOffset = scrollArea.getBoundingClientRect().top; + var scrollAreaOffset = scrollArea.getBoundingClientRect().top + window.pageYOffset; // Use the offset of the top of the componet from the window // as this is used to calculate the CSS fixed top position for the stickies var scrollAreaHeight = ReactDOM.findDOMNode(this).getBoundingClientRect().height; From 67c623d41062fd6ec1fe43a15163068f92cc3233 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Mon, 5 Sep 2016 10:29:03 +0100 Subject: [PATCH 08/48] Rename the action to make it clearer what it is doing --- src/components/structures/MatrixChat.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index d4b3df93bd..c2cee983c3 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -357,8 +357,8 @@ module.exports = React.createClass({ this._setPage(this.PageTypes.RoomDirectory); this.notifyNewScreen('directory'); break; - case 'view_one_to_one_chat': - this._oneToOneChat(); + case 'view_create_chat': + this._createChat(); break; case 'notifier_enabled': this.forceUpdate(); @@ -496,7 +496,7 @@ module.exports = React.createClass({ } }, - _oneToOneChat: function() { + _createChat: function() { // TODO: Create a OneToOneChatChatDialog var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { From ca443e01d8b370f94862010df331a4d09fa101ca Mon Sep 17 00:00:00 2001 From: wmwragg Date: Mon, 5 Sep 2016 12:03:16 +0100 Subject: [PATCH 09/48] Initial commit of the new ChatInviteDialog --- src/component-index.js | 1 + src/components/structures/MatrixChat.js | 10 +- .../views/dialogs/ChatInviteDialog.js | 98 +++++++++++++++++++ 3 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 src/components/views/dialogs/ChatInviteDialog.js diff --git a/src/component-index.js b/src/component-index.js index 3871f60e15..df31acfeaa 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -45,6 +45,7 @@ module.exports.components['views.avatars.RoomAvatar'] = require('./components/vi module.exports.components['views.create_room.CreateRoomButton'] = require('./components/views/create_room/CreateRoomButton'); module.exports.components['views.create_room.Presets'] = require('./components/views/create_room/Presets'); module.exports.components['views.create_room.RoomAlias'] = require('./components/views/create_room/RoomAlias'); +module.exports.components['views.dialogs.ChatInviteDialog'] = require('./components/views/dialogs/ChatInviteDialog'); module.exports.components['views.dialogs.DeactivateAccountDialog'] = require('./components/views/dialogs/DeactivateAccountDialog'); module.exports.components['views.dialogs.ErrorDialog'] = require('./components/views/dialogs/ErrorDialog'); module.exports.components['views.dialogs.LogoutPrompt'] = require('./components/views/dialogs/LogoutPrompt'); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index c2cee983c3..a8d8355cf1 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -497,11 +497,11 @@ module.exports = React.createClass({ }, _createChat: function() { - // TODO: Create a OneToOneChatChatDialog - var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createDialog(ErrorDialog, { - title: "Unimplemented Feature", - description: "The OnToOneChatDialog is not yet implemented" + var ChatInviteDialog = sdk.getComponent("dialogs.ChatInviteDialog"); + Modal.createDialog(ChatInviteDialog, { + title: "Start a one to one chat", + description: "Who would you like to communicate with?", + placeholder: "User ID, Name or email", }); }, diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js new file mode 100644 index 0000000000..3cf734da63 --- /dev/null +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -0,0 +1,98 @@ +/* +Copyright 2015, 2016 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. +*/ + +var React = require("react"); +var sdk = require('../../../index'); + +module.exports = React.createClass({ + displayName: 'ChatInviteDialog', + propTypes: { + title: React.PropTypes.string, + description: React.PropTypes.oneOfType([ + React.PropTypes.element, + React.PropTypes.string, + ]), + value: React.PropTypes.string, + button: React.PropTypes.string, + focus: React.PropTypes.bool, + onFinished: React.PropTypes.func.isRequired + }, + + getDefaultProps: function() { + return { + title: "", + value: "", + description: "", + button: "Start Chat", + focus: true + }; + }, + + componentDidMount: function() { + if (this.props.focus) { + // Set the cursor at the end of the text input + this.refs.textinput.value = this.props.value; + } + }, + + onOk: function() { + this.props.onFinished(true, this.refs.textinput.value); + }, + + onCancel: function() { + this.props.onFinished(false); + }, + + onKeyDown: function(e) { + if (e.keyCode === 27) { // escape + e.stopPropagation(); + e.preventDefault(); + this.props.onFinished(false); + } + else if (e.keyCode === 13) { // enter + e.stopPropagation(); + e.preventDefault(); + this.props.onFinished(true, this.refs.textinput.value); + } + }, + + render: function() { + var TintableSvg = sdk.getComponent('elements.TintableSvg'); + return ( +
+
+ {this.props.title} +
+
+ +
+
+ +
+
+
+ +
+
+
+ +
+
+ ); + } +}); From 3d66dff0aa80eb8264328f3e99c91e7b7c74e4e8 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Mon, 5 Sep 2016 14:16:21 +0100 Subject: [PATCH 10/48] Basic ChatInviteDialog functionality - Creates new room, and tries to invite the address typed into the text box, and reports errors, if any --- .../views/dialogs/ChatInviteDialog.js | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 3cf734da63..07dc3e7809 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -15,10 +15,13 @@ limitations under the License. */ var React = require("react"); -var sdk = require('../../../index'); +var sdk = require("../../../index"); +var Invite = require("../../../Invite"); +var createRoom = require("../../../createRoom"); +var Modal = require('../../../Modal'); module.exports = React.createClass({ - displayName: 'ChatInviteDialog', + displayName: "ChatInviteDialog", propTypes: { title: React.PropTypes.string, description: React.PropTypes.oneOfType([ @@ -48,8 +51,24 @@ module.exports = React.createClass({ } }, - onOk: function() { - this.props.onFinished(true, this.refs.textinput.value); + onStartChat: function() { + this._startChat(this.refs.textinput.value); + }, + + _startChat: function(addr) { + createRoom().then(function(roomId) { + return Invite.inviteToRoom(roomId, addr); + }) + .catch(function(err) { + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Failure to invite " + addr, + description: err.toString() + }); + return null; + }) + .done(); + this.props.onFinished(true, addr); }, onCancel: function() { @@ -65,12 +84,12 @@ module.exports = React.createClass({ else if (e.keyCode === 13) { // enter e.stopPropagation(); e.preventDefault(); - this.props.onFinished(true, this.refs.textinput.value); + this._startChat(this.refs.textinput.value); } }, render: function() { - var TintableSvg = sdk.getComponent('elements.TintableSvg'); + var TintableSvg = sdk.getComponent("elements.TintableSvg"); return (
@@ -88,7 +107,7 @@ module.exports = React.createClass({
-
From d9c6448a0f79a0e9bae9aad58eb32f0b5b1c56ad Mon Sep 17 00:00:00 2001 From: wmwragg Date: Mon, 5 Sep 2016 14:29:21 +0100 Subject: [PATCH 11/48] Adding better deafults and ErrorDialog message --- src/components/structures/MatrixChat.js | 2 -- src/components/views/dialogs/ChatInviteDialog.js | 11 ++++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index bfd8ae8e86..48431a956b 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -513,8 +513,6 @@ module.exports = React.createClass({ var ChatInviteDialog = sdk.getComponent("dialogs.ChatInviteDialog"); Modal.createDialog(ChatInviteDialog, { title: "Start a one to one chat", - description: "Who would you like to communicate with?", - placeholder: "User ID, Name or email", }); }, diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 07dc3e7809..2445dfb8f3 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -29,6 +29,7 @@ module.exports = React.createClass({ React.PropTypes.string, ]), value: React.PropTypes.string, + placeholder: React.PropTypes.string, button: React.PropTypes.string, focus: React.PropTypes.bool, onFinished: React.PropTypes.func.isRequired @@ -36,9 +37,10 @@ module.exports = React.createClass({ getDefaultProps: function() { return { - title: "", + title: "Start a chat", + description: "Who would you like to communicate with?", value: "", - description: "", + placeholder: "User ID, Name or email", button: "Start Chat", focus: true }; @@ -56,18 +58,21 @@ module.exports = React.createClass({ }, _startChat: function(addr) { + // Start the chat createRoom().then(function(roomId) { return Invite.inviteToRoom(roomId, addr); }) .catch(function(err) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failure to invite " + addr, + title: "Failure to invite user", description: err.toString() }); return null; }) .done(); + + // Close - this will happen before the above, as that is async this.props.onFinished(true, addr); }, From 54f21c9accdae4ff9dcd25883f5a98606fb7cf52 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 5 Sep 2016 14:58:16 +0100 Subject: [PATCH 12/48] Expose join rules of a room --- src/ScalarMessaging.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index cc552ba898..e58a5ab21b 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -193,6 +193,11 @@ function getMembershipState(event, roomId, userId) { returnStateEvent(event, roomId, "m.room.member", userId); } +function getJoinRules(event, roomId) { + console.log(`join_rules of ${roomId} requested.`); + returnStateEvent(event, roomId, "m.room.join_rules"); +} + function botOptions(event, roomId, userId) { console.log(`bot_options of ${userId} in room ${roomId} requested.`); returnStateEvent(event, roomId, "m.room.bot.options", "_" + userId); @@ -256,6 +261,9 @@ const onMessage = function(event) { case "set_bot_options": setBotOptions(event, roomId, userId); break; + case "join_rules_state": + getJoinRules(event, roomId); + break; default: console.warn("Unhandled postMessage event with action '" + event.data.action +"'"); break; From 1c29c959901dad1d06bb167f79d811097f23a3c1 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 5 Sep 2016 15:13:48 +0100 Subject: [PATCH 13/48] Only current room works with postMessage --- src/ScalarMessaging.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index e58a5ab21b..ee894ac785 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -123,6 +123,7 @@ Example: const SdkConfig = require('./SdkConfig'); const MatrixClientPeg = require("./MatrixClientPeg"); +var dis = require("../../dispatcher"); function sendResponse(event, res) { const data = JSON.parse(JSON.stringify(event.data)); @@ -203,7 +204,6 @@ function botOptions(event, roomId, userId) { returnStateEvent(event, roomId, "m.room.bot.options", "_" + userId); } - function returnStateEvent(event, roomId, eventType, stateKey) { const client = MatrixClientPeg.get(); if (!client) { @@ -223,6 +223,18 @@ function returnStateEvent(event, roomId, eventType, stateKey) { sendResponse(event, stateEvent.getContent()); } +var currentRoomId = null; + +// Listen for when a room is viewed +dis.register(onAction); +function onAction(payload) { + switch (payload.action) { + case 'view_room': + currentRoomId = payload.room_id; + break; + } +} + const onMessage = function(event) { if (!event.origin) { // stupid chrome event.origin = event.originalEvent.origin; @@ -248,6 +260,15 @@ const onMessage = function(event) { sendError(event, "Missing room_id in request"); return; } + if (!currentRoomId) { + sendError(event, "Must be viewing a room"); + return; + } + if (roomId !== currentRoomId) { + sendError(event, "Room not in view"); + return; + } + switch (event.data.action) { case "membership_state": getMembershipState(event, roomId, userId); From efccdab0ad501df35bcb1963d0d086dc7f5d13c9 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 5 Sep 2016 15:16:22 +0100 Subject: [PATCH 14/48] Better error message for room not viewed --- src/ScalarMessaging.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index ee894ac785..b8ba474b5f 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -265,7 +265,7 @@ const onMessage = function(event) { return; } if (roomId !== currentRoomId) { - sendError(event, "Room not in view"); + sendError(event, "Room " + roomId + " not in view"); return; } From 310e6602caa20a1392bda3bc8f068f353de9db7f Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 5 Sep 2016 15:24:05 +0100 Subject: [PATCH 15/48] Fix ref to dispatcher --- src/ScalarMessaging.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index b8ba474b5f..857ef1e3c7 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -123,7 +123,7 @@ Example: const SdkConfig = require('./SdkConfig'); const MatrixClientPeg = require("./MatrixClientPeg"); -var dis = require("../../dispatcher"); +var dis = require("./dispatcher"); function sendResponse(event, res) { const data = JSON.parse(JSON.stringify(event.data)); From 3dd84e2b8a53394f39eeef0f134a732f1bce802c Mon Sep 17 00:00:00 2001 From: wmwragg Date: Mon, 5 Sep 2016 17:28:08 +0100 Subject: [PATCH 16/48] Initial AddressTile added --- src/component-index.js | 1 + .../views/dialogs/ChatInviteDialog.js | 111 +++++++++++++++--- src/components/views/elements/AddressTile.js | 65 ++++++++++ 3 files changed, 162 insertions(+), 15 deletions(-) create mode 100644 src/components/views/elements/AddressTile.js diff --git a/src/component-index.js b/src/component-index.js index df31acfeaa..4cf2ba4016 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -54,6 +54,7 @@ module.exports.components['views.dialogs.NeedToRegisterDialog'] = require('./com module.exports.components['views.dialogs.QuestionDialog'] = require('./components/views/dialogs/QuestionDialog'); module.exports.components['views.dialogs.SetDisplayNameDialog'] = require('./components/views/dialogs/SetDisplayNameDialog'); module.exports.components['views.dialogs.TextInputDialog'] = require('./components/views/dialogs/TextInputDialog'); +module.exports.components['views.elements.AddressTile'] = require('./components/views/elements/AddressTile'); module.exports.components['views.elements.EditableText'] = require('./components/views/elements/EditableText'); module.exports.components['views.elements.EditableTextContainer'] = require('./components/views/elements/EditableTextContainer'); module.exports.components['views.elements.EmojiText'] = require('./components/views/elements/EmojiText'); diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 2445dfb8f3..e704289259 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -18,8 +18,12 @@ var React = require("react"); var sdk = require("../../../index"); var Invite = require("../../../Invite"); var createRoom = require("../../../createRoom"); +var MatrixClientPeg = require("../../../MatrixClientPeg"); +var rate_limited_func = require("../../../ratelimitedfunc"); var Modal = require('../../../Modal'); +const TRUNCATE_QUERY_LIST = 4; + module.exports = React.createClass({ displayName: "ChatInviteDialog", propTypes: { @@ -46,17 +50,56 @@ module.exports = React.createClass({ }; }, + getInitialState: function() { + return { + query: "", + queryList: [], + addressSelected: false, + }; + }, + componentDidMount: function() { if (this.props.focus) { // Set the cursor at the end of the text input this.refs.textinput.value = this.props.value; } + this._updateUserList(); }, onStartChat: function() { this._startChat(this.refs.textinput.value); }, + onCancel: function() { + this.props.onFinished(false); + }, + + onKeyDown: function(e) { + if (e.keyCode === 27) { // escape + e.stopPropagation(); + e.preventDefault(); + this.props.onFinished(false); + } + else if (e.keyCode === 13) { // enter + e.stopPropagation(); + e.preventDefault(); + //this._startChat(this.refs.textinput.value); + this.setState({ addressSelected: true }); + } + }, + + onQueryChanged: function(ev) { + var query = ev.target.value; + var queryList = this._userList.filter((user) => { + return this._matches(query, user); + }); + this.setState({ queryList: queryList }); + }, + + onDismissed: function() { + this.setState({ addressSelected: false }); + }, + _startChat: function(addr) { // Start the chat createRoom().then(function(roomId) { @@ -76,25 +119,65 @@ module.exports = React.createClass({ this.props.onFinished(true, addr); }, - onCancel: function() { - this.props.onFinished(false); - }, + _updateUserList: new rate_limited_func(function() { + // Get all the users + this._userList = MatrixClientPeg.get().getUsers(); + }, 500), - onKeyDown: function(e) { - if (e.keyCode === 27) { // escape - e.stopPropagation(); - e.preventDefault(); - this.props.onFinished(false); + // This is the search algorithm for matching users + _matches: function(query, user) { + var name = user.displayName.toLowerCase(); + var uid = user.userId.toLowerCase(); + query = query.toLowerCase(); + + // direct prefix matches + if (name.indexOf(query) === 0 || uid.indexOf(query) === 0) { + return true; } - else if (e.keyCode === 13) { // enter - e.stopPropagation(); - e.preventDefault(); - this._startChat(this.refs.textinput.value); + + // strip @ on uid and try matching again + if (uid.length > 1 && uid[0] === "@" && uid.substring(1).indexOf(query) === 0) { + return true; } + + // split spaces in name and try matching constituent parts + var parts = name.split(" "); + for (var i = 0; i < parts.length; i++) { + if (parts[i].indexOf(query) === 0) { + return true; + } + } + return false; }, render: function() { var TintableSvg = sdk.getComponent("elements.TintableSvg"); + console.log("### D E B U G - queryList:"); + console.log(this.state.queryList); + + var query; + if (this.state.addressSelected) { + var AddressTile = sdk.getComponent("elements.AddressTile"); + // NOTE: _userList[0] is just a place holder until the selection logic is completed + query = ( + + ); + } else { + query = ( + + ); + } + return (
@@ -107,9 +190,7 @@ module.exports = React.createClass({
-
- -
+
{ query }
- +
-
{ query }
+
{ query }
{ query }
+
+ { this.createQueryListTiles() } +