From bfe0cdcfd1e5f88cb8feefa74069ba49c9ecd38f Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 13 Jul 2015 01:51:24 +0100 Subject: [PATCH 001/200] vector wireframes --- examples/trivial/img | 1 + examples/trivial/index.html | 1 + skins/base/css/atoms/MessageTimestamp.css | 2 - skins/base/css/common.css | 14 ++- skins/base/css/molecules/MemberTile.css | 37 ++++++++ skins/base/css/molecules/MessageComposer.css | 47 +++++++++- skins/base/css/molecules/MessageTile.css | 24 ++++- skins/base/css/molecules/RoomDropTarget.css | 27 ++++++ skins/base/css/molecules/RoomHeader.css | 43 ++++++++- skins/base/css/molecules/RoomTile.css | 23 +++-- skins/base/css/molecules/SenderProfile.css | 2 - skins/base/css/organisms/LeftPanel.css | 88 ++++++++++++++++++ skins/base/css/organisms/MemberList.css | 42 +++++++++ skins/base/css/organisms/RightPanel.css | 54 +++++++++++ skins/base/css/organisms/RoomList.css | 7 ++ skins/base/css/organisms/RoomView.css | 78 +++++++++------- skins/base/css/pages/MatrixChat.css | 54 +++-------- skins/base/img/attach.png | Bin 0 -> 369 bytes skins/base/img/chevron.png | Bin 0 -> 2920 bytes skins/base/img/create.png | Bin 0 -> 807 bytes skins/base/img/file.png | Bin 0 -> 308 bytes skins/base/img/hide.png | Bin 0 -> 341 bytes skins/base/img/info.png | Bin 0 -> 660 bytes skins/base/img/members.png | Bin 0 -> 910 bytes skins/base/img/placeholder.png | Bin 0 -> 394 bytes skins/base/img/search.png | Bin 0 -> 651 bytes skins/base/img/video.png | Bin 0 -> 471 bytes skins/base/img/voip.png | Bin 0 -> 541 bytes skins/base/views/molecules/DirectoryMenu.js | 50 ++++++++++ skins/base/views/molecules/MemberTile.js | 1 + skins/base/views/molecules/MessageComposer.js | 11 ++- skins/base/views/molecules/MessageTile.js | 3 + skins/base/views/molecules/RoomCreate.js | 43 +++++++++ skins/base/views/molecules/RoomDropTarget.js | 36 +++++++ skins/base/views/molecules/RoomHeader.js | 23 ++++- skins/base/views/molecules/RoomTile.js | 9 +- skins/base/views/organisms/LeftPanel.js | 40 ++++++++ skins/base/views/organisms/MemberList.js | 18 ++-- skins/base/views/organisms/RightPanel.js | 39 ++++++++ skins/base/views/organisms/RoomList.js | 15 ++- skins/base/views/organisms/RoomView.js | 16 ++-- skins/base/views/pages/MatrixChat.js | 14 +-- src/ComponentBroker.js | 7 ++ 43 files changed, 741 insertions(+), 128 deletions(-) create mode 120000 examples/trivial/img create mode 100644 skins/base/css/molecules/MemberTile.css create mode 100644 skins/base/css/molecules/RoomDropTarget.css create mode 100644 skins/base/css/organisms/LeftPanel.css create mode 100644 skins/base/css/organisms/MemberList.css create mode 100644 skins/base/css/organisms/RightPanel.css create mode 100644 skins/base/img/attach.png create mode 100644 skins/base/img/chevron.png create mode 100644 skins/base/img/create.png create mode 100644 skins/base/img/file.png create mode 100644 skins/base/img/hide.png create mode 100644 skins/base/img/info.png create mode 100644 skins/base/img/members.png create mode 100644 skins/base/img/placeholder.png create mode 100644 skins/base/img/search.png create mode 100644 skins/base/img/video.png create mode 100644 skins/base/img/voip.png create mode 100644 skins/base/views/molecules/DirectoryMenu.js create mode 100644 skins/base/views/molecules/RoomCreate.js create mode 100644 skins/base/views/molecules/RoomDropTarget.js create mode 100644 skins/base/views/organisms/LeftPanel.js create mode 100644 skins/base/views/organisms/RightPanel.js diff --git a/examples/trivial/img b/examples/trivial/img new file mode 120000 index 000000000..0d3ef0e2f --- /dev/null +++ b/examples/trivial/img @@ -0,0 +1 @@ +../../skins/base/img \ No newline at end of file diff --git a/examples/trivial/index.html b/examples/trivial/index.html index 4ec5b9093..b5f4175f2 100644 --- a/examples/trivial/index.html +++ b/examples/trivial/index.html @@ -3,6 +3,7 @@ Matrix React SDK Example +
diff --git a/skins/base/css/atoms/MessageTimestamp.css b/skins/base/css/atoms/MessageTimestamp.css index 62b306566..b3c685094 100644 --- a/skins/base/css/atoms/MessageTimestamp.css +++ b/skins/base/css/atoms/MessageTimestamp.css @@ -15,6 +15,4 @@ limitations under the License. */ .mx_MessageTimestamp { - display: table-cell; - white-space: pre; } diff --git a/skins/base/css/common.css b/skins/base/css/common.css index 5153f9706..7fe0bca6c 100644 --- a/skins/base/css/common.css +++ b/skins/base/css/common.css @@ -15,9 +15,21 @@ limitations under the License. */ body { - font-family: Helvetica, Arial, Sans-Serif; + font-family: 'Muli', Helvetica, Arial, Sans-Serif; + font-weight: 300; + font-size: 15px; + color: #747474; + border: 0px; + margin: 0px; } div.error { color: red; } + +h2 { + font-weight: 400; + font-size: 20px; + margin-top: 16px; + margin-bottom: 16px; +} diff --git a/skins/base/css/molecules/MemberTile.css b/skins/base/css/molecules/MemberTile.css new file mode 100644 index 000000000..a01947e3f --- /dev/null +++ b/skins/base/css/molecules/MemberTile.css @@ -0,0 +1,37 @@ +/* +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. +*/ + +.mx_MemberTile { + cursor: pointer; + display: table-row; +} + +.mx_MemberTile_avatar { + display: table-cell; + padding-right: 12px; + padding-top: 3px; + padding-bottom: 3px; + vertical-align: middle; + width: 32px; + height: 32px; +} + +.mx_MemberTile_name { + display: table-cell; + vertical-align: middle; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/skins/base/css/molecules/MessageComposer.css b/skins/base/css/molecules/MessageComposer.css index 829e25a93..9ef77ba5e 100644 --- a/skins/base/css/molecules/MessageComposer.css +++ b/skins/base/css/molecules/MessageComposer.css @@ -14,7 +14,50 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_MessageComposer textarea { - width: 100%; +.mx_MessageComposer_wrapper { + max-width: 720px; + height: 50px; + vertical-align: middle; margin: auto; + border-top: 1px solid #d8d8d8; + border-left: 1px solid #d8d8d8; + border-right: 1px solid #d8d8d8; } + +.mx_MessageComposer_row { + display: table-row; + width: 100%; + height: 50px; +} + +.mx_MessageComposer .mx_MessageComposer_avatar { + display: table-cell; + padding-left: 12px; + padding-right: 12px; + padding-top: 3px; + padding-bottom: 3px; + vertical-align: middle; + width: 32px; + height: 32px; +} + +.mx_MessageComposer_input { + display: table-cell; + width: 100%; + padding-right: 1em; + vertical-align: middle; +} + +.mx_MessageComposer_input textarea { + font-size: 15px; + width: 100%; + height: 1em; + border: 0px; + resize: none; + outline: none; + padding-top: 0.7em; + padding-bottom: 0.7em; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} \ No newline at end of file diff --git a/skins/base/css/molecules/MessageTile.css b/skins/base/css/molecules/MessageTile.css index dae12e1a2..f0b337983 100644 --- a/skins/base/css/molecules/MessageTile.css +++ b/skins/base/css/molecules/MessageTile.css @@ -15,11 +15,31 @@ limitations under the License. */ .mx_MessageTile { - display: table-row; + width: 100%; + clear: both; + margin-top: 32px; +} + +.mx_MessageTile_avatar { + padding-left: 12px; + padding-right: 12px; + margin-top: -7px; + float: left; +} + +.mx_MessageTile .mx_SenderProfile { + color: #acacac; + font-size: 13px; + display: block; +} + +.mx_MessageTile .mx_MessageTimestamp { + color: #acacac; + font-size: 13px; + float: right; } .mx_MessageTile_content { - display: table-cell; } .mx_MessageTile_sending { diff --git a/skins/base/css/molecules/RoomDropTarget.css b/skins/base/css/molecules/RoomDropTarget.css new file mode 100644 index 000000000..946b40912 --- /dev/null +++ b/skins/base/css/molecules/RoomDropTarget.css @@ -0,0 +1,27 @@ +/* +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. +*/ + +.mx_RoomDropTarget { + font-size: 14px; + text-align: center; + margin-left: -8px; + margin-right: -8px; + padding-top: 16px; + padding-bottom: 16px; + background-color: #fbfbfb; + border: 1px dashed #d7d7d7; + border-radius: 8px; +} diff --git a/skins/base/css/molecules/RoomHeader.css b/skins/base/css/molecules/RoomHeader.css index 63d6fc33f..bbf4e8e2e 100644 --- a/skins/base/css/molecules/RoomHeader.css +++ b/skins/base/css/molecules/RoomHeader.css @@ -15,6 +15,45 @@ limitations under the License. */ .mx_RoomHeader { - height: 1em; - padding: 0px; } + +.mx_RoomHeader_wrapper { + max-width: 720px; + margin: auto; + height: 50px; +} + +.mx_RoomHeader_leftRow { + display: table-row; + height: 50px; + float: left; +} + +.mx_RoomHeader_rightRow { + display: table-row; + height: 50px; + float: right; +} + +.mx_RoomHeader_name { + display: table-cell; + vertical-align: middle; + height: 50px; + font-weight: 400; + font-size: 20px; + padding-left: 16px; + padding-right: 16px; +} + +.mx_RoomHeader_avatar { + display: table-cell; + height: 50px; + vertical-align: middle; +} + +.mx_RoomHeader_button { + height: 50px; + display: table-cell; + vertical-align: middle; + padding-right: 16px; +} \ No newline at end of file diff --git a/skins/base/css/molecules/RoomTile.css b/skins/base/css/molecules/RoomTile.css index 719551cb5..b3f4018cd 100644 --- a/skins/base/css/molecules/RoomTile.css +++ b/skins/base/css/molecules/RoomTile.css @@ -15,31 +15,40 @@ limitations under the License. */ .mx_RoomTile { - padding: 5px; cursor: pointer; + display: table-row; } -.mx_RoomTile.selected { +.mx_RoomTile_selected { text-decoration: underline; } -.mx_RoomTile_name { +.mx_RoomTile_avatar { + display: table-cell; + padding-right: 12px; + padding-top: 3px; + padding-bottom: 3px; + vertical-align: middle; + width: 32px; + height: 32px; } -.mx_RoomTile div { +.mx_RoomTile_name { + display: table-cell; + vertical-align: middle; overflow: hidden; text-overflow: ellipsis; } -.mx_RoomTile.unread { +.mx_RoomTile_unread { font-weight: bold; } -.mx_RoomTile.highlight { +.mx_RoomTile_highlight { background-color: lime; } -.mx_RoomTile.invited { +.mx_RoomTile_invited { font-weight: bold; } diff --git a/skins/base/css/molecules/SenderProfile.css b/skins/base/css/molecules/SenderProfile.css index 549b59845..18523a9b3 100644 --- a/skins/base/css/molecules/SenderProfile.css +++ b/skins/base/css/molecules/SenderProfile.css @@ -15,6 +15,4 @@ limitations under the License. */ .mx_SenderProfile { - display: table-cell; - padding: 0px 1em 0em 1em; } diff --git a/skins/base/css/organisms/LeftPanel.css b/skins/base/css/organisms/LeftPanel.css new file mode 100644 index 000000000..36bc5933c --- /dev/null +++ b/skins/base/css/organisms/LeftPanel.css @@ -0,0 +1,88 @@ +/* +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. +*/ + +.mx_LeftPanel { + position: relative; + + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + flex-direction: column; + -webkit-flex-direction: column; + + border-right: 1px solid #d8d8d8; +} + +.mx_LeftPanel_hideButton { + position: absolute; + top: 10px; + right: 10px; +} + +.mx_LeftPanel .mx_RoomList { + -webkit-box-ordinal-group: 1; + -moz-box-ordinal-group: 1; + -ms-flex-order: 1; + -webkit-order: 1; + order: 1; + + padding-left: 16px; + padding-right: 16px; + + /* background-color: #0ff; */ + height: 100%; + overflow-y: scroll; +} + +.mx_LeftPanel .mx_RoomCreate { + -webkit-box-ordinal-group: 2; + -moz-box-ordinal-group: 2; + -ms-flex-order: 2; + -webkit-order: 2; + order: 2; + + padding-left: 16px; + padding-right: 16px; + min-height: 46px; + + border-top: 1px solid #d8d8d8; + border-bottom: 1px solid #d8d8d8; +} + +.mx_LeftPanel .mx_RoomCreate .mx_RoomCreate_table { + display: table; + width: 100%; + height: 46px; +} + +.mx_LeftPanel .mx_DirectoryMenu { + -webkit-box-ordinal-group: 3; + -moz-box-ordinal-group: 3; + -ms-flex-order: 3; + -webkit-order: 3; + order: 3; + + min-height: 150px; + padding-left: 16px; + padding-right: 16px; +} + +.mx_LeftPanel .mx_DirectoryMenu .mx_DirectoryMenu_options { + margin-top: -12px; + width: 100%; +} \ No newline at end of file diff --git a/skins/base/css/organisms/MemberList.css b/skins/base/css/organisms/MemberList.css new file mode 100644 index 000000000..4831b86f9 --- /dev/null +++ b/skins/base/css/organisms/MemberList.css @@ -0,0 +1,42 @@ +/* +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. +*/ + +.mx_MemberList { + width: 100%; + height: 100%; + margin-bottom: 100px; +} + +.mx_MemberList_chevron { + position: absolute; + right: 20px; + margin-top: -5px; +} + +.mx_MemberList_wrapper { + border: 1px solid #d8d8d8; + margin: 8px; + overflow-y: scroll; + height: auto; + max-height: 75%; + border-radius: 8px; + padding: 20px 24px 14px 24px; + table-layout: fixed; +} + +.mx_MemberList h2 { + margin-top: 0px; +} diff --git a/skins/base/css/organisms/RightPanel.css b/skins/base/css/organisms/RightPanel.css new file mode 100644 index 000000000..d4b33c302 --- /dev/null +++ b/skins/base/css/organisms/RightPanel.css @@ -0,0 +1,54 @@ +/* +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. +*/ + +.mx_RightPanel { + position: relative; + + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + flex-direction: column; + -webkit-flex-direction: column; +} + +.mx_RightPanel_header { + -webkit-box-ordinal-group: 1; + -moz-box-ordinal-group: 1; + -ms-flex-order: 1; + -webkit-order: 1; + order: 1; + flex: 0 0 50px; + + text-align: right; + + height: 50px; + border-bottom: 1px solid #d8d8d8; +} + +.mx_RightPanel_headerButton { + margin-top: 9px; + margin-right: 16px; +} + +.mx_RightPanel .mx_MemberList { + -webkit-box-ordinal-group: 2; + -moz-box-ordinal-group: 2; + -ms-flex-order: 2; + -webkit-order: 2; + order: 2; +} diff --git a/skins/base/css/organisms/RoomList.css b/skins/base/css/organisms/RoomList.css index e2dec3c9f..31962824c 100644 --- a/skins/base/css/organisms/RoomList.css +++ b/skins/base/css/organisms/RoomList.css @@ -16,3 +16,10 @@ limitations under the License. .mx_RoomList { } + +.mx_RoomList_recents { + margin-top: -12px; + display: table; + table-layout: fixed; + width: 100%; +} \ No newline at end of file diff --git a/skins/base/css/organisms/RoomView.css b/skins/base/css/organisms/RoomView.css index 4176c4b8c..460a02f8b 100644 --- a/skins/base/css/organisms/RoomView.css +++ b/skins/base/css/organisms/RoomView.css @@ -17,66 +17,74 @@ limitations under the License. .mx_RoomView { word-wrap: break-word; position: relative; -} -.mx_RoomView .mx_RoomHeader { - height: 30px; -} - -.mx_RoomView_roomWrapper { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; - display: flex; - position: absolute; + display: flex; width: 100%; - top: 32px; - bottom: 0px; + flex-direction: column; + -webkit-flex-direction: column; } -.mx_RoomView_messagePanel { +.mx_RoomView .mx_RoomHeader { -webkit-box-ordinal-group: 1; -moz-box-ordinal-group: 1; -ms-flex-order: 1; -webkit-order: 1; order: 1; - width: 100%; - height: 100%; - /* background-color: #ff0; */ + + flex: 0 0 50px; + border-bottom: 1px solid #d8d8d8; } -.mx_RoomView_messageListWrapper { - height: 100%; - overflow-y: scroll; -} - -.mx_RoomView_MessageList { - display: table; -} - -.mx_RoomView_invitePrompt { -} - -.mx_RoomView .mx_MemberList { +.mx_RoomView_auxPanel { -webkit-box-ordinal-group: 2; -moz-box-ordinal-group: 2; -ms-flex-order: 2; -webkit-order: 2; order: 2; - /* background-color: #0f0; */ - width: 250px; - overflow-y: scroll; - height: 100%; + width: 100%; + height: 0%; } -.mx_RoomView .mx_MemberList ul { - margin: 0px; - padding: 0px; +.mx_RoomView_messagePanel { + -webkit-box-ordinal-group: 3; + -moz-box-ordinal-group: 3; + -ms-flex-order: 3; + -webkit-order: 3; + order: 3; + + width: 100%; + height: 100%; + margin-bottom: 60px; + /* background-color: #ff0; */ + + overflow-y: scroll; +} + +.mx_RoomView_messageListWrapper { + max-width: 720px; + margin: auto; +} + +.mx_RoomView_MessageList { + width: 100%; +} + +.mx_RoomView_invitePrompt { } .mx_RoomView .mx_MessageComposer { + -webkit-box-ordinal-group: 4; + -moz-box-ordinal-group: 4; + -ms-flex-order: 4; + -webkit-order: 4; + order: 4; + width: 100%; - bottom: 0px; + flex: 0 0 50px; + /* background-color: #ff0; */ } diff --git a/skins/base/css/pages/MatrixChat.css b/skins/base/css/pages/MatrixChat.css index 7ce88ec7f..22a53aea0 100644 --- a/skins/base/css/pages/MatrixChat.css +++ b/skins/base/css/pages/MatrixChat.css @@ -18,62 +18,23 @@ limitations under the License. position: relative; width: 100%; height: 100%; -} - -.mx_MatrixChat_chatWrapper { - display: -webkit-box; - display: -moz-box; - display: -ms-flexbox; - display: -webkit-flex; - display: flex; - position: absolute; - width: 100%; - top: 0px; - bottom: 42px; -} - -.mx_MatrixChat_leftPanel { - -webkit-box-ordinal-group: 1; - -moz-box-ordinal-group: 1; - -ms-flex-order: 1; - -webkit-order: 1; - order: 1; display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; - flex-direction: column; - -webkit-flex-direction: column; - - /* background-color: #f00; */ - width: 250px; - height: 100%; } -.mx_MatrixChat_leftPanel .mx_MatrixToolbar { +.mx_MatrixChat .mx_LeftPanel { -webkit-box-ordinal-group: 1; -moz-box-ordinal-group: 1; -ms-flex-order: 1; -webkit-order: 1; order: 1; - width: 100%; - height: 40px; -} - -.mx_MatrixChat_leftPanel .mx_RoomList { - -webkit-box-ordinal-group: 2; - -moz-box-ordinal-group: 2; - -ms-flex-order: 2; - -webkit-order: 2; - order: 2; - - /* background-color: #0ff; */ - width: 100%; + flex: 0 0 230px; height: 100%; - overflow-y: scroll; } .mx_MatrixChat .mx_RoomView { @@ -87,3 +48,14 @@ limitations under the License. width: 100%; height: 100%; } + +.mx_MatrixChat .mx_RightPanel { + -webkit-box-ordinal-group: 3; + -moz-box-ordinal-group: 3; + -ms-flex-order: 3; + -webkit-order: 3; + order: 3; + + flex: 0 0 230px; + height: 100%; +} diff --git a/skins/base/img/attach.png b/skins/base/img/attach.png new file mode 100644 index 0000000000000000000000000000000000000000..1bcb70045d457e1b96c03a89b6652c3c720137e5 GIT binary patch literal 369 zcmV-%0gnEOP)S8 zD2f_}0rz*kj^}wVo+3va$H$j^2uKSak7=Ig0D$#ek|d%iE<06KHBGagoTf=t)ono( zMbBP@8Wm$${Y!350zb()-4S(;FBps*d9|bJS>bkyb2_SuazX~t_q8w+Y1HH_H P00000NkvXXu0mjfe{z=) literal 0 HcmV?d00001 diff --git a/skins/base/img/chevron.png b/skins/base/img/chevron.png new file mode 100644 index 0000000000000000000000000000000000000000..3c908d1ca9f00fedd1eb5b9da1e15986d2273cd1 GIT binary patch literal 2920 zcmV-u3zzhXP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0001!Nkl%efSnic{wJb=9_&28mufTlStD+i87qhPDPRDU9Ww(F zQEQE}JDdf~45btzA{t}l5dh1ls)z_26A@5VWOldXyU3;Z4l?}^5x6^6K9s>aHcAxzS S##K=O0000(RCwC7md$D!Q544~Nx$yJCJ6a z&P>#vg>q-^{hf2~J#+qNN7FRP&Zg7pa5x-~$CJr~q0i^@`~7=+dy1miuHCV40QchJ z;`;h}Fc^eFA;IOj@N{!?6AT6uiNwLdfrTe?2ea9%*=#l%jbt(jA{vd#vTT^MSS&i7 z4(_k6uF~mrDwXnjy^b98`~70E7>PtOnM@!Muswv)XjG|Gy4`LrmkWo(#@E_IYq#5l zLV;iHk;anK)6>h#OT+UA4tNc{*XwC(8Czcs?%n}hLST}%fdMgus5>BG&d$!(I2qHk z0tHYE_1qw5xK*-6+Sq`A0w{*E$agZ5oRPL}5KW=~9&gAn1d*^_SPzhqOn6y>nCcpxhsbbWb)kut!oABiT~^b{_;#_7RaF!uSy4QuE5TA0ck1;zf7xu-yr6#n^5N5G z>tNr$`}lg_q?(q?Wqi1;7kh%w@<(~ewH&zJYU}ICdG*avKJJplMXRd&`4f)?!A*&$ zJpA)0clQrp?cbkQXL@ozdGYcv;o!b5Qb6hP5x=;=mJfNFDao6~`S0%#QdRkd4BmeE}k$^5&e zSX-7wh=#_(*tYPR5Y}s3O#7Yx-gw!!j))y{WZF6sZ>!aMbn9r*{0ilmEN!Fa*R*{H lN`YiZ3B!}a_Wh3l0{{dzLWKWE_s{?U002ovPDHLkV1ng%k_i9+ literal 0 HcmV?d00001 diff --git a/skins/base/img/file.png b/skins/base/img/file.png new file mode 100644 index 0000000000000000000000000000000000000000..2ea4f280f52336c7ac2a9c6892aac42a48cb306a GIT binary patch literal 308 zcmV-40n7f0P)j1{xbLg0000F(EK6P2F~bJ$>3!c1!w^LgAp|o|@K42k-*sIt%Mym6Wm(9tuz=$@s;auK zD+mJ9H1Rh^S+wtaQ53dq`@WB~{w?;TZQHUeYnp}$=@}5m@i>l5RMLxvwWw`du^XUL z1WV5I+;JSw^LUrc5mRU{RDn09(u=0?dfIhenx^Zzel4b-g2ygN5@$+eO nI7TV`<_^>^Qvv=K@DgAE-GM6u`V|KC00000NkvXXu0mjf;D(g? literal 0 HcmV?d00001 diff --git a/skins/base/img/info.png b/skins/base/img/info.png new file mode 100644 index 0000000000000000000000000000000000000000..699fd64e013954b01bca869c67ce3868eb82338b GIT binary patch literal 660 zcmV;F0&D$=P)-bA>~pwRsOBqVpKY)2 z+h?7%zqK`zB)vToKi-~CKSS%Ke zMs+&zi|+UPX0zF7G{WI2#=frHb5cx8-vA=LuA&;xAR+s8UgoKqU~s z2{@}tVS2qj5{cYXvXDR}5WoP=PVgWgIa}5f-BhE|2n1xx-v%TmlSv?e1LKj83qS&u zKmdQofgcxu1S)|*Fc`$&Rcibm5Dp2ANFd;FIPd_W&)g5fA^F(mK2;IDiSBW2mSD5l z)y76R0`sf@0000Id9V7oTbM+iiuY!ieFgBF$*U7?HA=5(b-ELKNZ zQR?jMwApNg<>24|zOk{fo}QlEnXRp@U@$l}H6_0zQ@D8S{QNv|&s*N#-{5*%Adf^MWHlG} ze8lSO>y<^)*x1PKuW)M`z94|3CZOJ_NU3Hl77KAumJoJ!rDuTvj+$U+XNOEmC^$Sm zJ}L>Yvnv@vpg+_E7Z(@$lBccAX0wvOWHLQJKkIWt+SCL*nO>C~(&;on#R%Ayj39_1 zHAt7Os;ZJ48X6j|uCDYqWl^d6&H@1(H32%K2cmD=+uP{_$xgy(k(QPg$qoWIY63EL zdwZ+DX@7tJ-rk;M+~4058K+>#9~h-le4q4DCpVQSsNc6ho^io9gOn#u-x6 z)z#JA-3_9_V31@O=y-OKYP6l6K*mvQG4twq;P?CKUPgk;6mv$pb+LuIkrll3Q}dIVO#S$LzCS;c^Z8(Upzk05DyR#O$MfZ1 k#ozcB{r{V0*G~Zk0M~sfGW4*&p8x;=07*qoM6N<$f)7Z)xBvhE literal 0 HcmV?d00001 diff --git a/skins/base/img/placeholder.png b/skins/base/img/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..7da32f259c1a90d721dfc9abc4ad427ab9e7c5bf GIT binary patch literal 394 zcmV;50d@X~P)ntlanzq{fbCjfCT%hE_`W?6RRV+Y`~D2n@8z07%@=Tuia0Fgm_4E7hI zgjnH=q~EA_vkiP0O6pa0H)#llu-yUw)TKgXy87Bio%`#m+c~Zt`?=?wZny3lKJ4|| zd#(Ta@2$9AuPKF z>7CJuU@*v8WvGa*R;yJi^ECS{LZJ}5>GgV|05s!rxgOU2@nWSi91b@c4N(A!L^HBv z?(ukLvl+S&0-*Qjs(2r-udgPP3Hb^Em?oW0CwEqv1{Mkdm{q1pE`a)Q4j}+eAaU4- z!OXM7Y&Hu4@EM#y7GOG^QdNV&AOv7`@EM#y98j;<{eHiwOz}uu44)CqKAB9$<8dGm zkZ~X2k+>KW_cS{$l+Wj*(Wq9dl>tC=cx1U;#*}EF#NN~CG}h8=HgOBt_rYqlx;ZvZ zz^wjKAxP%7R;y7N_D=TEXoNHpiG*6MmI1g0E{4yLky+(r=p99(8M;c{sSG>F<#N&t z#nWfYEibdmIneu^BA+r8AAc7~Gd|%}K}PbD9R{Sko`24>c}jLZtuz002ovPDHLkV1i!QG86y+ literal 0 HcmV?d00001 diff --git a/skins/base/img/video.png b/skins/base/img/video.png new file mode 100644 index 0000000000000000000000000000000000000000..d83640a4ff69ce9505bf4320404a5296962ee2ee GIT binary patch literal 471 zcmV;|0Vw{7P)jl%V^V_{s0FAIO>q7C^`)hyzkdBf ziDY27^YQVKY5`CST7(@uco1SG6B85lQ_P*YQL zb#C>mQst@GlC-1tizA>Gphh?sm{{Mxe?Mo=oPYoRq5A+> zdz?LcmQ+^*wE#6Di`d!OK}4W-(7M85L~eM|qRM0(ZP|@lKrsLaFaS4s~@Fx|S>vzXq_ zIq!4cw`b;g#;Pca#mpcqCWq+;UpjTG)vDX=ilTTp9Bek5&*#fzG9*cAZnWyDLBHQ0 z33-sVltUjDwXYadxZl54)*bOLeKFFg@VK3xWa(| z2m5M~7mGzG6uL_R2m7kQe!ssx{^b&2|N3|Es|GB~>df*$`KiH625OtK+wHsE?ydkh z*o*RM1A-uq$73K6n9t{T1;D{V1EmpzU@$nF&CoBK&F1YTfB**z4U|R zN8axgoLa3GvX@FFwbTYD+Ua!a^?IYxC?1caKRcby&1Qr04u?aEqSEQ~g9_^%nFv{y zd7fV`m*ep`8jbq>{#Y#LcDuEADo+N(Fi+_}z34svMb&B*Z;rZNuh%Y@OI_oQDwoS| fF! +

Directory

+
+
+
+ (+) +
+
Users
+
+
+
+ (+) +
+
Rooms
+
+
+ + ); + } +}); diff --git a/skins/base/views/molecules/MemberTile.js b/skins/base/views/molecules/MemberTile.js index 60d1cadd8..7ed4eadc2 100644 --- a/skins/base/views/molecules/MemberTile.js +++ b/skins/base/views/molecules/MemberTile.js @@ -26,6 +26,7 @@ module.exports = React.createClass({ render: function() { return (
+
()
{this.props.member.name}
); diff --git a/skins/base/views/molecules/MessageComposer.js b/skins/base/views/molecules/MessageComposer.js index 89c426cb2..7cecb79c2 100644 --- a/skins/base/views/molecules/MessageComposer.js +++ b/skins/base/views/molecules/MessageComposer.js @@ -27,7 +27,16 @@ module.exports = React.createClass({ render: function() { return (
- + ); + } +}); diff --git a/skins/base/views/molecules/DirectoryMenu.js b/skins/base/views/molecules/DirectoryMenu.js index f3b9e592b..60b5542d4 100644 --- a/skins/base/views/molecules/DirectoryMenu.js +++ b/skins/base/views/molecules/DirectoryMenu.js @@ -33,11 +33,15 @@ module.exports = React.createClass({ dis.dispatch({action: 'view_user_settings'}); }, + onCreateRoomClick: function() { + dis.dispatch({action: 'view_create_room'}); + }, + render: function() { return (
-
+
diff --git a/skins/base/views/organisms/CreateRoom.js b/skins/base/views/organisms/CreateRoom.js index 36f6e466e..d7e84cccd 100644 --- a/skins/base/views/organisms/CreateRoom.js +++ b/skins/base/views/organisms/CreateRoom.js @@ -24,6 +24,8 @@ var ComponentBroker = require('../../../../src/ComponentBroker'); var CreateRoomButton = ComponentBroker.get("atoms/create_room/CreateRoomButton"); var RoomNameTextbox = ComponentBroker.get("atoms/create_room/RoomNameTextbox"); +var RoomTopic = ComponentBroker.get("atoms/create_room/RoomTopic"); +var RoomAlias = ComponentBroker.get("atoms/create_room/RoomAlias"); var Presets = ComponentBroker.get("atoms/create_room/Presets"); var UserSelector = ComponentBroker.get("molecules/UserSelector"); @@ -61,10 +63,12 @@ module.exports = React.createClass({ } return (
- - - - +
+
+
+
+
+
{error_box}
); diff --git a/skins/base/views/pages/MatrixChat.js b/skins/base/views/pages/MatrixChat.js index 27d1a1151..4ab0e6492 100644 --- a/skins/base/views/pages/MatrixChat.js +++ b/skins/base/views/pages/MatrixChat.js @@ -25,28 +25,44 @@ var RightPanel = ComponentBroker.get('organisms/RightPanel'); var Login = ComponentBroker.get('templates/Login'); var UserSettings = ComponentBroker.get('organisms/UserSettings'); var Register = ComponentBroker.get('templates/Register'); +var CreateRoom = ComponentBroker.get('organisms/CreateRoom'); var MatrixChatController = require("../../../../src/controllers/pages/MatrixChat"); // should be atomised var Loader = require("react-loader"); +var dis = require("../../../../src/dispatcher"); + module.exports = React.createClass({ displayName: 'MatrixChat', mixins: [MatrixChatController], + onRoomCreated: function(room_id) { + dis.dispatch({ + action: "view_room", + room_id: room_id, + }); + }, + render: function() { if (this.state.logged_in && this.state.ready) { var page_element; var right_panel = ""; - if (this.state.page_type == this.PageTypes.RoomView) { - page_element = - right_panel = - } else if (this.state.page_type == this.PageTypes.UserSettings) { - page_element = + switch (this.state.page_type) { + case this.PageTypes.RoomView: + page_element = + right_panel = + break; + case this.PageTypes.UserSettings: + page_element = + break; + case this.PageTypes.CreateRoom: + page_element = + break; } return ( diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js index dfbcf2e21..58e8f2eef 100644 --- a/src/ComponentBroker.js +++ b/src/ComponentBroker.js @@ -63,6 +63,8 @@ require('../skins/base/views/atoms/EnableNotificationsButton'); require('../skins/base/views/atoms/MessageTimestamp'); require('../skins/base/views/atoms/create_room/CreateRoomButton'); require('../skins/base/views/atoms/create_room/RoomNameTextbox'); +require('../skins/base/views/atoms/create_room/RoomTopic'); +require('../skins/base/views/atoms/create_room/RoomAlias'); require('../skins/base/views/atoms/create_room/Presets'); require('../skins/base/views/atoms/EditableText'); require('../skins/base/views/molecules/MatrixToolbar'); diff --git a/src/controllers/atoms/create_room/RoomAlias.js b/src/controllers/atoms/create_room/RoomAlias.js new file mode 100644 index 000000000..804b0b29e --- /dev/null +++ b/src/controllers/atoms/create_room/RoomAlias.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_alias: React.PropTypes.string + }, + + getDefaultProps: function() { + return { + default_alias: '', + }; + }, + + getInitialState: function() { + return { + room_alias: this.props.default_alias, + } + }, + + getAlias: function() { + return this.state.room_alias; + }, +}; diff --git a/src/controllers/atoms/create_room/RoomTopic.js b/src/controllers/atoms/create_room/RoomTopic.js new file mode 100644 index 000000000..cbd21b9b8 --- /dev/null +++ b/src/controllers/atoms/create_room/RoomTopic.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_topic: React.PropTypes.string + }, + + getDefaultProps: function() { + return { + default_topic: '', + }; + }, + + getInitialState: function() { + return { + room_topic: this.props.default_topic, + } + }, + + getTopic: function() { + return this.state.room_topic; + }, +}; diff --git a/src/controllers/organisms/CreateRoom.js b/src/controllers/organisms/CreateRoom.js index c2112ce58..048f36795 100644 --- a/src/controllers/organisms/CreateRoom.js +++ b/src/controllers/organisms/CreateRoom.js @@ -77,11 +77,11 @@ module.exports = { var self = this; - deferred.then(function () { + deferred.then(function (resp) { self.setState({ phase: self.phases.CREATED, }); - self.props.onRoomCreated(); + self.props.onRoomCreated(resp.room_id); }, function(err) { self.setState({ phase: self.phases.ERROR, diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js index 9367872b2..26bc6cf62 100644 --- a/src/controllers/pages/MatrixChat.js +++ b/src/controllers/pages/MatrixChat.js @@ -32,6 +32,11 @@ module.exports = { PageTypes: { RoomView: "room_view", UserSettings: "user_settings", + CreateRoom: "create_room", + }, + + AuxPanel: { + RoomSettings: "room_settings", }, getInitialState: function() { @@ -39,6 +44,7 @@ module.exports = { logged_in: !!(MatrixClientPeg.get() && MatrixClientPeg.get().credentials), ready: false, page_type: this.PageTypes.RoomView, + aux_panel: null, }; }, @@ -143,6 +149,11 @@ module.exports = { page_type: this.PageTypes.UserSettings, }); break; + case 'view_create_room': + this.setState({ + page_type: this.PageTypes.CreateRoom, + }); + break; } }, From 6fbb7d7da4e04388cf81317e61743351c996ac7e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 16 Jul 2015 14:25:57 +0100 Subject: [PATCH 047/200] Implement nick completion (tab-complete). Including SHIFT+TAB to go backwards and the 'blink' css (which may need to be factored out of the view). Mostly ported from Angular. --- src/controllers/molecules/MessageComposer.js | 167 ++++++++++++++++--- 1 file changed, 145 insertions(+), 22 deletions(-) diff --git a/src/controllers/molecules/MessageComposer.js b/src/controllers/molecules/MessageComposer.js index 11628bbf6..1012fe375 100644 --- a/src/controllers/molecules/MessageComposer.js +++ b/src/controllers/molecules/MessageComposer.js @@ -19,10 +19,20 @@ limitations under the License. var MatrixClientPeg = require("../../MatrixClientPeg"); var dis = require("../../dispatcher"); +var KeyCode = { + ENTER: 13, + TAB: 9, + SHIFT: 16 +}; module.exports = { componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); + this.tabStruct = { + completing: false, + original: null, + index: 0 + }; }, componentWillUnmount: function() { @@ -38,30 +48,143 @@ module.exports = { }, onKeyDown: function (ev) { - if (ev.keyCode == 13) { - var contentText = this.refs.textarea.getDOMNode().value; - - var content = null; - if (/^\/me /i.test(contentText)) { - content = { - msgtype: 'm.emote', - body: contentText.substring(4) - }; - } else { - content = { - msgtype: 'm.text', - body: contentText - }; + if (ev.keyCode === KeyCode.ENTER) { + this.onEnter(ev); + } + else if (ev.keyCode === KeyCode.TAB) { + var members = []; + if (this.props.room) { + members = this.props.room.getJoinedMembers(); } - - MatrixClientPeg.get().sendMessage(this.props.room.roomId, content).then(function() { - dis.dispatch({ - action: 'message_sent' - }); - }); - this.refs.textarea.getDOMNode().value = ''; - ev.preventDefault(); + this.onTab(ev, members); + } + else if (ev.keyCode !== KeyCode.SHIFT && this.tabStruct.completing) { + // they're resuming typing; reset tab complete state vars. + this.tabStruct.completing = false; + this.tabStruct.index = 0; } }, + + onEnter: function(ev) { + var contentText = this.refs.textarea.getDOMNode().value; + var content = null; + if (/^\/me /i.test(contentText)) { + content = { + msgtype: 'm.emote', + body: contentText.substring(4) + }; + } else { + content = { + msgtype: 'm.text', + body: contentText + }; + } + + MatrixClientPeg.get().sendMessage(this.props.room.roomId, content).then(function() { + dis.dispatch({ + action: 'message_sent' + }); + }); + this.refs.textarea.getDOMNode().value = ''; + ev.preventDefault(); + }, + + onTab: function(ev, sortedMembers) { + var textArea = this.refs.textarea.getDOMNode(); + if (!this.tabStruct.completing) { + this.tabStruct.completing = true; + this.tabStruct.index = 0; + // cache starting text + this.tabStruct.original = textArea.value; + } + + // loop in the right direction + if (ev.shiftKey) { + this.tabStruct.index --; + if (this.tabStruct.index < 0) { + // wrap to the last search match, and fix up to a real index + // value after we've matched. + this.tabStruct.index = Number.MAX_VALUE; + } + } + else { + this.tabStruct.index++; + } + + var searchIndex = 0; + var targetIndex = this.tabStruct.index; + var text = this.tabStruct.original; + + var search = /@?([a-zA-Z0-9_\-:\.]+)$/.exec(text); + // console.log("Searched in '%s' - got %s", text, search); + if (targetIndex === 0) { // 0 is always the original text + textArea.value = text; + } + else if (search && search[1]) { + // console.log("search found: " + search+" from "+text); + var expansion; + + // FIXME: could do better than linear search here + for (var i=0; i= targetIndex) { + break; + } + var userId = sortedMembers[i].userId; + // === 1 because mxids are @username + if (userId.toLowerCase().indexOf(search[1].toLowerCase()) === 1) { + expansion = userId; + searchIndex++; + } + } + } + + if (searchIndex === targetIndex || + targetIndex === Number.MAX_VALUE) { + // xchat-style tab complete, add a colon if tab + // completing at the start of the text + if (search[0].length === text.length) { + expansion += ": "; + } + else { + expansion += " "; + } + textArea.value = text.replace( + /@?([a-zA-Z0-9_\-:\.]+)$/, expansion + ); + // cancel blink + textArea.style["background-color"] = ""; + if (targetIndex === Number.MAX_VALUE) { + // wrap the index around to the last index found + this.tabStruct.index = searchIndex; + targetIndex = searchIndex; + } + } + else { + // console.log("wrapped!"); + textArea.style["background-color"] = "#faa"; + setTimeout(function() { + textArea.style["background-color"] = ""; + }, 150); + textArea.value = text; + this.tabStruct.index = 0; + } + } + else { + this.tabStruct.index = 0; + } + // prevent the default TAB operation (typically focus shifting) + ev.preventDefault(); + } }; From 42c97662038393e613dca4ebde8e9c02c063ca4b Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 16 Jul 2015 14:39:15 +0100 Subject: [PATCH 048/200] s/did/will/ --- src/controllers/molecules/MessageComposer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/molecules/MessageComposer.js b/src/controllers/molecules/MessageComposer.js index 1012fe375..cdfee2eb8 100644 --- a/src/controllers/molecules/MessageComposer.js +++ b/src/controllers/molecules/MessageComposer.js @@ -26,7 +26,7 @@ var KeyCode = { }; module.exports = { - componentDidMount: function() { + componentWillMount: function() { this.dispatcherRef = dis.register(this.onAction); this.tabStruct = { completing: false, From dac94d2293ffd550180491607c0da45ae08fe423 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 16 Jul 2015 15:15:14 +0100 Subject: [PATCH 049/200] mplement custom registration screen --- skins/base/views/templates/Register.js | 60 +++++++++++++++++++++-- src/controllers/molecules/ServerConfig.js | 18 ++++--- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/skins/base/views/templates/Register.js b/skins/base/views/templates/Register.js index 94f3b9697..1f789860d 100644 --- a/skins/base/views/templates/Register.js +++ b/skins/base/views/templates/Register.js @@ -27,9 +27,18 @@ var RegisterController = require("../../../../src/controllers/templates/Register var ServerConfig = ComponentBroker.get("molecules/ServerConfig"); module.exports = React.createClass({ + DEFAULT_HS_URL: 'https://matrix.org', + DEFAULT_IS_URL: 'https://matrix.org', + displayName: 'Register', mixins: [RegisterController], + getInitialState: function() { + return { + serverConfigVisible: false + }; + }, + getRegFormVals: function() { return { email: this.refs.email.getDOMNode().value, @@ -40,24 +49,65 @@ module.exports = React.createClass({ }, getHsUrl: function() { - return this.refs.serverConfig.getHsUrl(); + if (this.state.serverConfigVisible) { + return this.refs.serverConfig.getHsUrl(); + } else { + return this.DEFAULT_HS_URL; + } }, getIsUrl: function() { - return this.refs.serverConfig.getIsUrl(); + if (this.state.serverConfigVisible) { + return this.refs.serverConfig.getIsUrl(); + } else { + return this.DEFAULT_IS_URL; + } + }, + + onServerConfigVisibleChange: function(ev) { + this.setState({ + serverConfigVisible: ev.target.checked + }); + }, + + getUserIdSuffix: function() { + var actualHsUrl = document.createElement('a'); + actualHsUrl.href = this.getHsUrl(); + var defaultHsUrl = document.createElement('a'); + defaultHsUrl.href = this.DEFAULT_HS_URL; + if (actualHsUrl.host == defaultHsUrl.host) { + return ':matrix.org'; + } + return ''; + }, + + onServerUrlChanged: function(newUrl) { + this.forceUpdate(); }, componentForStep: function(step) { switch (step) { case 'initial': + var serverConfigStyle = {}; + if (!this.state.serverConfigVisible) { + serverConfigStyle.display = 'none'; + } return (
Email:
- Username:
+ Username: {this.getUserIdSuffix()}
Password:
Confirm Password:
- + + + Use custom server options (advanced) +
+ +
+
@@ -87,7 +137,7 @@ module.exports = React.createClass({ } else { return (
-

Create a new account:

+

Create an account

{this.componentForStep(this.state.step)}
{this.state.errorText}
Sign in with existing account diff --git a/src/controllers/molecules/ServerConfig.js b/src/controllers/molecules/ServerConfig.js index 3cd5156ba..3f5dd99bb 100644 --- a/src/controllers/molecules/ServerConfig.js +++ b/src/controllers/molecules/ServerConfig.js @@ -30,26 +30,28 @@ module.exports = { return { onHsUrlChanged: function() {}, onIsUrlChanged: function() {}, - default_hs_url: 'https://matrix.org/', - default_is_url: 'https://matrix.org/' + defaultHsUrl: 'https://matrix.org/', + defaultIsUrl: 'https://matrix.org/' }; }, getInitialState: function() { return { - hs_url: this.props.default_hs_url, - is_url: this.props.default_is_url, + hs_url: this.props.defaultHsUrl, + is_url: this.props.defaultIsUrl, } }, hsChanged: function(ev) { - this.setState({hs_url: ev.target.value}); - this.props.onHsUrlChanged(this.state.hs_url); + this.setState({hs_url: ev.target.value}, function() { + this.props.onHsUrlChanged(this.state.hs_url); + }); }, isChanged: function(ev) { - this.setState({is_url: ev.target.value}); - this.props.onIsUrlChanged(this.state.is_url); + this.setState({is_url: ev.target.value}, function() { + this.props.onIsUrlChanged(this.state.is_url); + }); }, getHsUrl: function() { From 1677a3bf3ad53aa5ca9f1d651b18fe4bc0594dd0 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 16 Jul 2015 15:16:04 +0100 Subject: [PATCH 050/200] text change --- skins/base/views/templates/Register.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skins/base/views/templates/Register.js b/skins/base/views/templates/Register.js index 1f789860d..930228b8b 100644 --- a/skins/base/views/templates/Register.js +++ b/skins/base/views/templates/Register.js @@ -140,7 +140,7 @@ module.exports = React.createClass({

Create an account

{this.componentForStep(this.state.step)}
{this.state.errorText}
- Sign in with existing account + I already have an account
); } From b0438891699597f91141ec544054d36fd2e8d77b Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 16 Jul 2015 15:22:46 +0100 Subject: [PATCH 051/200] Implement sent message history (up/down keys). This includes preserving and restoring partially entered text per room. This is mostly ported straight from Angular. --- src/controllers/molecules/MessageComposer.js | 106 ++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/controllers/molecules/MessageComposer.js b/src/controllers/molecules/MessageComposer.js index cdfee2eb8..38d4a4f42 100644 --- a/src/controllers/molecules/MessageComposer.js +++ b/src/controllers/molecules/MessageComposer.js @@ -22,7 +22,9 @@ var dis = require("../../dispatcher"); var KeyCode = { ENTER: 13, TAB: 9, - SHIFT: 16 + SHIFT: 16, + UP: 38, + DOWN: 40 }; module.exports = { @@ -33,10 +35,105 @@ module.exports = { original: null, index: 0 }; + this.sentHistory = { + // The list of typed messages. Index 0 is more recent + data: [], + // The position in data currently displayed + position: -1, + // The room the history is for. + roomId: null, + // The original text before they hit UP + originalText: null, + // The textarea element to set text to. + element: null, + + init: function(element, roomId) { + this.roomId = roomId; + this.element = element; + this.position = -1; + var storedData = window.sessionStorage.getItem( + "history_" + roomId + ); + if (storedData) { + this.data = JSON.parse(storedData); + } + if (this.roomId) { + this.setLastTextEntry(); + } + }, + + push: function(text) { + // store a message in the sent history + this.data.unshift(text); + window.sessionStorage.setItem( + "history_" + this.roomId, + JSON.stringify(this.data) + ); + // reset history position + this.position = -1; + this.originalText = null; + }, + + // move in the history. Returns true if we managed to move. + next: function(offset) { + if (this.position === -1) { + // user is going into the history, save the current line. + this.originalText = this.element.value; + } + else { + // user may have modified this line in the history; remember it. + this.data[this.position] = this.element.value; + } + + if (offset > 0 && this.position === (this.data.length - 1)) { + // we've run out of history + return false; + } + + // retrieve the next item (bounded). + var newPosition = this.position + offset; + newPosition = Math.max(-1, newPosition); + newPosition = Math.min(newPosition, this.data.length - 1); + this.position = newPosition; + + if (this.position !== -1) { + // show the message + this.element.value = this.data[this.position]; + } + else if (this.originalText) { + // restore the original text the user was typing. + this.element.value = this.originalText; + } + return true; + }, + + saveLastTextEntry: function() { + // save the currently entered text in order to restore it later. + // NB: This isn't 'originalText' because we want to restore + // sent history items too! + var text = this.element.value; + window.sessionStorage.setItem("input_" + this.roomId, text); + }, + + setLastTextEntry: function() { + var text = window.sessionStorage.getItem("input_" + this.roomId); + if (text) { + this.element.value = text; + } + } + }; + }, + + componentDidMount: function() { + this.sentHistory.init( + this.refs.textarea.getDOMNode(), + this.props.room.roomId + ); }, componentWillUnmount: function() { dis.unregister(this.dispatcherRef); + this.sentHistory.saveLastTextEntry(); }, onAction: function(payload) { @@ -49,6 +146,7 @@ module.exports = { onKeyDown: function (ev) { if (ev.keyCode === KeyCode.ENTER) { + this.sentHistory.push(this.refs.textarea.getDOMNode().value); this.onEnter(ev); } else if (ev.keyCode === KeyCode.TAB) { @@ -58,6 +156,12 @@ module.exports = { } this.onTab(ev, members); } + else if (ev.keyCode === KeyCode.UP || ev.keyCode === KeyCode.DOWN) { + this.sentHistory.next( + ev.keyCode === KeyCode.UP ? 1 : -1 + ); + ev.preventDefault(); + } else if (ev.keyCode !== KeyCode.SHIFT && this.tabStruct.completing) { // they're resuming typing; reset tab complete state vars. this.tabStruct.completing = false; From cd26d1323f9f7f13b7ef2d2763ae515d63e56891 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 16 Jul 2015 15:55:46 +0100 Subject: [PATCH 052/200] Wire together checkboxes and presets and use new /createRoom api --- skins/base/views/atoms/create_room/Presets.js | 9 +-- skins/base/views/organisms/CreateRoom.js | 58 ++++++++++++++++++- src/controllers/atoms/create_room/Presets.js | 25 +++++++- .../atoms/create_room/RoomAlias.js | 12 +++- src/controllers/organisms/CreateRoom.js | 33 ++++++++++- 5 files changed, 124 insertions(+), 13 deletions(-) diff --git a/skins/base/views/atoms/create_room/Presets.js b/skins/base/views/atoms/create_room/Presets.js index 83fe61bdb..04e7d34d7 100644 --- a/skins/base/views/atoms/create_room/Presets.js +++ b/skins/base/views/atoms/create_room/Presets.js @@ -25,14 +25,15 @@ module.exports = React.createClass({ mixins: [PresetsController], onValueChanged: function(ev) { - this.setState({preset: ev.target.value}) + this.setState({preset: ev.target.value}, this.props.onChange); }, render: function() { return ( - + + + ); } diff --git a/skins/base/views/organisms/CreateRoom.js b/skins/base/views/organisms/CreateRoom.js index d7e84cccd..ce12630be 100644 --- a/skins/base/views/organisms/CreateRoom.js +++ b/skins/base/views/organisms/CreateRoom.js @@ -22,6 +22,8 @@ var CreateRoomController = require("../../../../src/controllers/organisms/Create var ComponentBroker = require('../../../../src/ComponentBroker'); +var PresetValues = require('../../../../src/controllers/atoms/create_room/Presets').Presets; + var CreateRoomButton = ComponentBroker.get("atoms/create_room/CreateRoomButton"); var RoomNameTextbox = ComponentBroker.get("atoms/create_room/RoomNameTextbox"); var RoomTopic = ComponentBroker.get("atoms/create_room/RoomTopic"); @@ -42,10 +44,57 @@ module.exports = React.createClass({ return this.refs.name_textbox.getName(); }, + getTopic: function() { + return this.refs.topic.getTopic(); + }, + + getAliasLocalpart: function() { + return this.refs.alias.getAliasLocalpart(); + }, + getInvitedUsers: function() { return this.refs.user_selector.getUserIds(); }, + onPresetChanged: function() { + var preset = this.refs.presets.getPreset(); + switch (preset) { + case PresetValues.PrivateChat: + this.setState({ + preset: preset, + is_private: true, + share_history: false, + }); + break; + case PresetValues.PublicChat: + this.setState({ + preset: preset, + is_private: false, + share_history: true, + }); + break; + case PresetValues.Custom: + this.setState({ + preset: preset, + }); + break; + } + }, + + onPrivateChanged: function(ev) { + this.setState({ + preset: PresetValues.Custom, + is_private: ev.target.checked, + }); + }, + + onShareHistoryChanged: function(ev) { + this.setState({ + preset: PresetValues.Custom, + share_history: ev.target.checked, + }); + }, + render: function() { var curr_phase = this.state.phase; if (curr_phase == this.phases.CREATING) { @@ -64,10 +113,13 @@ module.exports = React.createClass({ return (

-
-
-
+
+

+
+ + +
{error_box}
diff --git a/src/controllers/atoms/create_room/Presets.js b/src/controllers/atoms/create_room/Presets.js index 5ff7327e5..976c88db1 100644 --- a/src/controllers/atoms/create_room/Presets.js +++ b/src/controllers/atoms/create_room/Presets.js @@ -18,20 +18,39 @@ limitations under the License. var React = require('react'); +var Presets = { + PrivateChat: "private_chat", + PublicChat: "public_chat", + Custom: "custom", +}; + module.exports = { propTypes: { - default_preset: React.PropTypes.string + onChange: React.PropTypes.func, + default_preset: React.PropTypes.string, + preset: React.PropTypes.string }, + Presets: Presets, + getDefaultProps: function() { return { - default_preset: 'private_chat', + onChange: function() {}, + default_preset: Presets.PrivateChat, }; }, getInitialState: function() { return { - preset: this.props.default_preset, + preset: this.props.preset || this.props.default_preset, + } + }, + + componentWillReceiveProps: function(new_props) { + if (new_props.preset) { + this.setState({ + preset: new_props.preset + }); } }, diff --git a/src/controllers/atoms/create_room/RoomAlias.js b/src/controllers/atoms/create_room/RoomAlias.js index 804b0b29e..7e3e38a5d 100644 --- a/src/controllers/atoms/create_room/RoomAlias.js +++ b/src/controllers/atoms/create_room/RoomAlias.js @@ -35,7 +35,15 @@ module.exports = { } }, - getAlias: function() { - return this.state.room_alias; + getAliasLocalpart: function() { + var room_alias = this.state.room_alias; + + if (room_alias) { + if (room_alias.startsWith("#") && room_alias.endsWith("example.com")) { + room_alias = room_alias.slice(1, -":example.com".length); + } + } + + return room_alias; }, }; diff --git a/src/controllers/organisms/CreateRoom.js b/src/controllers/organisms/CreateRoom.js index 048f36795..6ea2c6004 100644 --- a/src/controllers/organisms/CreateRoom.js +++ b/src/controllers/organisms/CreateRoom.js @@ -18,6 +18,7 @@ limitations under the License. var React = require("react"); var MatrixClientPeg = require("../../MatrixClientPeg"); +var PresetValues = require('../atoms/create_room/Presets').Presets; module.exports = { propTypes: { @@ -41,6 +42,9 @@ module.exports = { return { phase: this.phases.CONFIG, error_string: "", + is_private: true, + share_history: false, + default_preset: PresetValues.PrivateChat }; }, @@ -52,9 +56,31 @@ module.exports = { options.name = room_name; } + var room_topic = this.getTopic(); + if (room_name) { + options.topic = room_topic; + } + var preset = this.getPreset(); if (preset) { - options.preset = preset; + if (preset != PresetValues.Custom) { + options.preset = preset; + } else { + options.initial_state = [ + { + type: "m.room.join_rules", + content: { + "join_rules": this.state.is_private ? "invite" : "public" + } + }, + { + type: "m.room.history_visibility", + content: { + "history_visibility": this.state.share_history ? "shared" : "invited" + } + }, + ]; + } } var invited_users = this.getInvitedUsers(); @@ -62,6 +88,11 @@ module.exports = { options.invite = invited_users; } + var alias = this.getAliasLocalpart(); + if (alias) { + options.room_alias_name = alias; + } + var cli = MatrixClientPeg.get(); if (!cli) { // TODO: Error. From ebe6072225fe4aaa58ed1fd875a49e4b6134fcd2 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 16 Jul 2015 16:04:12 +0100 Subject: [PATCH 053/200] Make this a done so it doesn't swallow exceptions --- src/controllers/templates/Login.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/templates/Login.js b/src/controllers/templates/Login.js index 1c0559708..1b1f94cf9 100644 --- a/src/controllers/templates/Login.js +++ b/src/controllers/templates/Login.js @@ -72,7 +72,7 @@ module.exports = { MatrixClientPeg.get().login('m.login.password', { 'user': that.refs.user.getDOMNode().value, 'password': that.refs.pass.getDOMNode().value - }).then(function(data) { + }).done(function(data) { // XXX: we assume this means we're logged in, but there could be a next stage MatrixClientPeg.replace(Matrix.createClient({ baseUrl: that.state.hs_url, From 95968bf619e0783cc195d932c2be843bfc66ba3a Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 16 Jul 2015 16:14:55 +0100 Subject: [PATCH 054/200] Make server_name magix in RoomAlias optional --- .../base/views/atoms/create_room/RoomAlias.js | 48 +++++++++++-------- .../atoms/create_room/RoomAlias.js | 8 ++-- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/skins/base/views/atoms/create_room/RoomAlias.js b/skins/base/views/atoms/create_room/RoomAlias.js index f60ec6b32..fd0789b99 100644 --- a/skins/base/views/atoms/create_room/RoomAlias.js +++ b/skins/base/views/atoms/create_room/RoomAlias.js @@ -32,34 +32,40 @@ module.exports = React.createClass({ var target = ev.target; var curr_val = ev.target.value; - if (curr_val == "") { - target.value = "#:example.com"; - setTimeout(function() { - target.setSelectionRange(1, 1); - }, 0); - } else { - setTimeout(function() { - target.setSelectionRange( - curr_val.startsWith("#") ? 1 : 0, - curr_val.endsWith(":example.com") ? (target.value.length - ":example.com".length) : target.value.length - ); - }, 0); + if (this.props.homeserver) { + if (curr_val == "") { + setTimeout(function() { + target.value = "#:" + this.props.homeserver; + target.setSelectionRange(1, 1); + }, 0); + } else { + var suffix = ":" + this.props.homeserver; + setTimeout(function() { + target.setSelectionRange( + curr_val.startsWith("#") ? 1 : 0, + curr_val.endsWith(suffix) ? (target.value.length - suffix.length) : target.value.length + ); + }, 0); + } } }, onBlur: function(ev) { var curr_val = ev.target.value; - if (curr_val == "#:example.com") { - ev.target.value = ""; - return; - } + if (this.props.homeserver) { + if (curr_val == "#:" + this.props.homeserver) { + ev.target.value = ""; + return; + } - if (curr_val != "") { - var new_val = ev.target.value; - if (!curr_val.startsWith("#")) new_val = "#" + new_val; - if (!curr_val.endsWith(":example.com")) new_val = new_val + ":example.com"; - ev.target.value = new_val; + if (curr_val != "") { + var new_val = ev.target.value; + var suffix = ":" + this.props.homeserver; + if (!curr_val.startsWith("#")) new_val = "#" + new_val; + if (!curr_val.endsWith(suffix)) new_val = new_val + suffix; + ev.target.value = new_val; + } } }, diff --git a/src/controllers/atoms/create_room/RoomAlias.js b/src/controllers/atoms/create_room/RoomAlias.js index 7e3e38a5d..6aff89479 100644 --- a/src/controllers/atoms/create_room/RoomAlias.js +++ b/src/controllers/atoms/create_room/RoomAlias.js @@ -20,6 +20,7 @@ var React = require('react'); module.exports = { propTypes: { + homeserver: React.PropTypes.string, default_alias: React.PropTypes.string }, @@ -38,9 +39,10 @@ module.exports = { getAliasLocalpart: function() { var room_alias = this.state.room_alias; - if (room_alias) { - if (room_alias.startsWith("#") && room_alias.endsWith("example.com")) { - room_alias = room_alias.slice(1, -":example.com".length); + if (room_alias && this.props.homeserver) { + var suffix = ":" + this.props.homeserver; + if (room_alias.startsWith("#") && room_alias.endsWith(suffix)) { + room_alias = room_alias.slice(1, -suffix.length); } } From ebedf0b907a92163509759367f7a3bce96741f13 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 16 Jul 2015 16:17:29 +0100 Subject: [PATCH 055/200] Add comment about RoomAlias magic --- src/controllers/atoms/create_room/RoomAlias.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controllers/atoms/create_room/RoomAlias.js b/src/controllers/atoms/create_room/RoomAlias.js index 6aff89479..2496179a8 100644 --- a/src/controllers/atoms/create_room/RoomAlias.js +++ b/src/controllers/atoms/create_room/RoomAlias.js @@ -20,6 +20,8 @@ var React = require('react'); module.exports = { propTypes: { + // Specifying a homeserver will make magical things happen when you, + // e.g. start typing in the room alias box. homeserver: React.PropTypes.string, default_alias: React.PropTypes.string }, From 47f4c0dfff712624f783c5cc3090a0c7f2b03be8 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 16 Jul 2015 16:20:00 +0100 Subject: [PATCH 056/200] Use Loader --- skins/base/views/organisms/CreateRoom.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/skins/base/views/organisms/CreateRoom.js b/skins/base/views/organisms/CreateRoom.js index ce12630be..7d2e35498 100644 --- a/skins/base/views/organisms/CreateRoom.js +++ b/skins/base/views/organisms/CreateRoom.js @@ -31,6 +31,8 @@ var RoomAlias = ComponentBroker.get("atoms/create_room/RoomAlias"); var Presets = ComponentBroker.get("atoms/create_room/Presets"); var UserSelector = ComponentBroker.get("molecules/UserSelector"); +var Loader = require("react-loader"); + module.exports = React.createClass({ displayName: 'CreateRoom', @@ -99,7 +101,7 @@ module.exports = React.createClass({ var curr_phase = this.state.phase; if (curr_phase == this.phases.CREATING) { return ( -
Creating...
+ ); } else { var error_box = ""; From 6b81022e2838bb3219701ea369b3c97fcd057b60 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 16 Jul 2015 16:32:11 +0100 Subject: [PATCH 057/200] Move position of incoming call buttons. --- skins/base/views/molecules/RoomHeader.js | 12 ---- .../views/molecules/voip/IncomingCallBox.js | 56 ++++++++++++++++ skins/base/views/organisms/LeftPanel.js | 2 + src/ComponentBroker.js | 1 + src/controllers/molecules/RoomHeader.js | 6 -- .../molecules/voip/IncomingCallBox.js | 66 +++++++++++++++++++ 6 files changed, 125 insertions(+), 18 deletions(-) create mode 100644 skins/base/views/molecules/voip/IncomingCallBox.js create mode 100644 src/controllers/molecules/voip/IncomingCallBox.js diff --git a/skins/base/views/molecules/RoomHeader.js b/skins/base/views/molecules/RoomHeader.js index 1708bd1c3..62f244845 100644 --- a/skins/base/views/molecules/RoomHeader.js +++ b/skins/base/views/molecules/RoomHeader.js @@ -33,18 +33,6 @@ module.exports = React.createClass({ var callButtons; if (this.state) { switch (this.state.call_state) { - case "ringing": - callButtons = ( -
-
- YUP -
-
- NOPE -
-
- ); - break; case "ringback": case "connected": callButtons = ( diff --git a/skins/base/views/molecules/voip/IncomingCallBox.js b/skins/base/views/molecules/voip/IncomingCallBox.js new file mode 100644 index 000000000..95263fb6c --- /dev/null +++ b/skins/base/views/molecules/voip/IncomingCallBox.js @@ -0,0 +1,56 @@ +/* +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 classNames = require('classnames'); +var IncomingCallBoxController = require( + "../../../../../src/controllers/molecules/voip/IncomingCallBox" +); + +module.exports = React.createClass({ + displayName: 'IncomingCallBox', + mixins: [IncomingCallBoxController], + + render: function() { + if (!this.state.incomingCallRoomId) { + return ( +
+ ); + } + return ( +
+
+ +
+
+ General Incoming Call +
+
+
+ Decline +
+
+ Accept +
+
+
+ ); + } +}); diff --git a/skins/base/views/organisms/LeftPanel.js b/skins/base/views/organisms/LeftPanel.js index 8a9770da6..f8df727d7 100644 --- a/skins/base/views/organisms/LeftPanel.js +++ b/skins/base/views/organisms/LeftPanel.js @@ -21,6 +21,7 @@ var ComponentBroker = require('../../../../src/ComponentBroker'); var RoomList = ComponentBroker.get('organisms/RoomList'); var DirectoryMenu = ComponentBroker.get('molecules/DirectoryMenu'); +var IncomingCallBox = ComponentBroker.get('molecules/voip/IncomingCallBox'); var RoomCreate = ComponentBroker.get('molecules/RoomCreate'); module.exports = React.createClass({ @@ -30,6 +31,7 @@ module.exports = React.createClass({ return (
< +
diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js index 59f880464..d2275ef86 100644 --- a/src/ComponentBroker.js +++ b/src/ComponentBroker.js @@ -101,6 +101,7 @@ require('../skins/base/views/molecules/DirectoryMenu'); require('../skins/base/views/atoms/voip/VideoFeed'); require('../skins/base/views/molecules/voip/VideoView'); require('../skins/base/views/molecules/voip/CallView'); +require('../skins/base/views/molecules/voip/IncomingCallBox'); require('../skins/base/views/molecules/voip/MCallInviteTile'); require('../skins/base/views/molecules/voip/MCallAnswerTile'); require('../skins/base/views/molecules/voip/MCallHangupTile'); diff --git a/src/controllers/molecules/RoomHeader.js b/src/controllers/molecules/RoomHeader.js index 24f0d47ab..5bd51e44d 100644 --- a/src/controllers/molecules/RoomHeader.js +++ b/src/controllers/molecules/RoomHeader.js @@ -76,12 +76,6 @@ module.exports = { action: 'hangup', room_id: this.props.room.roomId }); - }, - onAnswerClick: function() { - dis.dispatch({ - action: 'answer', - room_id: this.props.room.roomId - }); } }; diff --git a/src/controllers/molecules/voip/IncomingCallBox.js b/src/controllers/molecules/voip/IncomingCallBox.js new file mode 100644 index 000000000..dc993936b --- /dev/null +++ b/src/controllers/molecules/voip/IncomingCallBox.js @@ -0,0 +1,66 @@ +/* +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 dis = require("../../../dispatcher"); +var CallHandler = require("../../../CallHandler"); + +module.exports = { + componentDidMount: function() { + this.dispatcherRef = dis.register(this.onAction); + }, + + componentWillUnmount: function() { + dis.unregister(this.dispatcherRef); + }, + + getInitialState: function() { + return { + incomingCallRoomId: null + } + }, + + onAction: function(payload) { + if (payload.action !== 'call_state') { + return; + } + var call = CallHandler.getCall(payload.room_id); + if (!call || call.call_state !== 'ringing') { + this.setState({ + incomingCallRoomId: null + }); + return; + } + this.setState({ + incomingCallRoomId: call.roomId + }); + }, + + onAnswerClick: function() { + dis.dispatch({ + action: 'answer', + room_id: this.state.incomingCallRoomId + }); + }, + onRejectClick: function() { + dis.dispatch({ + action: 'hangup', + room_id: this.state.incomingCallRoomId + }); + } +}; + From aa1b763518036c6a5cd611cf8d7300791ec22ae7 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 16 Jul 2015 17:20:03 +0100 Subject: [PATCH 058/200] Make CreateRoom remember what the values of its fields were. Remove some fairly pointless atoms --- .../base/views/atoms/create_room/RoomAlias.js | 5 ++- .../atoms/create_room/RoomNameTextbox.js | 36 ---------------- .../base/views/atoms/create_room/RoomTopic.js | 37 ----------------- skins/base/views/molecules/UserSelector.js | 2 +- skins/base/views/organisms/CreateRoom.js | 32 +++++++++++++-- .../atoms/create_room/RoomAlias.js | 14 +++---- .../atoms/create_room/RoomNameTextbox.js | 41 ------------------- .../atoms/create_room/RoomTopic.js | 41 ------------------- src/controllers/molecules/UserSelector.js | 30 ++++---------- src/controllers/organisms/CreateRoom.js | 20 ++++----- 10 files changed, 55 insertions(+), 203 deletions(-) delete mode 100644 skins/base/views/atoms/create_room/RoomNameTextbox.js delete mode 100644 skins/base/views/atoms/create_room/RoomTopic.js delete mode 100644 src/controllers/atoms/create_room/RoomNameTextbox.js delete mode 100644 src/controllers/atoms/create_room/RoomTopic.js diff --git a/skins/base/views/atoms/create_room/RoomAlias.js b/skins/base/views/atoms/create_room/RoomAlias.js index fd0789b99..a59a8e69a 100644 --- a/skins/base/views/atoms/create_room/RoomAlias.js +++ b/skins/base/views/atoms/create_room/RoomAlias.js @@ -25,7 +25,7 @@ module.exports = React.createClass({ mixins: [RoomAliasController], onValueChanged: function(ev) { - this.setState({room_alias: ev.target.value}) + this.props.onChange(ev.target.value); }, onFocus: function(ev) { @@ -72,7 +72,8 @@ module.exports = React.createClass({ render: function() { return ( + onChange={this.onValueChanged} onFocus={this.onFocus} onBlur={this.onBlur} + value={this.props.alias}/> ); } }); diff --git a/skins/base/views/atoms/create_room/RoomNameTextbox.js b/skins/base/views/atoms/create_room/RoomNameTextbox.js deleted file mode 100644 index 038d39a93..000000000 --- a/skins/base/views/atoms/create_room/RoomNameTextbox.js +++ /dev/null @@ -1,36 +0,0 @@ -/* -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/atoms/create_room/RoomTopic.js b/skins/base/views/atoms/create_room/RoomTopic.js deleted file mode 100644 index 134833f90..000000000 --- a/skins/base/views/atoms/create_room/RoomTopic.js +++ /dev/null @@ -1,37 +0,0 @@ -/* -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 RoomTopicController = require("../../../../../src/controllers/atoms/create_room/RoomTopic"); - -module.exports = React.createClass({ - displayName: 'RoomTopic', - mixins: [RoomTopicController], - - onValueChanged: function(ev) { - this.setState({room_topic: ev.target.value}) - }, - - render: function() { - return ( - - ); - } -}); diff --git a/skins/base/views/molecules/UserSelector.js b/skins/base/views/molecules/UserSelector.js index 7517e29d0..81afa5f4e 100644 --- a/skins/base/views/molecules/UserSelector.js +++ b/skins/base/views/molecules/UserSelector.js @@ -32,7 +32,7 @@ module.exports = React.createClass({ return (
    - {this.state.selected_users.map(function(user_id, i) { + {this.props.selected_users.map(function(user_id, i) { return
  • {user_id}
  • })}
diff --git a/skins/base/views/organisms/CreateRoom.js b/skins/base/views/organisms/CreateRoom.js index 7d2e35498..fa6d55f25 100644 --- a/skins/base/views/organisms/CreateRoom.js +++ b/skins/base/views/organisms/CreateRoom.js @@ -97,6 +97,30 @@ module.exports = React.createClass({ }); }, + onTopicChange: function(ev) { + this.setState({ + topic: ev.target.value, + }); + }, + + onNameChange: function(ev) { + this.setState({ + room_name: ev.target.value, + }); + }, + + onInviteChanged: function(invited_users) { + this.setState({ + invited_users: invited_users, + }); + }, + + onAliasChanged: function(alias) { + this.setState({ + alias: alias + }) + }, + render: function() { var curr_phase = this.state.phase; if (curr_phase == this.phases.CREATING) { @@ -114,10 +138,10 @@ module.exports = React.createClass({ } return (
-
-
-
-
+
+
+ save_button = ( +
+ Save +
+ ); + } else { + name = ; + if (topic) topic_el =
{ topic.getContent().topic }
; + settings_button = ( +
+ +
+ ); + } + return (
@@ -61,15 +86,14 @@ module.exports = React.createClass({
- + { name }
- { topic } + { topic_el }
-
- -
+ { save_button } + { settings_button }
diff --git a/skins/base/views/organisms/RoomView.js b/skins/base/views/organisms/RoomView.js index a93937f0b..3e1fb6c66 100644 --- a/skins/base/views/organisms/RoomView.js +++ b/skins/base/views/organisms/RoomView.js @@ -28,6 +28,7 @@ var MessageTile = ComponentBroker.get('molecules/MessageTile'); var RoomHeader = ComponentBroker.get('molecules/RoomHeader'); var MessageComposer = ComponentBroker.get('molecules/MessageComposer'); var CallView = ComponentBroker.get("molecules/voip/CallView"); +var RoomSettings = ComponentBroker.get("molecules/RoomSettings"); var RoomViewController = require("../../../../src/controllers/organisms/RoomView"); @@ -38,6 +39,68 @@ module.exports = React.createClass({ displayName: 'RoomView', mixins: [RoomViewController], + onSettingsClick: function() { + this.setState({editingRoomSettings: true}); + }, + + onSaveClick: function() { + this.setState({editingRoomSettings: false}); + + var new_name = this.refs.header.getRoomName(); + var new_topic = this.refs.room_settings.getTopic(); + var new_join_rule = this.refs.room_settings.getJoinRules(); + var new_history_visibility = this.refs.room_settings.getHistoryVisibility(); + + var old_name = this.state.room.name; + + var old_topic = this.state.room.currentState.getStateEvents('m.room.topic', ''); + if (old_topic) { + old_topic = old_topic.getContent().topic; + } else { + old_topic = ""; + } + + var old_join_rule = this.state.room.currentState.getStateEvents('m.room.join_rules', ''); + if (old_join_rule) { + old_join_rule = old_join_rule.getContent().join_rule; + } else { + old_join_rule = "invite"; + } + + var old_history_visibility = this.state.room.currentState.getStateEvents('m.room.history_visibility', ''); + console.log(old_history_visibility); + if (old_history_visibility) { + old_history_visibility = old_history_visibility.getContent().history_visibility; + } else { + old_history_visibility = "shared"; + } + + + if (old_name != new_name && new_name != undefined) { + MatrixClientPeg.get().setRoomName(this.state.room.roomId, new_name); + } + + if (old_topic != new_topic && new_topic != undefined) { + MatrixClientPeg.get().setRoomTopic(this.state.room.roomId, new_topic); + } + + if (old_join_rule != new_join_rule && new_join_rule != undefined) { + MatrixClientPeg.get().sendStateEvent( + this.state.room.roomId, "m.room.join_rules", { + join_rule: new_join_rule, + }, "" + ); + } + + if (old_history_visibility != new_history_visibility && new_history_visibility != undefined) { + MatrixClientPeg.get().sendStateEvent( + this.state.room.roomId, "m.room.history_visibility", { + history_visibility: new_history_visibility, + }, "" + ); + } + }, + render: function() { if (!this.state.room) { return ( @@ -103,11 +166,19 @@ module.exports = React.createClass({ } } + var roomEdit = null; + + if (this.state.editingRoomSettings) { + roomEdit = ; + } + return (
- +
+ { roomEdit }
@@ -129,4 +200,3 @@ module.exports = React.createClass({ } }, }); - diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js index 8a7bd6632..56164d3d4 100644 --- a/src/ComponentBroker.js +++ b/src/ComponentBroker.js @@ -92,6 +92,7 @@ require('../skins/base/views/molecules/UserSelector'); require('../skins/base/views/organisms/UserSettings'); require('../skins/base/views/molecules/ChangeAvatar'); require('../skins/base/views/molecules/ChangePassword'); +require('../skins/base/views/molecules/RoomSettings'); // new for vector require('../skins/base/views/organisms/LeftPanel'); require('../skins/base/views/organisms/RightPanel'); diff --git a/src/controllers/molecules/RoomHeader.js b/src/controllers/molecules/RoomHeader.js index 5bd51e44d..2ef99953d 100644 --- a/src/controllers/molecules/RoomHeader.js +++ b/src/controllers/molecules/RoomHeader.js @@ -21,10 +21,25 @@ limitations under the License. * this.state.call_state = the UI state of the call (see CallHandler) */ +var React = require('react'); var dis = require("../../dispatcher"); var CallHandler = require("../../CallHandler"); module.exports = { + propTypes: { + room: React.PropTypes.object.isRequired, + editing: React.PropTypes.bool, + onSettingsClick: React.PropTypes.func, + onSaveClick: React.PropTypes.func, + }, + + getDefaultProps: function() { + return { + editing: false, + onSettingsClick: function() {}, + onSaveClick: function() {}, + }; + }, componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); @@ -43,7 +58,7 @@ module.exports = { onAction: function(payload) { // if we were given a room_id to track, don't handle anything else. - if (payload.room_id && this.props.room && + if (payload.room_id && this.props.room && this.props.room.roomId !== payload.room_id) { return; } @@ -78,4 +93,3 @@ module.exports = { }); } }; - diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js index a5bae7542..4f6c4d3cd 100644 --- a/src/controllers/organisms/RoomView.js +++ b/src/controllers/organisms/RoomView.js @@ -44,7 +44,8 @@ module.exports = { getInitialState: function() { return { room: this.props.roomId ? MatrixClientPeg.get().getRoom(this.props.roomId) : null, - messageCap: INITIAL_SIZE + messageCap: INITIAL_SIZE, + editingRoomSettings: false, } }, @@ -99,7 +100,7 @@ module.exports = { // we'll only be showing a spinner. if (this.state.joining) return; if (room.roomId != this.props.roomId) return; - + if (this.refs.messageWrapper) { var messageWrapper = this.refs.messageWrapper.getDOMNode(); this.atBottom = messageWrapper.scrollHeight - messageWrapper.scrollTop <= messageWrapper.clientHeight; @@ -300,7 +301,7 @@ module.exports = { dateSeparator = ; continuation = false; } - } + } if (!TileType) continue; ret.unshift( @@ -313,4 +314,3 @@ module.exports = { return ret; } }; - From 05d9afc040dc24e9b883dab091eeb2ac32e31cc4 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 20 Jul 2015 08:23:55 -0700 Subject: [PATCH 151/200] don't depend on google for fonts, given i'm on inflight wifi... --- examples/trivial/index.html | 2 +- ...ANxSmnAhzbFH8PgLUuEpTyoUstqEm5AMlJo4.woff2 | Bin 0 -> 18908 bytes ...rk_5HEcCpYdJu8BTbgVql8nDJpwnrE27mub0.woff2 | Bin 0 -> 2768 bytes ...I1cMoAHxvl0w9LVKPGs1ZzpMvnHX-7fPOuAc.woff2 | Bin 0 -> 3380 bytes skins/base/fonts/Lato.css | 48 ++++++++++++++++++ ...Q_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2 | Bin 0 -> 16436 bytes ...1C_tIEuLEmicLmwLUuEpTyoUstqEm5AMlJo4.woff2 | Bin 0 -> 16392 bytes ...Xi8zxUjnybc2ZQFKPGs1ZzpMvnHX-7fPOuAc.woff2 | Bin 0 -> 2808 bytes 8 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 skins/base/fonts/22JRxvfANxSmnAhzbFH8PgLUuEpTyoUstqEm5AMlJo4.woff2 create mode 100644 skins/base/fonts/8qcEw_nrk_5HEcCpYdJu8BTbgVql8nDJpwnrE27mub0.woff2 create mode 100644 skins/base/fonts/IY9HZVvI1cMoAHxvl0w9LVKPGs1ZzpMvnHX-7fPOuAc.woff2 create mode 100644 skins/base/fonts/Lato.css create mode 100644 skins/base/fonts/MDadn8DQ_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2 create mode 100644 skins/base/fonts/MgNNr5y1C_tIEuLEmicLmwLUuEpTyoUstqEm5AMlJo4.woff2 create mode 100644 skins/base/fonts/rZPI2gHXi8zxUjnybc2ZQFKPGs1ZzpMvnHX-7fPOuAc.woff2 diff --git a/examples/trivial/index.html b/examples/trivial/index.html index cc77b1e34..1258b78af 100644 --- a/examples/trivial/index.html +++ b/examples/trivial/index.html @@ -3,7 +3,7 @@ vector - +