Compare commits

...

527 Commits

Author SHA1 Message Date
David Baker
3db86b1f59 changelog 2015-10-28 18:37:53 +00:00
David Baker
5c77395faa v0.1.2 2015-10-28 18:32:13 +00:00
David Baker
74afa710d1 Merge branch 'develop' 2015-10-28 18:27:33 +00:00
David Baker
e48e636c44 Bump js-sdk & react-sdk deps 2015-10-28 18:27:09 +00:00
David Baker
4118c05d15 Unused variables 2015-10-28 16:23:48 +00:00
David Baker
cee37c4152 Port react-sdk 2365fe8c over to vector's fork of the roomlist controller 2015-10-28 15:17:03 +00:00
Kegsay
4175dcd102 Merge pull request #260 from vector-im/inbound-audio
Fix inbound audio
2015-10-28 11:43:52 +00:00
Kegan Dougal
35862e0c66 Explicitly make React use the same audio element.. Use a 'key' and comment why it is required. 2015-10-28 11:43:13 +00:00
Kegsay
424d1b84db Merge pull request #264 from vector-im/246-start-chat-ui-feedback
Show a spinner if creating a room on "Start chat" click
2015-10-28 11:38:52 +00:00
Kegsay
3423a493e7 Merge pull request #265 from vector-im/230-exit-full-screen-voip
Exit full screen programatically when the remote side hangs up
2015-10-28 11:36:18 +00:00
Kegan Dougal
731ad26be4 Exit full screen programatically when the remote side hangs up 2015-10-27 17:45:47 +00:00
Kegan Dougal
9dfd0bc3bb Show a spinner if creating a room on "Start chat" click
Use a gif instead of 'orrible CSS spinners which are CPU hungry. Encapsulate
it in a very basic Spinner atom.
2015-10-27 16:56:37 +00:00
Kegan Dougal
05dba9c2d4 Fix inbound audio
This was caused by an <img> being the first thing in the <div> rather than
the <audio>. This caused a conflict because the "not in call" render was just
<div><audio /></div> and "in call" render was <div><img /> <audio /></div>

React can't tell in this case that the <audio> tags are the "same" so was
clobbering it (which meant that on inbound calls we would call play() on an
audio tag which would then immediately be clobbered by another audio tag).
2015-10-27 12:59:04 +00:00
Kegsay
ed52bc37b2 Merge pull request #259 from vector-im/linkify-userids
Add linkify handlers
2015-10-27 12:25:26 +00:00
Kegan Dougal
99e8a54a27 Add linkify handlers 2015-10-27 10:46:18 +00:00
Kegsay
9455d02d50 Merge pull request #237 from vector-im/kegan/delete-empty-files
Remove empty files
2015-10-27 10:19:05 +00:00
Kegan Dougal
c98f7f926a Remove stuff that was merged from working space 2015-10-27 10:18:43 +00:00
Kegan Dougal
c91b642a8b Merge branch 'develop' into kegan/delete-empty-files
Conflicts:
	src/skins/vector/views/molecules/EventAsTextTile.js
2015-10-27 09:19:08 +00:00
Kegsay
ce33c8cdf6 Merge pull request #258 from vector-im/desktop-notification-spam
Add a tag to notifications so they can clobber.
2015-10-27 09:17:45 +00:00
Kegan Dougal
58bac0fbdc Add a tag to notifications so they can clobber. Fixes #159.
This is the same fix we applied to angular to fix this problem in SYWEB-21.
2015-10-26 16:56:44 +00:00
David Baker
9217ae8fbb Fix event listener leak 2015-10-26 10:30:12 +00:00
Matthew Hodgson
e580cb809d spell out how to set up the deps when developing 2015-10-25 12:33:23 +00:00
Matthew Hodgson
5844fb4020 spell out that developers need to use npm link 2015-10-25 11:56:29 +00:00
Matthew Hodgson
8257f325c4 s/getMembersWithMemership/getMembersWithMembership/ 2015-10-25 11:51:17 +00:00
Matthew Hodgson
379fed813e actually use the config file for default HS and IS URLs... 2015-10-25 02:44:57 +00:00
Matthew Hodgson
1188c4c69f Merge pull request #243 from vector-im/kegan/reg-errors-176
Fix #176 Password complexity error message
2015-10-25 02:12:21 +00:00
Matthew Hodgson
88dd135b5a Merge pull request #241 from vector-im/kegan/redact-messages
Hook up delete button on contextual menu (#56)
2015-10-25 02:12:11 +00:00
David Baker
5392afdec4 Add UI for changing room avatars and update UI when room avatars change 2015-10-23 17:36:02 +01:00
David Baker
e844b7aa21 UI to set Room Avatars 2015-10-23 13:47:32 +01:00
David Baker
d66427ddde Relative-ize paths in webpack config: they're supposed to be relative but sometimes they aren't. 2015-10-23 10:16:00 +01:00
David Baker
f618585bd6 Merge branch 'develop' of github.com:vector-im/vector-web into develop 2015-10-23 09:25:15 +01:00
David Baker
7c6fb36520 Let the tile contents specify whether it requires a sender profile or not. Fixes #250. 2015-10-23 09:24:25 +01:00
Matthew Hodgson
351a94b4a1 oops - wrong branch
Revert "WIP of new CSS"

This reverts commit ad4e3418ff.
2015-10-23 02:38:32 +01:00
Matthew Hodgson
ad4e3418ff WIP of new CSS 2015-10-23 02:32:49 +01:00
Matthew Hodgson
82affac438 oops, typo 2015-10-22 16:33:53 +01:00
David Baker
08270b26ee Do room avatars properly. 2015-10-22 13:10:02 +01:00
David Baker
4b645bcd66 Make context menus point the right way 2015-10-21 19:02:02 +01:00
David Baker
1f3a6e408c Factor out stuff commnon to all timeline events into EventTile: makes timestamp & edit button etc appear on everything, not just messages. 2015-10-21 17:52:34 +01:00
Kegan Dougal
3779ff7691 Handle Length case. Add default case and whine loudly. 2015-10-21 17:45:53 +01:00
Kegan Dougal
3d3680e42f NPE fix when accessing event.sender 2015-10-21 16:11:47 +01:00
Kegan Dougal
af67df4c4a Hook up delete button on contextual menu (#56) 2015-10-21 15:52:35 +01:00
Matthew Hodgson
bf40011815 prettier file upload 2015-10-21 15:30:18 +01:00
Kegan Dougal
a9b093b7f5 Remove empty controllers 2015-10-21 15:30:04 +01:00
Kegan Dougal
5e7bd1e51f Remove empty files 2015-10-21 15:17:03 +01:00
David Baker
7142ea8f1e Redundant onclick 2015-10-21 11:15:27 +01:00
Matthew Hodgson
c8f6d46c8b add remoteAudioElement 2015-10-21 01:23:15 +01:00
Matthew Hodgson
5d1ad4d259 only show the zoom button on video calls 2015-10-21 01:23:15 +01:00
David Baker
006f0b00c6 Try refing the container using a functiob as it currently seems to be endinh up with no refs some of the time 2015-10-20 18:23:27 +01:00
David Baker
fe0707535c binding makes no difference - put a null check in to catch the rogue exception 2015-10-20 17:46:11 +01:00
David Baker
044c75270f This has changed in newer react sdk but in master, it should be state.memberDict 2015-10-20 12:41:16 +01:00
David Baker
209889210b Remove unnececessary and wrong null check 2015-10-20 12:36:10 +01:00
David Baker
93d81d27ba fix memberDict reference 2015-10-20 12:32:40 +01:00
David Baker
da6c5653b1 Try binding actin handler 2015-10-20 12:13:31 +01:00
Matthew Hodgson
79eda12656 doh 2015-10-20 12:10:31 +01:00
Kegan Dougal
c74f7c956f Fix missing getAvatarUrlForMember 2015-10-20 11:49:21 +01:00
Matthew Hodgson
137439243a fix layout 2015-10-20 11:49:08 +01:00
Matthew Hodgson
bb5895c157 move mute state into the existing voice/video buttons for now. move zoom button to that set for now 2015-10-20 11:30:54 +01:00
David Baker
34ad48a5d3 Wire up fullscreen button. Requires react-sdk with sync flag to dispatcher. 2015-10-20 11:03:32 +01:00
David Baker
078134d481 Add fullscreen button (not wired up to anything) 2015-10-20 10:48:08 +01:00
Kegan Dougal
f882ecc31b 'center' the buttons just like the cog/video/voice buttons are. 2015-10-20 10:22:23 +01:00
Kegan Dougal
d302f3eebb Add in voip mute video/audio skin. Needs a bit more CSS tweaks. 2015-10-20 09:55:41 +01:00
David Baker
bdbfc2b6e0 Add the little edit widgets and make those the things that bring up the message context menus. Still need to add them to all event tiles and make the context menus point the right way. 2015-10-19 19:30:04 +01:00
Matthew Hodgson
f256f79418 accidental regression that was causing the room list to scroll horizontally 2015-10-19 18:27:21 +01:00
Matthew Hodgson
d1cda75c8b Date refinements. Show more detailed timestamps for older messages, and try to show a separator as the first message in every room 2015-10-19 18:19:26 +01:00
Matthew Hodgson
530b077a8e reimplement 1a95148dae which somehow got lost during refactoring vector-web into matrix-react-sdk and vector-web 2015-10-19 17:13:51 +01:00
David Baker
11aa6f8c37 Null check userId on member. Fixes #5. 2015-10-19 14:33:45 +01:00
David Baker
e3e49daddb Make 'view source' work 2015-10-15 14:41:12 +01:00
David Baker
4b904d90f2 Slightly improve source path tree in the browser debugger 2015-10-15 14:40:36 +01:00
David Baker
48924a6106 Change resend buttons to a context menu with working resending and non-working 'view source' 2015-10-15 14:14:33 +01:00
David Baker
2adb8bac5c Actually turn on production mode: env vars need to be explicitly passed through 2015-10-14 09:20:18 +01:00
David Baker
c0938f270e Unused code 2015-10-13 16:03:07 +01:00
David Baker
47c1bb35db Un-break member hovering 2015-10-13 15:17:20 +01:00
David Baker
7598be684c Merge pull request #198 from stevenhammerton/sh-cas-auth
Add support for CAS auth
2015-10-13 14:26:03 +01:00
David Baker
1dd707775a Use new js-sdk modified time to avoid unnecessary member tile updates. Also avoid double-updating since we were setting state and then forcing an update which is redundant. 2015-10-13 11:10:43 +01:00
Steven Hammerton
293ee1bbcb Fix typo in comment and remove console.log leftover from debugging 2015-10-12 17:41:56 +01:00
Steven Hammerton
b5357d3298 Remove whitespace 2015-10-12 10:28:39 +01:00
Steven Hammerton
c561647460 Add missing comma 2015-10-12 10:27:45 +01:00
Steven Hammerton
f5039ac9af Use node querystring module to parse query string like name value pairs from fragment 2015-10-12 10:27:21 +01:00
Steven Hammerton
353af6c647 Move CasLogin logic to controller class and logic object in react-sdk 2015-10-12 10:27:16 +01:00
Matthew Hodgson
17c81c1101 icons 2015-10-11 22:51:00 +01:00
Matthew Hodgson
50ebce69b7 make file upload look slightly less crap 2015-10-11 18:42:54 +01:00
Matthew Hodgson
191d56673b fix message spacing on Safari caused by switching back to <li/>s... 2015-10-11 18:21:36 +01:00
Matthew Hodgson
5d962e1feb improve horizontal flexing of timeline 2015-10-11 18:04:01 +01:00
Matthew Hodgson
201caed773 fix rubberband bounce on OSX and iOS 2015-10-11 17:50:24 +01:00
Matthew Hodgson
9be98058b7 fix horizontal overscroll 2015-10-11 17:50:16 +01:00
Matthew Hodgson
ba0ae5ba59 various cosmetic fixes based on design feedback 2015-10-11 17:28:36 +01:00
Matthew Hodgson
9a8a9a4ce4 track RHS collapse state, and implement a basic responsive design 2015-10-11 16:09:46 +01:00
Matthew Hodgson
b05f3343e2 tooltipize BottomLeftMenu too for consistency 2015-10-11 15:00:43 +01:00
Matthew Hodgson
ae506b5b1f fix cursor for unhide LHS button 2015-10-11 13:56:25 +01:00
Matthew Hodgson
93de2307c1 improve collapsed LHS implementation - split the tooltip into its own component; position it with javascript as overflow-y + position absolute = clipping hell; preserve the collapse state between MatrixChat re-renders; fix positioning of the 'show' button; switch to dispatcher for show/hide LHS; remove errant scrollbars 2015-10-11 13:54:38 +01:00
Matthew Hodgson
8bdb5c0745 implement right panel collapsing more correctly too 2015-10-11 02:25:26 +01:00
Matthew Hodgson
47ed8971e3 implement collapsible leftpanel at last 2015-10-11 02:09:14 +01:00
Steven Hammerton
a8d51cdf58 Add support for CAS auth 2015-10-10 18:52:44 +01:00
Matthew Hodgson
a05437e81f add npm i source-map-loader troubleshooting step 2015-10-10 18:51:22 +01:00
David Baker
93f266a4fa Update to new memberlist api and hopefully sort out presence (list wasn't being re-sorted at the right time)
Hopefully fix #11
2015-10-09 17:26:28 +01:00
David Baker
aed1fe9bf1 Merge branch 'master' into develop 2015-10-09 16:40:27 +01:00
David Baker
7296cbfd5b Spellig 2015-10-09 16:38:37 +01:00
David Baker
023034ce4f Check for existence of content.size. Fixes #201. 2015-10-09 16:28:51 +01:00
David Baker
c68ef38399 Use ChangeDisplayNname / ChangeAvatar widgets to prompt for display name & avatar at signup.
Fixes #7.
2015-10-09 11:56:16 +01:00
David Baker
ccc5f30c9b Get the vector 'ongoing conference' bar back (vector now needs a custom RoomView for this: it would be nice it it didn't) 2015-10-08 15:22:16 +01:00
David Baker
c22442f6d1 Add ChangeDisplayName component and use it 2015-10-07 18:44:07 +01:00
David Baker
fca65a8cdb Show invited members separately.
May not be the final look.

Fixes #6
2015-10-06 15:09:42 +01:00
David Baker
807e947146 Add spinner for inviting. Fixes #13. 2015-10-06 14:12:45 +01:00
David Baker
85636ccdad Show end call button in states other than connected and ringback: it's perfectly valid to want to end the call at other times.
Fixes #9
2015-10-05 16:29:07 +01:00
David Baker
490e56bfbb Improved url / hash change handling 2015-10-05 15:32:34 +01:00
David Baker
61f951a33e Merge pull request #190 from vector-im/reactsdk-unfork
New vector using react-sdk
2015-10-05 10:31:39 +01:00
David Baker
53c8b9bcf7 no single quotes because windows 2015-10-05 10:20:02 +01:00
David Baker
df39c3a281 Changes from PR feedback 2015-10-02 16:44:35 +01:00
David Baker
050c6cf72f Dummy merge branch 'master' into reactsdk-unfork
(affected file no longer in this repo)
2015-10-02 14:36:07 +01:00
David Baker
2247d951d6 Add config file for default hs/is urls 2015-10-02 11:48:52 +01:00
David Baker
7b9cd7c232 Update readme 2015-10-01 16:02:44 +01:00
David Baker
c687f32f39 Port over custom vector roomlist controller with mini callview 2015-10-01 10:46:42 +01:00
David Baker
3845a989f6 Get conf calling working, apart from the end call button showing in the right room. 2015-09-30 18:22:15 +01:00
David Baker
94a6f856d1 Use the new interface for providing conf call functionality. Doesn't shoe it in the right room yet. 2015-09-30 16:52:45 +01:00
Matthew Hodgson
c62d97ca04 better XXXs 2015-09-29 12:57:54 +01:00
David Baker
fd6e7663cb Fix notifications 2015-09-28 17:52:34 +01:00
David Baker
7d540572fd Update for new default avatar API. 2015-09-28 17:06:39 +01:00
David Baker
c3f32b74e4 Some missed '/' / '.' replacemement 2015-09-28 14:48:07 +01:00
David Baker
588dbf5693 reskindex 2015-09-28 11:34:11 +01:00
David Baker
91c0df4450 Merge branch 'master' into reactsdk-unfork 2015-09-28 11:32:40 +01:00
David Baker
3ecf19df49 Disable caching on the local http server as commented 2015-09-25 17:38:51 +01:00
David Baker
f778f6adf9 Remove unused stuff 2015-09-25 15:33:38 +01:00
David Baker
796f424a3f Didn't need these in the end 2015-09-25 11:51:35 +01:00
David Baker
409697b35b Oops, these were just at the wrong scope 2015-09-25 11:46:06 +01:00
David Baker
f020f4397c Switch to webpack
Webapck actually supports loading input source maps and generally seems a lot
more solid then browserify (even if their website has an annoying animated
logo).
2015-09-25 11:43:28 +01:00
Matthew Hodgson
5fe41e28d7 make presence work better on the memberlist. kludges around lack of syjs-28. is about as good as angular was now. 2015-09-24 01:58:21 +02:00
Matthew Hodgson
a5a6a35122 don't blindly and inconsistently kill scrollbars 2015-09-24 00:19:40 +02:00
David Baker
bfa4cda2c6 build is no longer used 2015-09-23 10:14:38 +01:00
David Baker
c21dd853f9 Update package.json for renamed skin 2015-09-23 09:48:18 +01:00
Matthew Hodgson
1901fdf889 oops, bogus commit 2015-09-22 22:57:27 +02:00
David Baker
b11abae8e8 More fixing up of paths, requires etc 2015-09-22 19:09:23 +01:00
David Baker
7e72ee891a More fixing up of vector skin 2015-09-22 18:49:04 +01:00
David Baker
40594fc5fa Fix up controller requires 2015-09-22 18:17:19 +01:00
David Baker
dd4cfb25f8 Replace symlinks 2015-09-22 18:06:43 +01:00
David Baker
148dbc23ed Rename base skin to vector 2015-09-22 18:05:55 +01:00
David Baker
682392d02a Move skins dir to src 2015-09-22 18:05:31 +01:00
David Baker
09b81f46b0 Remove controllers that all come from react-sdk 2015-09-22 17:20:22 +01:00
David Baker
2f0df6d37e Merge branch 'master' into reactsdk-unfork 2015-09-22 15:28:50 +01:00
David Baker
616b4fe0f1 Merge pull request #175 from vector-im/matthew/userlist
Reskin the userlist as per the design
2015-09-22 15:27:21 +01:00
Matthew Hodgson
ef3603cd1a oops, rogue debugging stmt 2015-09-22 01:25:58 +02:00
Matthew Hodgson
61c94d63e7 make the new userlist UI actually work 2015-09-22 01:16:45 +02:00
Matthew Hodgson
260e22186b WIP at turning MemberInfo into a ContextualMenu 2015-09-21 19:23:04 +02:00
Matthew Hodgson
048260bb1b WIP at turning MemberInfo into a ContextualMenu 2015-09-21 19:22:29 +02:00
David Baker
a545007a19 Merge branch 'master' into reactsdk-unfork 2015-09-21 18:08:58 +01:00
Matthew Hodgson
56c5f6f46e clarify deployment 2015-09-19 20:17:45 +01:00
David Baker
81db1b2360 Merge pull request #160 from vector-im/conferencing
Add conferencing support
2015-09-18 10:03:02 +01:00
Kegan Dougal
240d5502fe Add a FIXME explaining the situation around alternative FS ASes 2015-09-17 11:47:42 +01:00
Kegan Dougal
7a50166dc6 Move the 'thumbnail' video to the top-left of the screen
This was originally laid out at the MatrixChat level which could then be
CSSified, but Matthew suggests this looks a lot better being at the
RoomList level above recents. Move the rendering logic to RoomList.
2015-09-17 11:37:56 +01:00
Kegan Dougal
9c8b540d14 Actually add the doc 2015-09-17 11:06:50 +01:00
Kegan Dougal
e991beb900 Add conferencing doc 2015-09-17 11:06:08 +01:00
David Baker
f1120562f3 Random console log 2015-09-16 14:14:21 +01:00
David Baker
901574b56e Update package.json 2015-09-16 14:13:16 +01:00
David Baker
fe586f6a36 Merge branch 'master' into reactsdk-unfork 2015-09-16 10:49:04 +01:00
Matthew Hodgson
01d3f2f119 implement /part, /j, and error rather than pass-through unrecognised commands 2015-09-16 01:09:32 +01:00
Matthew Hodgson
0aec086ebb actually link to blog etc from the login page 2015-09-15 17:06:04 +01:00
Kegan Dougal
f89fbffe89 Auto-place a video call if the conf notification is clicked 2015-09-15 15:55:02 +01:00
Kegan Dougal
2b65b4c2dc Hide the local video when in a conf call 2015-09-15 15:49:33 +01:00
Matthew Hodgson
ce2632bbe6 thinko 2015-09-15 15:18:39 +01:00
Kegan Dougal
370310bf82 Use better variable names 2015-09-15 15:02:02 +01:00
Kegan Dougal
f384aa7d9e Add notification to group chat rooms with ongoing conf calls
This notification disappears when in the conf call / when the call is over.
CSS stolen from the desktop notification bar.
2015-09-15 14:18:17 +01:00
Kegan Dougal
353269370f Wire up the "room" CallView for conferencing
This also separates out concerns better - UI elements just need to poke
getCallForRoom rather than care if the thing they are displaying is a
true 1:1 for this room ID or actually a conf room.
2015-09-15 13:19:07 +01:00
Kegan Dougal
7866979c79 Show/hide the Hangup button depending on the state of the conf call. 2015-09-15 13:04:09 +01:00
Kegan Dougal
5e3698de64 Actually enforce 1 call semantics. 2015-09-15 11:43:51 +01:00
Kegan Dougal
59986d8b72 Pass the call around different CallViews to keep media flowing
Previously, the CallView was attached to the RoomView, so you would get
a new CallView each time you changed the room and the one you changed
from would be destroyed. This would destroy media capture/playback as
the element was no longer in the DOM.

This is now fixed by having a "global" CallView which is attached at
the MatrixChat "page" level in the DOM hierarchy. This CallView isn't
scoped to a particular room; it will render any "active" call it can
find that *isn't the current room being displayed*. This has the side
effect of enforcing 1 call per app semantics as only the first active
call found is returned.

This fixes https://github.com/vector-im/vector-web/issues/31
This is unfinished (CSS for the global call view isn't done)
2015-09-15 11:05:53 +01:00
Kegan Dougal
fc892b3580 Hide 1:1 conference rooms 2015-09-11 16:55:48 +01:00
Kegan Dougal
e3b02a295c Check conf user/rooms a bit more efficiently 2015-09-11 16:14:30 +01:00
Kegan Dougal
77401e215e First working outbound conference calling
This has a number of failings currently: 1) It needs to hide the 1:1 conference
room, 2) Swapping tabs on the outbound call mutes audio (this just seems to be
a vector bug since I can repro this on a normal 1:1 voip call), 3) Needs a big
plinth/etc to say the conf call is in progress.
2015-09-11 15:49:47 +01:00
David Baker
ce9fcdbbb5 Old, useless README from the trivial react-sdk example 2015-09-08 17:06:19 +01:00
David Baker
980c71076e Start moving back to basing off react sdk: move vector out of examples dir 2015-09-08 17:02:24 +01:00
David Baker
ee4da24b84 Merge pull request #148 from vector-im/matthew/login
Fix up various login bugs and nastinesses
2015-09-07 10:47:25 +01:00
Matthew Hodgson
737fc74756 Merge branch 'matthew/login' into matthew/userlist 2015-09-01 02:13:52 +03:00
Matthew Hodgson
027ab6ee99 fix login layout on tall screens; limit dialog box width; wait a full second to re-query new HS details 2015-09-01 01:55:13 +03:00
Matthew Hodgson
8214ee8fad fix blinking when toggling advanced 2015-09-01 01:35:47 +03:00
Matthew Hodgson
ab068cc372 improve login, including checkbox fix for advanced options, rechecking when you change server, avoiding flickering when you change HS, better error/spinner layout, and trimming whitespace 2015-08-31 19:30:24 +01:00
Matthew Hodgson
5bab440a1f temporarily pin flux to 2.0, as 2.1 switches to ES6 and Babel which breaks our Dispatcher.js which fails to correctly extend the new Flux dispatcher, presumably due to using our noddy extend.js rather than an ES6-compatible one 2015-08-29 20:28:07 +01:00
David Baker
ef027706b9 Offer to join a room if you're not in it 2015-08-20 16:47:25 +01:00
David Baker
2351ad997c More places where we assumed sender would not be null 2015-08-20 11:46:54 +01:00
David Baker
cb25740961 Fix exception when accepting room invites 2015-08-20 11:43:08 +01:00
Matthew Hodgson
e3798e1b85 WIP fixing up the member list - just needs CSS and testing 2015-08-15 03:06:21 +01:00
Matthew Hodgson
80c3b2c8a3 match the design 2015-08-14 21:14:05 +01:00
Matthew Hodgson
a2e7c4aa77 WIP for fixing the popovers 2015-08-14 19:15:41 +01:00
Matthew Hodgson
25a4f1fde0 comment out ugly thumbnail bg for now 2015-08-14 17:43:37 +01:00
Matthew Hodgson
6b72c992c5 fix 'save changes' linewrap - thanks jfred 2015-08-14 17:08:31 +01:00
Matthew Hodgson
cb7f1aa916 ctrl-alt-num to change rooms 2015-08-14 16:30:19 +01:00
Matthew Hodgson
1176168960 escape key to cancel imageview popup 2015-08-14 15:52:44 +01:00
Matthew Hodgson
24630f598f fix errors with alt-up/down 2015-08-14 15:52:44 +01:00
Matthew Hodgson
316a28838f let's wrap when you go off the beginning 2015-08-14 15:51:57 +01:00
David Baker
960a38fe43 Don't try loading -ve room indices 2015-08-14 15:44:21 +01:00
David Baker
87feb6b076 Revert accidental commit 2015-08-14 15:37:41 +01:00
David Baker
c5e33352b0 You can't just use React classes as normal static classes :( 2015-08-14 15:25:05 +01:00
Matthew Hodgson
e1efb165fd make file thumbnails match the design 2015-08-14 14:44:16 +01:00
David Baker
12e53f5046 Ditch envify as it doesn't actually seem to work. Just setting the env var works fine though. 2015-08-14 14:13:30 +01:00
Matthew Hodgson
4851adf3b0 fix up the look & feel for unread messages warning to make it more visible 2015-08-14 13:53:32 +01:00
Matthew Hodgson
9ed5ca3ccb implement a pretty droptarget when uploading files 2015-08-14 13:20:39 +01:00
Matthew Hodgson
88095d4360 cursor: pointer for toolbar buttons 2015-08-14 13:05:44 +01:00
David Baker
7bdf612ad5 argh 2 2015-08-14 11:25:54 +01:00
David Baker
6d390ebd2f Argh 2015-08-14 11:24:41 +01:00
David Baker
ca09758210 Fix onerror handlers 2015-08-14 10:31:45 +01:00
David Baker
e5099ce3b7 Don't clobber the ready state if the sdk isn't ready yet 2015-08-14 10:31:09 +01:00
David Baker
a3879b507a Fix default avatars 2015-08-14 10:30:47 +01:00
David Baker
7a8537f3dc Don't show blank EventAsText tiles 2015-08-14 10:30:14 +01:00
Matthew Hodgson
001d1c50ef factor out MRoomMemberTile, MCallInviteTile, MCallAnswerTile and MCallHangupTile to just use EventAsTextTile and thus reduce duplication enormously 2015-08-14 00:28:37 +01:00
David Baker
fec266f1c0 Move avatars into their own components so I can add functionality like custom default avatars and onerror sources without having to add it in 13 separate places. Add the aforementioned features. 2015-08-13 19:30:02 +01:00
David Baker
b580fba7db Rooms with notifs turned off should still go bold. 2015-08-13 16:43:59 +01:00
David Baker
8bb836ad49 Assuming this was meant to be temporary 2015-08-12 18:26:43 +01:00
David Baker
eb36a2b242 If we were loaded with a room alias, don't lose that alias when we try to load the corresponding room. 2015-08-12 17:06:45 +01:00
Matthew Hodgson
18be8530fe put key='' on the right element 2015-08-12 01:45:04 +01:00
Matthew Hodgson
cf77a96ac5 make text buttons in the header look clickable with a pointer 2015-08-12 01:33:25 +01:00
Matthew Hodgson
5153954a28 put cancel & save buttons into the roomheader 2015-08-12 01:30:23 +01:00
Matthew Hodgson
bf10a03ab1 revert part of 0eceb737 as we need the auxpanel to have overflow: auto, not overflow: visible (initial)... 2015-08-12 01:30:05 +01:00
Matthew Hodgson
566c0437c0 provide a way to hide the notification nag toolbar 2015-08-12 00:42:04 +01:00
Matthew Hodgson
2ffa450e31 don't try to show negative power levels 2015-08-12 00:41:46 +01:00
Matthew Hodgson
8fd26509ac remove spurious dead code 2015-08-12 00:41:20 +01:00
Matthew Hodgson
3fc4aee269 lots of missing -webkit-flex for safari 2015-08-11 21:00:33 +01:00
David Baker
a20b4d2d2c If we have a current room on load, we should display it! 2015-08-11 17:24:12 +01:00
David Baker
be5aaeaad7 Don't try to fill space if we don't have a message wrapper 2015-08-11 17:20:31 +01:00
David Baker
18c56a171e Focus composer on alt-up/down 2015-08-11 14:43:52 +01:00
David Baker
b44d19d305 Call initial release 0.1.0 and this release 0.1.1 2015-08-10 18:19:30 +01:00
David Baker
a9fc47efd7 changelog, authors and contributing files 2015-08-10 18:09:35 +01:00
David Baker
a45785fe1a Fix blank page on login 2015-08-10 17:12:31 +01:00
David Baker
19d350e876 Merge branch 'email_login' 2015-08-10 16:25:04 +01:00
David Baker
7a1796870a Handle old server that don't support login using email address 2015-08-10 16:22:33 +01:00
David Baker
96cedc237e Actually change to vector IS 2015-08-10 15:50:26 +01:00
David Baker
6ab993f1a9 Change default IS to vector 2015-08-10 15:27:36 +01:00
David Baker
efcc2061b8 Hopefully port over ndarilek's accessibility changes to Vector (albeit with list elements contained within RoomView) 2015-08-10 15:17:15 +01:00
David Baker
10053fa770 Argh, the scrollbars! 2015-08-07 16:57:16 +01:00
David Baker
3519555710 Again, no point displaying scrollbars unless they're actually necessary 2015-08-07 16:48:48 +01:00
David Baker
0eceb737de Remove scrollbars by removing overflow: scroll in places. Add a title for hover over on long (or otherwise) topics. 2015-08-07 16:01:39 +01:00
David Baker
64727cb60e Don't die on malformed VoIP offers 2015-08-07 14:48:50 +01:00
David Baker
711bf583ab missed a file 2015-08-06 16:04:22 +01:00
David Baker
2771907573 Support room aliases in url bar and show them for rooms that have them 2015-08-06 14:58:52 +01:00
David Baker
68d408bfff Wire up popup to the "What does this mean?" link 2015-08-05 11:37:52 +01:00
David Baker
cdbbf4bfef Don't re-set savedParams, we did it earlier 2015-08-04 18:04:56 +01:00
David Baker
5cffee7ce6 stop matrix client on logout please 2015-08-04 16:45:39 +01:00
David Baker
9d8d4e4896 Support email login 2015-08-04 16:30:41 +01:00
David Baker
259d9dc3a2 Handle THREEPID_IN_USE error 2015-08-04 14:49:01 +01:00
David Baker
69ac0bd368 Set up URL routing after creating matrixchat in case onload / hashchange gets called before 2015-07-31 15:50:47 +01:00
Matthew Hodgson
9f98c4e9f7 crop zalgos on chrome fix 2015-07-30 00:56:27 +01:00
Matthew Hodgson
278a8282fe crop zalgos on chrome 2015-07-30 00:54:44 +01:00
Matthew Hodgson
55a4f3e3a1 display zalgo'd nicknames correctly on chrome/osx 2015-07-30 00:48:20 +01:00
Matthew Hodgson
2d1b88e50d use right paths 2015-07-28 16:30:01 +01:00
Matthew Hodgson
7017f68db7 favicon 2015-07-28 01:04:23 +01:00
Matthew Hodgson
2391c21eeb fix up the room directory a lot - with loading spinner, better layout, etc 2015-07-27 22:31:24 +01:00
Matthew Hodgson
f5b9f470b2 fix CSS for QuestionDialog 2015-07-27 18:26:51 +01:00
David Baker
7ac852d1fe Merge pull request #2 from vector-im/timestamp_hover
Show timestamp when you hover over a message
2015-07-27 14:57:10 +01:00
Matthew Hodgson
a24d7a9bce remove spurious console.logs 2015-07-24 11:17:45 +02:00
Matthew Hodgson
65cf8f030c alt/title tags and cursors 2015-07-24 10:57:28 +02:00
Matthew Hodgson
05cc604e8d Merge pull request #4 from neko259/master
Fixed scroll for room name and topic
2015-07-24 10:43:26 +02:00
nekorin
dc112e718e Fixed scroll for room name and topic 2015-07-24 11:25:19 +03:00
David Baker
2f9e3fcaea Make images be normal hyperlinks if middle/command clicked 2015-07-23 20:07:34 -07:00
David Baker
33f2955927 Don't show the bar if the platform doesn't support notifs 2015-07-23 19:40:09 -07:00
David Baker
674f90f27f If no Notifications, we essentially don't have permission (should fix on iOS) 2015-07-23 19:33:37 -07:00
David Baker
79c2a5abd6 Hide things that aren't wired up yet 2015-07-23 19:18:12 -07:00
Matthew Hodgson
02846c4fff room invite css 2015-07-23 11:01:28 -07:00
Matthew Hodgson
cc9123a33d oops, forgot css 2015-07-23 10:53:14 -07:00
Matthew Hodgson
5248b0c631 css prettification 2015-07-23 10:24:34 -07:00
Matthew Hodgson
e2644e3c13 curvy logo 2015-07-23 08:58:25 -07:00
Mark Haines
ccaeb43ff3 Ignore olm when building vector 2015-07-23 10:28:52 +01:00
Matthew Hodgson
11f5561be6 better room settings 2015-07-23 01:33:16 -07:00
Matthew Hodgson
59f380d3fc fix dialog css 2015-07-23 01:33:10 -07:00
Matthew Hodgson
d4efb37b03 sacrifice a flexbox goat or two to make firefox work. apparently flex-inside-nonflex-inside-flex always results in extreme confusion 2015-07-23 00:41:35 -07:00
Matthew Hodgson
0781c767ff s/vector/Vector/ 2015-07-23 00:30:16 -07:00
Matthew Hodgson
11e1a45ed5 missing -webkit-flex 2015-07-23 00:30:09 -07:00
David Baker
6f62211465 Return to root URL on log out. 2015-07-22 21:40:13 -07:00
David Baker
c2e92045d0 Don't announce that we've entered the null room on login if there are no rooms. 2015-07-22 21:37:46 -07:00
David Baker
9847383ba6 Commit imageview files 2015-07-22 20:37:08 -07:00
David Baker
772053713a lightbox image viewing (that needs CSS) 2015-07-22 16:04:29 -07:00
David Baker
7ffd684a9e Merge pull request #3 from vector-im/confirm_on_leave
Prompt if a user really wants to leave the room
2015-07-22 12:00:08 -07:00
Erik Johnston
51d2677525 Prompt if a user really wants to leave the room 2015-07-22 17:53:18 +01:00
Erik Johnston
c726257e9b Show timestamp when you hover over a message 2015-07-22 17:34:10 +01:00
Kegan Dougal
fbb6775523 Implement unread message status when scrolled up. 2015-07-22 14:49:32 +01:00
Kegan Dougal
8b0db49b8b Bugfix: Accepting an invite no longer results in a stale membership list. 2015-07-22 14:10:06 +01:00
Kegsay
b8c18130da Merge pull request #1 from vector-im/leave_room_button
Leave room button
2015-07-22 14:01:37 +01:00
Erik Johnston
431c93fc29 Fix invites so they display in room list 2015-07-22 13:57:48 +01:00
Erik Johnston
0016c2ad83 Also change URL when going to next/prev room 2015-07-22 13:47:08 +01:00
Erik Johnston
ed1cb44deb Show Loader while leaving 2015-07-22 13:39:36 +01:00
Erik Johnston
b9fd174f72 Merge branch 'master' of github.com:vector-im/vector-web into leave_room_button 2015-07-22 13:30:34 +01:00
Kegan Dougal
d4147c1315 Don't allow blank messages to be sent. 2015-07-22 13:15:12 +01:00
Kegan Dougal
7e42072952 Scroll to bottom when there are live call updates.
This keeps the latest messages visible when you place or receive a call.
2015-07-22 13:04:18 +01:00
Erik Johnston
6bfc566d9a Switch to another room when we succesfully leave a room 2015-07-22 11:41:32 +01:00
Erik Johnston
5835ea0a97 Only display rooms you're currently joined to in recents 2015-07-22 11:33:46 +01:00
Kegan Dougal
e80cf8a133 Bugfix: Scroll to the bottom more reliably on new incoming messages.
Added some padding to the calculation which means the scrollbar can
be scrolled up a bit and still get bumped down. Scroll a lot though
and it will not keep bumping you down (parity with Angular)
2015-07-22 11:12:45 +01:00
Erik Johnston
5fb6ea94b2 Add leave button as per wireframes 2015-07-22 10:59:36 +01:00
Mark Haines
e1aca588b5 Clear local storage *before* creating the client, Otherwise we will blow away anything that the client tried to persist after it was created 2015-07-22 09:43:40 +01:00
Erik Johnston
79e03597b3 Merge remote-tracking branch 'upstream/vector' 2015-07-22 09:24:13 +01:00
Kegan Dougal
6b44fa7642 Bugfix: Also grey out messages which are in the 'queued' state. 2015-07-22 09:14:39 +01:00
Kegan Dougal
772f987489 Unbreak npm start when running on Windows 2015-07-22 08:25:40 +01:00
Matthew Hodgson
663646f845 fix firefox layout 2015-07-22 00:17:20 -07:00
Matthew Hodgson
f6be51bd98 make login page scrollable 2015-07-22 00:17:15 -07:00
Matthew Hodgson
538536eb88 vaguely make room editing prettier 2015-07-21 23:19:51 -07:00
David Baker
c8f3f5841c Depend on develop js-sdk for now 2015-07-21 22:51:54 -07:00
David Baker
0f8686b8cd Rename example to vector 2015-07-21 22:46:21 -07:00
David Baker
8c25855f38 Tweak README for vector 2015-07-21 22:45:01 -07:00
David Baker
92e346a842 Merge branch 'vector' 2015-07-21 22:37:14 -07:00
David Baker
904754b20d Allow uploading the same file twice 2015-07-21 20:55:23 -07:00
David Baker
2eba2280d8 Don't barf if we we can't get a given room ID 2015-07-21 20:34:55 -07:00
Matthew Hodgson
67d3368e1e fix up some of the modals 2015-07-21 17:02:06 -07:00
Matthew Hodgson
ceb214f192 skin dialogs correctly 2015-07-21 16:48:55 -07:00
Matthew Hodgson
0b3a9baa44 fix CSS on firefox with copious application of black magic. the same trick might help the vertical height problem on chrome which was worked around by turning RoomView into a dummy flexbox 2015-07-21 15:59:11 -07:00
Matthew Hodgson
b2130a5295 remove remotevideo bottom border hack 2015-07-21 15:46:28 -07:00
Matthew Hodgson
a2f5933417 make aux panel behave vaguely intelligently 2015-07-21 15:43:54 -07:00
David Baker
9af09de7d4 Dispatch notifier_enabled when permission given if we don't already have it. 2015-07-21 15:35:30 -07:00
Matthew Hodgson
aaa96f1ac1 vicious rewrite of the CSS to support the notifications toolbar, removing all height: 100%'s and letting the flexbox stuff calculate auto-height instead. may have slowed down the rendering, especially when the toolbar is visible 2015-07-21 15:03:05 -07:00
David Baker
e03809b224 Merge pull request #16 from matrix-org/markjh/end-to-end
Add basic support for end-to-end crypto using olm.
2015-07-21 13:21:43 -07:00
David Baker
6fc910a259 Don't try to set page_type if not logged in 2015-07-21 11:12:59 -07:00
David Baker
959c0f0669 Order room members by lastActiveAgo 2015-07-21 11:05:54 -07:00
Matthew Hodgson
8dc73cb6cc finally fix dave's MemberInfo visibility bug, hopefully 2015-07-21 11:03:01 -07:00
Kegan Dougal
2160440ff1 Add and impl resend button. Update UI when failing to send messages. 2015-07-21 18:05:22 +01:00
Mark Haines
f036a10a7d Add missing src/encryption.js file 2015-07-21 17:00:57 +01:00
Mark Haines
6bb6eafdc0 Hook up slash commands to enable and disable encryption for a room so that we can experiment with encryption while we wait for the rest of the UI to exist 2015-07-21 16:46:17 +01:00
Kegan Dougal
e0496305aa Log when presence is set. 2015-07-21 16:23:21 +01:00
Kegan Dougal
2698405e2f Add MatrixToolbar CSS. Make the toolbar part of RoomView and don't cover the UI (shift it instead) 2015-07-21 16:17:50 +01:00
Kegan Dougal
c1de5e9e95 Factor out logic from EnableNotificationsButton(!) and reuse MatrixToolbar.
Added notification logic to Notifier; dispatch notifier_enabled when toggled
so the toolbar can be shown/hidden and the button text can be kept in sync.
Add MatrixToolbar back into MatrixChat for notification nagging.
2015-07-21 16:17:50 +01:00
David Baker
ed738b6398 Merge pull request #15 from matrix-org/erikj/room_editing
Show banned users in room settings
2015-07-21 08:14:25 -07:00
Erik Johnston
e36ca10e6c Show banned users in room settings 2015-07-21 16:08:56 +01:00
David Baker
71f5d1f6cb Use bind to take variable value rather than reference: make room directory able to join rooms 2015-07-21 08:05:58 -07:00
David Baker
4679e005bf Merge pull request #14 from matrix-org/erikj/room_editing
Room Settings.
2015-07-21 07:38:10 -07:00
Erik Johnston
c5d84562ba Move logic from view to controller 2015-07-21 15:24:10 +01:00
Erik Johnston
16846c36fd Handle default named rooms when editing room names 2015-07-21 14:48:07 +01:00
Kegan Dougal
2fe56fd86d Re-add the notifications button. 2015-07-21 14:45:32 +01:00
Erik Johnston
89f6459915 Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into erikj/room_editing 2015-07-21 14:14:48 +01:00
Erik Johnston
b8e1927e82 Use getDefaultProps instead of setting porps 2015-07-21 14:14:15 +01:00
Erik Johnston
d81260c92a Use getDefaultProps instead of setting porps 2015-07-21 14:13:59 +01:00
Erik Johnston
76c014b9ef Deal with the insanity if there are no power levels 2015-07-21 13:33:01 +01:00
Kegan Dougal
2454a71b38 Implement create/remove mod button. 2015-07-21 13:24:59 +01:00
Mark Haines
726ee7b50b Hook up the encrypt button when creating rooms 2015-07-21 12:03:15 +01:00
Mark Haines
3474f08334 Display the body of unknown message types 2015-07-21 12:01:18 +01:00
Kegan Dougal
13f04f77dc Tidy up power level logic. Add 'Moderator' label to members. 2015-07-21 11:43:18 +01:00
Erik Johnston
085e07c5b1 Display error on fail 2015-07-21 11:26:08 +01:00
Kegan Dougal
2e2cecdd4f Implement kick/ban/[un]mute buttons on member list dialogs. 2015-07-21 11:26:02 +01:00
Erik Johnston
0e9074b0de Remove console.logs 2015-07-21 11:22:11 +01:00
Erik Johnston
2bec7ec981 Add spinner while uploading state 2015-07-21 11:02:36 +01:00
Erik Johnston
0b1b6057d6 Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into erikj/room_editing 2015-07-21 10:39:46 +01:00
Erik Johnston
af190f286c Add event power levels to room settings 2015-07-21 10:33:41 +01:00
Matthew Hodgson
3657029fc7 apply opacity only to the subelements to avoid breaking hoverover on yosemite 2015-07-20 22:18:29 -07:00
Matthew Hodgson
12c824323d rename DirectoryMenu as BottomLeftMenu and implement a really really really basic RoomDirectory 2015-07-20 20:11:33 -07:00
Matthew Hodgson
fe71f69f0a rename EditableText's placeHolder parameter to be 'label' to avoid colliding with the HTML5 placeholder parameter 2015-07-20 20:11:33 -07:00
David Baker
e0673eee29 Don't go & load the first room if we've already been told to load a different one. 2015-07-20 14:09:41 -07:00
David Baker
36b1280f0c Bookmarkable room URLs 2015-07-20 12:20:35 -07:00
Matthew Hodgson
dcecdc8260 lipstick for hangup button and typing notifs 2015-07-20 12:09:24 -07:00
Erik Johnston
813cf0481e Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into erikj/room_editing 2015-07-20 18:18:04 +01:00
David Baker
0a3cddbd89 Merge pull request #13 from matrix-org/markjh/vector-cleanup-client-peg
Markjh/vector cleanup client peg
2015-07-20 10:12:16 -07:00
David Baker
e9b2cd1364 Allow input history to go forwards again to the empty field 2015-07-20 10:05:53 -07:00
Kegan Dougal
5d59a5b297 Change opacity of member list entries when their presence changes.
This is done by attaching a single room listener at the member list level and
then forceUpdate()ing the individual tiles as presence changes come in from
the JS SDK. This is more efficient than having hundreds of listeners attached
directly to the JS SDK (if we were to add a listener per tile).
2015-07-20 17:42:19 +01:00
Erik Johnston
3a7ebf73eb Wire up changing of power levels 2015-07-20 17:31:40 +01:00
Kegan Dougal
9d110d58e5 Manage presence of the client (same semantics as angular) 2015-07-20 17:14:29 +01:00
Kegan Dougal
bcab2f231a Add error dialogs for invites and call timeouts. 2015-07-20 16:40:00 +01:00
Erik Johnston
1b6ca2b0ee Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into erikj/room_editing 2015-07-20 16:31:02 +01:00
Erik Johnston
eae0972820 Add files. Add power levels to room settings 2015-07-20 16:28:23 +01:00
Kegan Dougal
6fe842e130 Add ErrorDialog class. Use it for VoIP/command errors. 2015-07-20 16:26:53 +01:00
Matthew Hodgson
bb06484732 fix up MemberInfo behaviour 2015-07-20 08:24:53 -07:00
Matthew Hodgson
05d9afc040 don't depend on google for fonts, given i'm on inflight wifi... 2015-07-20 08:24:53 -07:00
Erik Johnston
04f17c963c Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into erikj/room_editing 2015-07-20 16:03:35 +01:00
Erik Johnston
0039ccf203 Add ability to edit room settings 2015-07-20 15:07:51 +01:00
Kegan Dougal
f2bd802bdc Wire up invite button on the member list. 2015-07-20 15:07:19 +01:00
Mark Haines
28022534f7 Fix the client-peg clean up to match the changes vector has made to the sdk 2015-07-20 14:28:02 +01:00
Mark Haines
d8494ff89b Fix syntax 2015-07-20 14:01:52 +01:00
Mark Haines
715db89204 Move all the calls to createClient inside the MatrixClientPeg 2015-07-20 14:01:52 +01:00
Kegan Dougal
19ee75577e Actually access state_key when getting target invite names... 2015-07-20 13:30:01 +01:00
Kegan Dougal
0baa2141fc Wire up Start Chat button. 2015-07-20 13:22:56 +01:00
Kegan Dougal
08c16e0d7a Hook up presence/last active up (live updating; no ticker for last active). 2015-07-20 11:37:48 +01:00
Kegan Dougal
87dd9e8bb4 Unbreak stuff 2015-07-20 10:38:44 +01:00
Erik Johnston
46764c3614 Don't set room name if it hasn't changed 2015-07-20 10:23:07 +01:00
David Baker
0fa7f6cb63 .click() was what I was looking for... 2015-07-19 22:55:17 -07:00
David Baker
29b4f59982 Basically working upload progress bar. 2015-07-19 22:55:17 -07:00
David Baker
a477c8be4c Mostly wire up the send file button, except I can't figure out the js magic to make a file input open the prompt. 2015-07-19 22:55:17 -07:00
David Baker
b82d932a51 Logout button 2015-07-19 22:55:17 -07:00
Matthew Hodgson
2121ddc295 add a MemberInfo list overlay as a mini user-profile page 2015-07-20 01:51:58 +01:00
Matthew Hodgson
6eaba4ff04 title tag 2015-07-20 01:23:36 +01:00
David Baker
337e6b329f Don't lose username & password on login failure 2015-07-19 18:00:46 -04:00
David Baker
caa7f813eb Bugfix sending of typing events 2015-07-19 17:29:41 +01:00
David Baker
e8b944c0e1 Sooner or later I'll get used to this. 2015-07-19 16:43:45 +01:00
David Baker
e1f3c80f19 Display who's typing 2015-07-19 16:38:56 +01:00
David Baker
73c8eb7738 Send typing notifs 2015-07-19 15:29:16 +01:00
David Baker
5aa913f201 Fix label in register screen 2015-07-19 10:56:12 +01:00
David Baker
85748c09cf Linkify emote tiles 2015-07-19 10:43:16 +01:00
Matthew Hodgson
58907e5842 absolute path thinko 2015-07-19 03:39:13 +01:00
Matthew Hodgson
202c155788 absolute path thinko 2015-07-19 03:37:39 +01:00
Matthew Hodgson
2d25414b57 fix up registration page too 2015-07-19 03:30:41 +01:00
Matthew Hodgson
d239070adb implement login 2015-07-19 03:19:37 +01:00
Matthew Hodgson
1e1f7492d8 basic skin of incomingCallBox 2015-07-19 01:58:04 +01:00
Matthew Hodgson
919e1cf84f unbreak voice calls 2015-07-19 00:36:23 +01:00
Matthew Hodgson
981bcbe74f disambiguate z-index for remote video 2015-07-18 23:29:38 +01:00
Matthew Hodgson
27d19f2ec8 include the code used to gen these gfx 2015-07-18 19:11:39 +01:00
Matthew Hodgson
ea8737d957 POWER 2015-07-18 19:06:58 +01:00
Matthew Hodgson
c83ff1c623 hide events with no text equiv 2015-07-18 19:06:36 +01:00
Matthew Hodgson
db94a93fde hide events with no text equiv 2015-07-18 19:06:26 +01:00
Matthew Hodgson
fc5f9bb70c highlight should imply bold 2015-07-18 19:06:06 +01:00
Matthew Hodgson
5b83974edd try to hide ugly scrollbars on win & lin 2015-07-18 19:05:49 +01:00
Matthew Hodgson
5a12a4a1a3 don't break the layout with unrecognised join events 2015-07-18 02:17:10 +01:00
Matthew Hodgson
aa4f9abd5c basic VoIP lipstick 2015-07-18 02:04:58 +01:00
Matthew Hodgson
97981058f0 tweak badge 2015-07-18 01:22:25 +01:00
Matthew Hodgson
00d2d82a14 new style badges, hr, notices 2015-07-18 01:21:56 +01:00
Matthew Hodgson
4ded74765a encore du lipstick 2015-07-18 00:48:22 +01:00
Matthew Hodgson
b685e784f1 oops, unbreak selectedRoom. sorry dave 2015-07-18 00:48:17 +01:00
Matthew Hodgson
10cdf46c2c s/that/self/g 2015-07-17 21:59:48 +01:00
Matthew Hodgson
0d34728190 border for bottom left 2015-07-17 21:59:41 +01:00
Matthew Hodgson
15edb9a80b fix up memberlist a bit more 2015-07-17 21:30:25 +01:00
Matthew Hodgson
706abe654a fix up memberlist a bit more 2015-07-17 21:30:12 +01:00
Matthew Hodgson
d4541f54a3 fix up memberlist a bit more 2015-07-17 21:29:54 +01:00
Matthew Hodgson
348aa3e5e1 fix up memberlist a bit more 2015-07-17 21:29:41 +01:00
Matthew Hodgson
6280adc6e7 new assets 2015-07-17 21:19:43 +01:00
Matthew Hodgson
6394978326 degray 2015-07-17 20:23:11 +01:00
Matthew Hodgson
d09ddc48e0 lay out topic updates correctly 2015-07-17 20:09:56 +01:00
Matthew Hodgson
48063608c7 nudge css 2015-07-17 20:09:43 +01:00
Matthew Hodgson
aa70dd7b67 alt tags for avatars; improve header spacing; improve roomview margin 2015-07-17 19:09:27 +01:00
David Baker
5f367f7c75 missing event listener remove 2015-07-17 19:01:11 +01:00
David Baker
5c7bef3107 Add topic changes to timeline by adding a tile that just uses TextForEvent 2015-07-17 18:49:48 +01:00
Matthew Hodgson
b60a3b61bb handle huge room & topic names more sanely 2015-07-17 18:42:20 +01:00
Matthew Hodgson
ddb426095e /topic 2015-07-17 18:14:05 +01:00
David Baker
214ef4b4ce Tidy up profile picture setting & fix notification bug 2015-07-17 17:13:51 +01:00
Matthew Hodgson
88167358bb fix text input on FF 2015-07-17 17:08:39 +01:00
Matthew Hodgson
7bef6245f7 'ended the call' kinda handles both cancelled and 'hung up' 2015-07-17 17:08:38 +01:00
Kegan Dougal
812eb66ed5 Play ringback/busy/callend audio at the right times. 2015-07-17 17:05:11 +01:00
Kegan Dougal
827e777079 Implement ringing audio. Add other audio tags. 2015-07-17 16:42:26 +01:00
David Baker
ff567faeaa Profile picture setting and notifdications thereof. 2015-07-17 16:41:46 +01:00
Kegan Dougal
782234de6d Add ringtone files 2015-07-17 16:18:07 +01:00
Matthew Hodgson
328d5004d8 it's spelt 'hung up' 2015-07-17 16:15:23 +01:00
David Baker
a730804943 there is no content.target - it's state_key. Also, warn if no target 2015-07-17 15:55:36 +01:00
David Baker
1df8e65cdf argh javascript 2015-07-17 14:42:36 +01:00
David Baker
383a958abe Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into vector 2015-07-17 14:36:15 +01:00
David Baker
9a79539978 missed removeventlistener 2015-07-17 14:35:33 +01:00
Kegan Dougal
5c6b8a4cf9 Merge branch 'irc-style-commands' into vector 2015-07-17 14:26:58 +01:00
Kegan Dougal
b6f9ca0f95 When accepting calls, go to the right room. Relink video elements when CallView loads. 2015-07-17 14:25:51 +01:00
David Baker
6a76d8ace8 Update room header when room name changes 2015-07-17 13:48:24 +01:00
David Baker
8fe6411539 Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into vector 2015-07-17 12:26:02 +01:00
David Baker
b53640f892 Just return nothing for unknown events 2015-07-17 12:23:24 +01:00
David Baker
70fce0989b Merge pull request #11 from matrix-org/irc-style-commands
IRC-style commands
2015-07-17 12:06:32 +01:00
David Baker
00c45e48a9 Merge branch 'vector' into irc-style-commands 2015-07-17 12:03:10 +01:00
David Baker
37108ac56c Make notifications sensible again and have information once and only once. 2015-07-17 11:57:26 +01:00
David Baker
1b03aa8119 Display nick changes and factor out getting text for events into a common place. 2015-07-17 11:57:26 +01:00
Kegan Dougal
2bb2295499 Implement /join 2015-07-17 11:48:40 +01:00
Kegan Dougal
001372ec39 Fix nick changes 2015-07-17 11:13:05 +01:00
Kegan Dougal
006907e52f Add kick message. Add reasons if given. 2015-07-17 09:47:30 +01:00
Kegan Dougal
c8caf34777 Merge branch 'vector' into irc-style-commands 2015-07-17 09:17:58 +01:00
Matthew Hodgson
891ba40114 basic date separator support 2015-07-17 00:12:54 +01:00
Matthew Hodgson
1a95148dae basic date separator support 2015-07-17 00:12:53 +01:00
Matthew Hodgson
a2ca5f2847 improve badges and room tile layout 2015-07-17 00:12:53 +01:00
Matthew Hodgson
28dcfb2f12 make it work on ff 2015-07-17 00:12:53 +01:00
David Baker
0f39ec580f Slightly improve error messages 2015-07-16 22:06:00 +01:00
David Baker
8ccce4d702 Make new login style work 2015-07-16 21:46:39 +01:00
David Baker
d08c47a328 Fix npe 2015-07-16 21:45:59 +01:00
David Baker
cfbef0177e Fix custom server or registration & do some of new login UI 2015-07-16 19:30:27 +01:00
David Baker
8feeb93215 Merge pull request #10 from matrix-org/editable_room_name
Make room name editable
2015-07-16 19:29:49 +01:00
Kegan Dougal
1126769686 Merge branch 'vector' into irc-style-commands 2015-07-16 18:08:30 +01:00
Erik Johnston
789e70f2d6 Remove old atoms 2015-07-16 18:07:28 +01:00
Erik Johnston
df999fb2f8 Remove deleted atoms 2015-07-16 18:03:29 +01:00
Kegan Dougal
d4a98b3850 Show correct membership messages for ban/unban. 2015-07-16 17:57:57 +01:00
Erik Johnston
ce3dab3c5b Make room name editable 2015-07-16 17:42:33 +01:00
Kegan Dougal
91943d8a45 Merge branch 'vector' into irc-style-commands 2015-07-16 17:41:30 +01:00
Kegan Dougal
9aa66c1d8b Add SlashCommands to functionally process /commands. 2015-07-16 17:41:12 +01:00
David Baker
03733e6a0f Merge pull request #9 from matrix-org/create_room
Wire in create room.
2015-07-16 17:37:48 +01:00
Kegan Dougal
59ca26ee93 Use target not sender when displaying member text. 2015-07-16 17:37:35 +01:00
Erik Johnston
98160c3947 Add ability to remove people from invite list 2015-07-16 17:30:10 +01:00
Erik Johnston
68d60aadd1 Make Presets stateless 2015-07-16 17:24:33 +01:00
Erik Johnston
aa1b763518 Make CreateRoom remember what the values of its fields were. Remove some fairly pointless atoms 2015-07-16 17:20:03 +01:00
David Baker
75f8363be0 Merge branch 'master' into vector 2015-07-16 16:53:27 +01:00
David Baker
3a6423dd0a Merge branch 'master' into vector 2015-07-16 16:52:19 +01:00
Kegan Dougal
6b81022e28 Move position of incoming call buttons. 2015-07-16 16:32:21 +01:00
Erik Johnston
47f4c0dfff Use Loader 2015-07-16 16:20:00 +01:00
Erik Johnston
ebedf0b907 Add comment about RoomAlias magic 2015-07-16 16:17:29 +01:00
Erik Johnston
95968bf619 Make server_name magix in RoomAlias optional 2015-07-16 16:14:55 +01:00
David Baker
50edc619af Merge branch 'master' into vector 2015-07-16 16:13:24 +01:00
David Baker
ebe6072225 Make this a done so it doesn't swallow exceptions 2015-07-16 16:04:31 +01:00
Erik Johnston
cd26d1323f Wire together checkboxes and presets and use new /createRoom api 2015-07-16 15:55:46 +01:00
David Baker
155dd74a6f Merge pull request #8 from matrix-org/message-history-arrow-keys
Implement sent message history (up/down keys).
2015-07-16 15:41:57 +01:00
Kegan Dougal
b043889169 Implement sent message history (up/down keys).
This includes preserving and restoring partially entered text per room. This
is mostly ported straight from Angular.
2015-07-16 15:22:46 +01:00
David Baker
1677a3bf3a text change 2015-07-16 15:16:26 +01:00
David Baker
dac94d2293 mplement custom registration screen 2015-07-16 15:16:26 +01:00
David Baker
41bab56133 Merge pull request #7 from matrix-org/nick-completion
Implement nick completion (tab-complete).
2015-07-16 14:52:46 +01:00
Kegan Dougal
42c9766203 s/did/will/ 2015-07-16 14:39:15 +01:00
Kegan Dougal
6fbb7d7da4 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.
2015-07-16 14:25:57 +01:00
David Baker
cf38b8a5bb Merge branch 'master' into vector 2015-07-16 14:19:50 +01:00
Erik Johnston
c708976635 Wire up CreateRoom to UI. 2015-07-16 13:49:34 +01:00
Kegan Dougal
0a3a3dac1a Display call logs in the UI.
Display placed/incoming calls, answers and hangups.
2015-07-16 13:30:14 +01:00
Kegan Dougal
c4379e4827 Remove 'status' from payload; unused. 2015-07-16 12:57:59 +01:00
David Baker
41f659db4c Merge branch 'master' into vector 2015-07-16 12:44:42 +01:00
David Baker
a6f857e9d8 Merge pull request #6 from matrix-org/voip
VoIP addition
2015-07-16 12:31:36 +01:00
Kegan Dougal
5f3721f471 Tidying up 2015-07-16 11:54:53 +01:00
Kegan Dougal
c056bdf104 Only allow calls to be placed if there are 2 joined members. 2015-07-16 11:34:39 +01:00
Kegan Dougal
50f9d34211 Only display video elements in video calls. 2015-07-16 11:30:34 +01:00
Kegan Dougal
eedd437ca7 Minimal CSS bodge so the video actually dies when the call ends. 2015-07-16 11:21:43 +01:00
Kegan Dougal
7ffd97b5dc Implement call FSM. All works. 2015-07-16 11:05:09 +01:00
David Baker
73a1c2b581 Merge pull request #5 from matrix-org/user_settings
User settings
2015-07-16 10:56:28 +01:00
Erik Johnston
5d9db52b32 I just couldn't help myself 2015-07-16 10:53:51 +01:00
Erik Johnston
f17a9b14c2 Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into user_settings 2015-07-16 10:46:40 +01:00
Erik Johnston
3555f35737 Check to make sure passwords aren't blank 2015-07-16 10:43:16 +01:00
Erik Johnston
ca593b8544 Remove commented out code 2015-07-16 10:39:58 +01:00
Erik Johnston
5d99abf18c Correctly pull in client version from package.json 2015-07-16 10:38:00 +01:00
David Baker
139b92fcd6 Merge branch 'master' into vector 2015-07-16 10:33:53 +01:00
Kegan Dougal
ecd1f09095 Glue in video elements. 2015-07-16 10:26:41 +01:00
Erik Johnston
02045858f7 Wire up change password 2015-07-16 10:23:31 +01:00
Erik Johnston
edc3302d89 Fix broken RoomView CSS due to name clashes and splitting an element in
two.
2015-07-16 09:43:05 +01:00
Erik Johnston
bc93aeb50e Flesh out the user_settings page 2015-07-16 09:37:58 +01:00
Erik Johnston
1b4358624f Add a basic modal dialog implementation 2015-07-16 09:37:14 +01:00
Kegan Dougal
4f132c418f Fix a couple state bugs. 2015-07-15 17:48:26 +01:00
Kegan Dougal
14a4da54f8 Wire up hangup/answer buttons. 2015-07-15 17:36:47 +01:00
Kegan Dougal
37c9c8fbb4 Add CallHandler singleton and add CallView.
CallView is the container for either VideoViews or WaveformViews. All UI
elements listen for 'call_state' payloads and then call
CallHandler.getCall(roomId) to extract the current MatrixCall for that room.
We can't do this via stateful dispatches because dispatching does not preserve
ordering empirically (probably due to setTimeout).
2015-07-15 16:52:23 +01:00
Kegan Dougal
6316f1b195 Add call handling logic. Outbound voice calls work! 2015-07-15 15:36:45 +01:00
Erik Johnston
2b81f46030 Add placeHolder prop for EditableText 2015-07-15 15:04:39 +01:00
Erik Johnston
dfd54f3b95 Basic structure of user settings 2015-07-15 15:04:24 +01:00
Kegan Dougal
7e30c0f47b Add CallHandler to handle call logic and make VideoViews/WaveformViews. 2015-07-15 14:57:52 +01:00
Kegan Dougal
28cebab9a3 Add voip subdirectory. 2015-07-15 14:35:04 +01:00
Kegan Dougal
7cbb43fddb Merge branch 'vector' into voip
Conflicts:
	src/ComponentBroker.js
2015-07-15 14:21:58 +01:00
Kegan Dougal
78bea916e1 Dispatch events when calls are made/received. 2015-07-15 14:06:44 +01:00
Erik Johnston
844a883ad8 Merge branch 'master' of github.com:matrix-org/matrix-react-sdk into vector 2015-07-15 13:59:24 +01:00
Kegan Dougal
f94a061fda Add onClick listeners. Add getters for refs. 2015-07-15 13:34:11 +01:00
Kegan Dougal
aba103b8e0 Add VideoFeed atom and VideoView organism. 2015-07-15 13:09:15 +01:00
Erik Johnston
2fc08aeb12 Merge branch 'master' of github.com:matrix-org/matrix-react-sdk into vector 2015-07-15 10:36:47 +01:00
Matthew Hodgson
c69606df44 oops 2015-07-15 04:29:30 +01:00
Matthew Hodgson
8db6c17220 fix header 2015-07-15 04:26:25 +01:00
Matthew Hodgson
b739e7be9e fix avatar spacing 2015-07-15 04:21:32 +01:00
Matthew Hodgson
ce38d4ea12 moar graphics 2015-07-15 04:16:51 +01:00
Matthew Hodgson
9b384e52b5 implement latest skin 2015-07-15 04:16:38 +01:00
Matthew Hodgson
c0bd574997 improve padding on membership list 2015-07-15 00:36:54 +01:00
Matthew Hodgson
9a51cace34 fix bad membership list horizontal scrolling 2015-07-15 00:31:47 +01:00
Matthew Hodgson
77e76972f0 avatars for joins & parts 2015-07-14 14:31:13 +01:00
Matthew Hodgson
dff9353339 tabs->spaces everywhere; sorry folks - \!blame sublime 2015-07-14 12:11:01 +01:00
Matthew Hodgson
69d1844773 fix NPE for invites 2015-07-14 12:10:15 +01:00
Matthew Hodgson
6b0167375c badges and broken avatars 2015-07-14 02:13:00 +01:00
Matthew Hodgson
341fe868e4 group messages together from the same user 2015-07-14 00:25:51 +01:00
Matthew Hodgson
a5d24329c2 https for google fonts 2015-07-13 17:01:35 +01:00
Matthew Hodgson
10b3f250ec make it work in safari 2015-07-13 14:56:58 +01:00
Matthew Hodgson
18066d848a relative paths 2015-07-13 02:11:05 +01:00
Matthew Hodgson
06dfbbf821 fine tune header bar 2015-07-13 02:02:56 +01:00
Matthew Hodgson
20f1c075fc fix message tile layout a bit 2015-07-13 01:59:07 +01:00
Matthew Hodgson
bfe0cdcfd1 vector wireframes 2015-07-13 01:51:24 +01:00
276 changed files with 7291 additions and 3524 deletions

5
.gitignore vendored
View File

@@ -1,4 +1,3 @@
node_modules
build
bundle.css
bundle.js
vector/bundle.*
lib

9
AUTHORS.rst Normal file
View File

@@ -0,0 +1,9 @@
Vector is written mainly by the Vector team, building upon the Matrix React
SDK. Vector also welcomes external contributions. Third party contributors
include:
* Nolan Darilek (https://github.com/ndarilek)
Accessibility and semantic markup contributions
* https://github.com/neko259
Improved scrollbar CSS

31
CHANGES.rst Normal file
View File

@@ -0,0 +1,31 @@
Changes in vector v0.1.2 (2015-10-28)
======================================
* Support Room Avatars
* Fullscreen video calls
* Mute mic in VoIP calls
* Fix bug with multiple desktop notifications
* Context menu on messages
* Better hover-over on member list
* Support CAS auth
* Many other bug fixes
Changes in vector v0.1.1 (2015-08-10)
======================================
* Support logging in with an email address
* Use the Vector identity server
* Fix a bug where the client was not stopped properly on logout
* Fix bugs where field values would be forgotten if login or registration failed
* Improve URL bar navigation
* Add explanatory help text on advanced server options
* Fix a bug which caused execptions on malformed VoIP invitations
* Remove superfluous scrollbars on Firefox
* Numerous CSS fixes
* Improved accessibility
* Support command-click / middle click to open image in a new tab
* Improved room directory
* Fix display of text with many combining unicode points
Changes in vector v0.1.0 (2015-08-10)
======================================
Initial release

4
CONTRIBUTING.rst Normal file
View File

@@ -0,0 +1,4 @@
Contributing code to Vector
===========================
Vector follows the same pattern as https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.rst

172
README.md
View File

@@ -1,148 +1,58 @@
matrix-react-sdk
================
Vector/Web
==========
This is a react-based SDK for inserting a Matrix chat/voip client into a web page.
It provides reusable and customisable UI components backed by the matrix-js-sdk.
Vector is a Matrix web client built using the Matrix React SDK (https://github.com/matrix-org/matrix-react-sdk).
Getting started with the trivial example
========================================
Getting started
===============
1. Install or update `node.js` so that your `npm` is at least at version `2.0.0`
2. Clone the repo: `git clone https://github.com/matrix-org/matrix-react-sdk.git`
3. Switch to the SDK directory: `cd matrix-react-sdk`
2. Clone the repo: `git clone https://github.com/vector-im/vector-web.git`
3. Switch to the SDK directory: `cd vector-web`
4. Install the prerequisites: `npm install`
5. Switch to the example directory: `cd examples/trivial`
6. Install the example app prerequisites: `npm install`
7. Build the example and start a server: `npm start`
5. Start the development builder and a testing server: `npm start`
6. Wait a few seconds for the initial build to finish.
7. Open http://127.0.0.1:8080/ in your browser to see your newly built Vector.
Now open http://127.0.0.1:8080/ in your browser to see your newly built
Matrix client.
With `npm start`, any changes you make to the source files will cause a rebuild so
your changes will show up when you refresh.
Using the example app for development
=====================================
For production use, run `npm run build` to build all the necessary files
into the `vector` directory and run your own server.
To work on the CSS and Javascript and have the bundle files update as you
change the source files, you'll need to do two extra things:
Development
===========
1. Link the react sdk package into the example:
`cd matrix-react-sdk/examples/trivial; npm link ../../`
2. Start a watcher for the CSS files:
`cd matrix-react-sdk; npm run start:css`
For simple tweaks, you can work on any of the source files within Vector with the
setup above, and your changes will cause an instant rebuild.
Note that you may need to restart the CSS builder if you add a new file. Note
that `npm start` builds debug versions of the javascript and CSS, which are
much larger than the production versions build by the `npm run build` commands.
However, all serious development on Vector happens on the `develop` branch. This typically
depends on the `develop` snapshot versions of `matrix-react-sdk` and `matrix-js-sdk`
too, which isn't expressed in Vector's `package.json`. To do this, check out
the `develop` branches of these libraries and then use `npm link` to tell Vector
about them:
IMPORTANT: If you customise components in your application (and hence require
react from your app) you must be sure to:
1. `git clone git@github.com:matrix-org/matrix-react-sdk.git`
2. `cd matrix-react-sdk`
3. `git checkout develop`
4. `npm install`
5. `npm start` (to start the dev rebuilder)
6. `cd ../vector-web`
7. Link the react sdk package into the example:
`npm link path/to/your/react/sdk`
1. Make your app depend on react directly
2. If you `npm link` matrix-react-sdk, manually remove the 'react' directory
from matrix-react-sdk's `node_modules` folder, otherwise browserify will
pull in both copies of react which causes the app to break.
Similarly, you may need to `npm link path/to/your/js/sdk` in your `matrix-react-sdk`
directory.
How to customise the SDK
========================
If you add or remove any components from the Vector skin, you will need to rebuild
the skin's index by running, `npm run reskindex`.
The matrix-react-sdk provides well-defined reusable UI components which may be
customised/replaced by the developer to build into an app. A set of consistent
UI components (View + CSS classes) is called a 'skin' - currently the SDK
provides a very vanilla whitelabelled 'base skin'. In future the SDK could
provide alternative skins (probably by extending the base skin) that provide more
specific look and feels (e.g. "IRC-style", "Skype-style") etc. However, unlike
Wordpress themes and similar, we don't normally expect app developers to define
reusable skins. Instead you just go and incorporate your view customisations
into your actual app.
You may need to run `npm i source-map-loader` in matrix-js-sdk if you get errors
about "Cannot resolve module 'source-map-loader'" due to shortcomings in webpack.
The SDK uses the 'atomic' design pattern as seen at http://patternlab.io to
encourage a very modular and reusable architecture, making it easy to
customise and use UI widgets independently of the rest of the SDK and your app.
In practice this means:
Deployment
==========
* The UI of the app is strictly split up into a hierarchy of components.
* Each component has its own:
* View object defined as a React javascript class containing embedded
HTML expressed in React's JSX notation.
* CSS file, which defines the styling specific to that component.
* Components are loosely grouped into the 5 levels outlined by atomic design:
* atoms: fundamental building blocks (e.g. a timestamp tag)
* molecules: "group of atoms which functions together as a unit"
(e.g. a message in a chat timeline)
* organisms: "groups of molecules (and atoms) which form a distinct section
of a UI" (e.g. a view of a chat room)
* templates: "a reusable configuration of organisms" - used to combine and
style organisms into a well-defined global look and feel
* pages: specific instances of templates.
Just run `npm build` and then mount the `vector` directory on your webserver to
actually serve up the app, which is entirely static content.
Good separation between the components is maintained by adopting various best
practices that anyone working with the SDK needs to be be aware of and uphold:
* Views are named with upper camel case (e.g. molecules/MessageTile.js)
* The view's CSS file MUST have the same name (e.g. molecules/MessageTile.css)
* Per-view CSS is optional - it could choose to inherit all its styling from
the context of the rest of the app, although this is unusual for any but
the simplest atoms and molecules.
* The view MUST *only* refer to the CSS rules defined in its own CSS file.
'Stealing' styling information from other components (including parents)
is not cool, as it breaks the independence of the components.
* CSS classes are named with an app-specific namespacing prefix to try to avoid
CSS collisions. The base skin shipped by Matrix.org with the matrix-react-sdk
uses the naming prefix "mx_". A company called Yoyodyne Inc might use a
prefix like "yy_" for its app-specific classes.
* CSS classes use upper camel case when they describe React components - e.g.
.mx_MessageTile is the selector for the CSS applied to a MessageTile view.
* CSS classes for DOM elements within a view which aren't components are named
by appending a lower camel case identifier to the view's class name - e.g.
.mx_MessageTile_randomDiv is how you'd name the class of an arbitrary div
within the MessageTile view.
* We deliberately use vanilla CSS 3.0 to avoid adding any more magic
dependencies into the mix than we already have. App developers are welcome
to use whatever floats their boat however.
* The CSS for a component can however override the rules for child components.
For instance, .mx_RoomList .mx_RoomTile {} would be the selector to override
styles of RoomTiles when viewed in the context of a RoomList view.
Overrides *must* be scoped to the View's CSS class - i.e. don't just define
.mx_RoomTile {} in RoomList.css - only RoomTile.css is allowed to define its
own CSS. Instead, say .mx_RoomList .mx_RoomTile {} to scope the override
only to the context of RoomList views. N.B. overrides should be relatively
rare as in general CSS inheritence should be enough.
* Components should render only within the bounding box of their outermost DOM
element. Page-absolute positioning and negative CSS margins and similar are
generally not cool and stop the component from being reused easily in
different places.
* We don't use the atomify library itself, as React already provides most
of the modularity requirements it brings to the table.
With all this in mind, here's how you go about skinning the react SDK UI
components to embed a Matrix client into your app:
* Create a new NPM project. Be sure to directly depend on react, (otherwise
you can end up with two copies of react).
* Create an index.js file that sets up react. Add require statements for
React, the ComponentBroker and matrix-react-sdk and a call to Render
the root React element as in the examples.
* Create React classes for any custom components you wish to add. These
can be based off the files in `views` in the `matrix-react-sdk` package,
modifying the require() statement appropriately.
You only need to copy files you want to customise.
* Add a ComponentBroker.set() call for each of your custom components. These
must come *before* `require("matrix-react-sdk")`.
* Add a way to build your project: we suggest copying the browserify calls
from the example projects, but you could use grunt or gulp.
* Create an index.html file pulling in your compiled index.js file, the
CSS bundle from matrix-react-sdk.
For more specific detail on any of these steps, look at the `custom` example in
matrix-react-sdk/examples.

4
config.json Normal file
View File

@@ -0,0 +1,4 @@
{
"default_hs_url": "https://matrix.org",
"default_is_url": "https://vector.im"
}

52
docs/conferencing.md Normal file
View File

@@ -0,0 +1,52 @@
# VoIP Conferencing
This is a draft proposal for a naive voice/video conferencing implementation for
Matrix clients. There are many possible conferencing architectures possible for
Matrix (Multipoint Conferencing Unit (MCU); Stream Forwarding Unit (SFU); Peer-
to-Peer mesh (P2P), etc; events shared in the group room; events shared 1:1;
possibly even out-of-band signalling).
This is a starting point for a naive MCU implementation which could provide one
possible Matrix-wide solution in future, which retains backwards compatibility
with standard 1:1 calling.
* A client chooses to initiate a conference for a given room by starting a
voice or video call with a 'conference focus' user. This is a virtual user
(typically Application Service) which implements a conferencing bridge. It
isn't defined how the client discovers or selects this user.
* The conference focus user MUST join the room in which the client has
initiated the conference - this may require the client to invite the
conference focus user to the room, depending on the room's `join_rules`. The
conference focus user needs to be in the room to let the bridge eject users
from the conference who have left the room in which it was initiated, and aid
discovery of the conference by other users in the room. The bridge
identifies the room to join based on the user ID by which it was invited.
The format of this identifier is implementation dependent for now.
* If a client leaves the group chat room, they MUST be ejected from the
conference. If a client leaves the 1:1 room with the conference focus user,
they SHOULD be ejected from the conference.
* For now, rooms can contain multiple conference focus users - it's left to
user or client implementation to select which to converge on. In future this
could be mediated using a state event (e.g. `im.vector.call.mcu`), but we
can't do that right now as by default normal users can't set arbitrary state
events on a room.
* To participate in the conference, other clients initiates a standard 1:1
voice or video call to the conference focus user.
* For best UX, clients SHOULD show the ongoing voice/video call in the UI
context of the group room rather than 1:1 with the focus user. If a client
recognises a conference user present in the room, it MAY chose to highlight
this in the UI (e.g. with a "conference ongoing" notification, to aid
discovery). Clients MAY hide the 1:1 room with the focus user (although in
future this room could be used for floor control or other direct
communication with the conference focus)
* When all users have left the conference, the 'conference focus' user SHOULD
leave the room.
* If a conference focus user joins a room but does not receive a 1:1 voice or
video call, it SHOULD time out after a period of time and leave the room.

View File

@@ -1,40 +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 MTextTileController = require("matrix-react-sdk/src/controllers/molecules/MTextTile");
module.exports = React.createClass({
displayName: 'MTextTile',
mixins: [MTextTileController],
render: function() {
var content = this.props.mxEvent.getContent();
return (
<span ref="content" className="mx_MTextTile mx_MessageTile_content" onClick={this.onClick}>
{content.body}
</span>
);
},
onClick: function(ev) {
global.alert(this.props.mxEvent.getContent().body);
}
});

View File

@@ -1,4 +0,0 @@
matrix-react-example
====================
An example of how to use the Matrix React SDK to build a more customised app

View File

@@ -1,12 +0,0 @@
<!doctype html>
<html lang="en" style="height: 100%; overflow: hidden">
<head>
<meta charset="utf-8">
<title>Matrix React SDK Custom Example</title>
</head>
<body style="height: 100%; ">
<section id="matrixchat" style="height: 100%; "></section>
<script src="bundle.js"></script>
<link rel="stylesheet" href="node_modules/matrix-react-sdk/bundle.css">
</body>
</html>

View File

@@ -1,40 +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';
// Remember to make your project depend on react directly as soon as
// you add a require('react') to any file in your project. Do not rely
// on react being pulled in via matrix-react-sdk: browserify breaks
// horribly in this situation and can end up pulling in multiple copies
// of react.
var React = require("react");
// We pull in the component broker first, separately, as we need to replace
// components before the SDK loads.
var ComponentBroker = require("matrix-react-sdk/src/ComponentBroker");
var CustomMTextTile = require('./CustomMTextTile');
ComponentBroker.set('molecules/MTextTile', CustomMTextTile);
var MatrixReactSdk = require("matrix-react-sdk");
//var MatrixReactSdk = require("../../src/index");
React.render(
<MatrixReactSdk.MatrixChat />,
document.getElementById('matrixchat')
);

View File

@@ -1,29 +0,0 @@
{
"name": "matrix-react-example",
"version": "0.0.1",
"description": "Example usage of matrix-react-sdk",
"author": "matrix.org",
"repository": {
"type": "git",
"url": "https://github.com/matrix-org/matrix-react-sdk"
},
"license": "Apache-2.0",
"devDependencies": {
"browserify": "^10.2.3",
"envify": "^3.4.0",
"http-server": "^0.8.0",
"matrix-react-sdk": "../../",
"npm-css": "^0.2.3",
"parallelshell": "^1.2.0",
"reactify": "^1.1.1",
"uglify-js": "^2.4.23",
"watchify": "^3.2.1"
},
"scripts": {
"build": "browserify -t [ envify --NODE_ENV production ] -g reactify index.js | uglifyjs -c -m -o bundle.js",
"start": "parallelshell 'watchify -v -d -g reactify index.js -o bundle.js' 'http-server'"
},
"dependencies": {
"react": "^0.13.3"
}
}

View File

@@ -1,4 +0,0 @@
matrix-react-example
====================
A simple example of how to use the Matrix React SDK

View File

@@ -1,12 +0,0 @@
<!doctype html>
<html lang="en" style="height: 100%; overflow: hidden">
<head>
<meta charset="utf-8">
<title>Matrix React SDK Example</title>
</head>
<body style="height: 100%;">
<section id="matrixchat" style="height: 100%;"></section>
<script src="bundle.js"></script>
<link rel="stylesheet" href="node_modules/matrix-react-sdk/bundle.css">
</body>
</html>

View File

@@ -1,25 +0,0 @@
{
"name": "matrix-react-example",
"version": "0.0.1",
"description": "Example usage of matrix-react-sdk",
"author": "matrix.org",
"repository": {
"type": "git",
"url": "https://github.com/matrix-org/matrix-react-sdk"
},
"license": "Apache-2.0",
"devDependencies": {
"browserify": "^10.2.3",
"envify": "^3.4.0",
"http-server": "^0.8.0",
"matrix-react-sdk": "../../",
"parallelshell": "^1.2.0",
"reactify": "^1.1.1",
"uglify-js": "^2.4.23",
"watchify": "^3.2.1"
},
"scripts": {
"build": "browserify -t [ envify --NODE_ENV production ] -t reactify index.js | uglifyjs -c -m -o bundle.js",
"start": "parallelshell 'watchify -v -d -t reactify index.js -o bundle.js' 'http-server'"
}
}

View File

@@ -1,40 +1,48 @@
{
"name": "matrix-react-sdk",
"version": "0.0.1",
"description": "SDK for matrix.org using React",
"name": "vector-web",
"version": "0.1.2",
"description": "Vector webapp",
"author": "matrix.org",
"repository": {
"type": "git",
"url": "https://github.com/matrix-org/matrix-react-sdk"
"url": "https://github.com/vector-im/vector-web"
},
"license": "Apache-2.0",
"main": "src/index.js",
"style": "bundle.css",
"scripts": {
"build:skins": "jsx skins build/skins",
"build:logic": "jsx src build/src",
"build:js": "npm run build:skins && npm run build:logic",
"start:js": "jsx -w skins/base/views/ build --source-map-inline",
"build:css": "catw 'skins/base/css/**/*.css' -o bundle.css -c uglifycss --no-watch",
"start:css": "catw 'skins/base/css/**/*.css' -o bundle.css -v",
"build": "npm run build:js && npm run build:css",
"start": "parallelshell 'npm run start:js' 'npm run start:css'",
"prepublish": "npm run build"
"reskindex": "reskindex vector -h src/skins/vector/header",
"build:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/bundle.css -c uglifycss --no-watch",
"build:compile": "babel --source-maps -d lib src",
"build:bundle": "NODE_ENV=production webpack -p lib/vector/index.js vector/bundle.js",
"build": "npm run build:css && npm run build:compile && npm run build:bundle",
"start:js": "webpack -w src/vector/index.js vector/bundle.js",
"start:skins:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/bundle.css",
"//cache": "Note the -c 1 below due to https://code.google.com/p/chromium/issues/detail?id=508270",
"start": "parallelshell \"npm run start:js\" \"npm run start:skins:css\" \"http-server -c 1 vector\"",
"clean": "rimraf lib vector/bundle.css vector/bundle.js vector/bundle.js.map",
"prepublish": "npm run build:css && npm run build:compile"
},
"dependencies": {
"classnames": "^2.1.2",
"filesize": "^3.1.2",
"flux": "^2.0.3",
"matrix-js-sdk": "0.1.1",
"flux": "~2.0.3",
"linkifyjs": "^2.0.0-beta.4",
"matrix-js-sdk": "^0.3.0",
"matrix-react-sdk": "^0.0.2",
"q": "^1.4.1",
"react": "^0.13.3",
"react-loader": "^1.4.0",
"linkifyjs": "^2.0.0-beta.4"
"react-loader": "^1.4.0"
},
"devDependencies": {
"babel": "^5.8.23",
"babel-core": "^5.8.25",
"babel-loader": "^5.3.2",
"catw": "^1.0.1",
"parallelshell": "^1.1.1",
"react-tools": "^0.13.3",
"http-server": "^0.8.4",
"json-loader": "^0.5.3",
"parallelshell": "^1.2.0",
"rimraf": "^2.4.3",
"source-map-loader": "^0.1.5",
"uglifycss": "0.0.15"
}
}

View File

@@ -1,47 +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.
*/
.mx_RoomTile {
padding: 5px;
cursor: pointer;
}
.mx_RoomTile.selected {
text-decoration: underline;
}
.mx_RoomTile_name {
}
.mx_RoomTile div {
overflow: hidden;
text-overflow: ellipsis;
}
.mx_RoomTile.unread {
font-weight: bold;
}
.mx_RoomTile.highlight {
background-color: lime;
}
.mx_RoomTile.invited {
font-weight: bold;
}
.mx_RoomTile:hover {
}

View File

@@ -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 (
<input type="text" className="mx_RoomNameTextbox" placeholder="ex. MyNewRoom" onChange={this.onValueChanged}/>
);
}
});

View File

@@ -1,66 +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 classNames = require("classnames");
var ComponentBroker = require('../../../../src/ComponentBroker');
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
var SenderProfile = ComponentBroker.get('molecules/SenderProfile');
var UnknownMessageTile = ComponentBroker.get('molecules/UnknownMessageTile');
var tileTypes = {
'm.text': ComponentBroker.get('molecules/MTextTile'),
'm.notice': ComponentBroker.get('molecules/MNoticeTile'),
'm.emote': ComponentBroker.get('molecules/MEmoteTile'),
'm.image': ComponentBroker.get('molecules/MImageTile'),
'm.file': ComponentBroker.get('molecules/MFileTile')
};
var MessageTileController = require("../../../../src/controllers/molecules/MessageTile");
module.exports = React.createClass({
displayName: 'MessageTile',
mixins: [MessageTileController],
render: function() {
var content = this.props.mxEvent.getContent();
var msgtype = content.msgtype;
var TileType = UnknownMessageTile;
if (msgtype && tileTypes[msgtype]) {
TileType = tileTypes[msgtype];
}
var classes = classNames({
mx_MessageTile: true,
mx_MessageTile_sending: this.props.mxEvent.status == 'sending',
mx_MessageTile_notSent: this.props.mxEvent.status == 'not_sent',
mx_MessageTile_highlight: this.shouldHighlight()
});
return (
<div className={classes}>
<MessageTimestamp ts={this.props.mxEvent.getTs()} />
<SenderProfile mxEvent={this.props.mxEvent} />
<TileType mxEvent={this.props.mxEvent} />
</div>
);
},
});

View File

@@ -1,44 +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 classNames = require('classnames');
var RoomTileController = require("../../../../src/controllers/molecules/RoomTile");
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
module.exports = React.createClass({
displayName: 'RoomTile',
mixins: [RoomTileController],
render: function() {
var myUserId = MatrixClientPeg.get().credentials.userId;
var classes = classNames({
'mx_RoomTile': true,
'selected': this.props.selected,
'unread': this.props.unread,
'highlight': this.props.highlight,
'invited': this.props.room.currentState.members[myUserId].membership == 'invite'
});
return (
<div className={classes} onClick={this.onClick}>
<div className="mx_RoomTile_name">{this.props.room.name}</div>
</div>
);
}
});

View File

@@ -1,43 +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 ServerConfigController = require("../../../../src/controllers/molecules/ServerConfig");
module.exports = React.createClass({
displayName: 'ServerConfig',
mixins: [ServerConfigController],
render: function() {
return (
<div className="HomeServerTextBox">
<table className="serverConfig">
<tr>
<td>Home Server URL</td>
<td><input type="text" value={this.state.hs_url} onChange={this.hsChanged} /></td>
</tr>
<tr>
<td>Identity Server URL</td>
<td><input type="text" value={this.state.is_url} onChange={this.isChanged} /></td>
</tr>
</table>
</div>
);
}
});

View File

@@ -1,73 +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 CreateRoomController = require("../../../../src/controllers/organisms/CreateRoom");
var ComponentBroker = require('../../../../src/ComponentBroker');
var CreateRoomButton = ComponentBroker.get("atoms/create_room/CreateRoomButton");
var RoomNameTextbox = ComponentBroker.get("atoms/create_room/RoomNameTextbox");
var Presets = ComponentBroker.get("atoms/create_room/Presets");
var UserSelector = ComponentBroker.get("molecules/UserSelector");
module.exports = React.createClass({
displayName: 'CreateRoom',
mixins: [CreateRoomController],
getPreset: function() {
return this.refs.presets.getPreset();
},
getName: function() {
return this.refs.name_textbox.getName();
},
getInvitedUsers: function() {
return this.refs.user_selector.getUserIds();
},
render: function() {
var curr_phase = this.state.phase;
if (curr_phase == this.phases.CREATING) {
return (
<div>Creating...</div>
);
} else {
var error_box = "";
if (curr_phase == this.phases.ERROR) {
error_box = (
<div className="mx_Error">
An error occured: {this.state.error_string}
</div>
);
}
return (
<div className="mx_CreateRoom">
<label>Room Name <RoomNameTextbox ref="name_textbox" /></label>
<Presets ref="presets"/>
<UserSelector ref="user_selector"/>
<CreateRoomButton onCreateRoom={this.onCreateRoom} />
{error_box}
</div>
);
}
}
});

View File

@@ -1,56 +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 MemberListController = require("../../../../src/controllers/organisms/MemberList");
var ComponentBroker = require('../../../../src/ComponentBroker');
var MemberTile = ComponentBroker.get("molecules/MemberTile");
module.exports = React.createClass({
displayName: 'MemberList',
mixins: [MemberListController],
makeMemberTiles: function() {
var that = this;
return Object.keys(that.state.memberDict).map(function(userId) {
var m = that.state.memberDict[userId];
return (
<li key={userId}>
<MemberTile
member={m}
/>
</li>
);
});
},
render: function() {
return (
<div className="mx_MemberList">
<ul>
{this.makeMemberTiles()}
</ul>
</div>
);
}
});

View File

@@ -1,95 +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 MatrixClientPeg = require("../../../../src/MatrixClientPeg");
var ComponentBroker = require('../../../../src/ComponentBroker');
var classNames = require("classnames");
var MessageTile = ComponentBroker.get('molecules/MessageTile');
var RoomHeader = ComponentBroker.get('molecules/RoomHeader');
var MemberList = ComponentBroker.get('organisms/MemberList');
var MessageComposer = ComponentBroker.get('molecules/MessageComposer');
var RoomViewController = require("../../../../src/controllers/organisms/RoomView");
var Loader = require("react-loader");
module.exports = React.createClass({
displayName: 'RoomView',
mixins: [RoomViewController],
render: function() {
if (!this.state.room) {
return (
<div />
);
}
var myUserId = MatrixClientPeg.get().credentials.userId;
if (this.state.room.currentState.members[myUserId].membership == 'invite') {
if (this.state.joining) {
return (
<div className="mx_RoomView">
<Loader />
</div>
);
} else {
var inviteEvent = this.state.room.currentState.members[myUserId].events.member.event;
// XXX: Leaving this intentionally basic for now because invites are about to change totally
var joinErrorText = this.state.joinError ? "Failed to join room!" : "";
return (
<div className="mx_RoomView">
<div className="mx_RoomView_invitePrompt">
<div>{inviteEvent.user_id} has invited you to a room</div>
<button ref="joinButton" onClick={this.onJoinButtonClicked}>Join</button>
<div className="error">{joinErrorText}</div>
</div>
</div>
);
}
} else {
var scrollheader_classes = classNames({
mx_RoomView_scrollheader: true,
loading: this.state.paginating
});
return (
<div className="mx_RoomView">
<RoomHeader room={this.state.room} />
<div className="mx_RoomView_roomWrapper">
<div className="mx_RoomView_messagePanel">
<div ref="messageWrapper" className="mx_RoomView_messageListWrapper" onScroll={this.onMessageListScroll}>
<div className="mx_RoomView_MessageList" aria-live="polite">
<div className={scrollheader_classes}>
</div>
{this.getEventTiles()}
</div>
</div>
<MessageComposer roomId={this.props.roomId} />
</div>
<MemberList roomId={this.props.roomId} key={this.props.roomId} />
</div>
</div>
);
}
},
});

View File

@@ -1,70 +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 ComponentBroker = require('../../../../src/ComponentBroker');
var RoomList = ComponentBroker.get('organisms/RoomList');
var RoomView = ComponentBroker.get('organisms/RoomView');
var MatrixToolbar = ComponentBroker.get('molecules/MatrixToolbar');
var Login = ComponentBroker.get('templates/Login');
var Register = ComponentBroker.get('templates/Register');
var MatrixChatController = require("../../../../src/controllers/pages/MatrixChat");
// should be atomised
var Loader = require("react-loader");
module.exports = React.createClass({
displayName: 'MatrixChat',
mixins: [MatrixChatController],
render: function() {
if (this.state.logged_in && this.state.ready) {
return (
<div className="mx_MatrixChat">
<div className="mx_MatrixChat_chatWrapper">
<div className="mx_MatrixChat_leftPanel">
<RoomList selectedRoom={this.state.currentRoom} />
<MatrixToolbar />
</div>
<RoomView roomId={this.state.currentRoom} key={this.state.currentRoom} />
</div>
</div>
);
} else if (this.state.logged_in) {
return (
<Loader />
);
} else if (this.state.screen == 'register') {
return (
<Register onLoggedIn={this.onLoggedIn} clientSecret={this.state.register_client_secret}
sessionId={this.state.register_session_id} idSid={this.state.register_id_sid}
hsUrl={this.state.register_hs_url} isUrl={this.state.register_is_url}
registrationUrl={this.props.registrationUrl}
/>
);
} else {
return (
<Login onLoggedIn={this.onLoggedIn} />
);
}
}
});

View File

@@ -1,102 +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 ComponentBroker = require("../../../../src/ComponentBroker");
var ProgressBar = ComponentBroker.get("molecules/ProgressBar");
var Loader = require("react-loader");
var LoginController = require("../../../../src/controllers/templates/Login");
var ServerConfig = ComponentBroker.get("molecules/ServerConfig");
module.exports = React.createClass({
displayName: 'Login',
mixins: [LoginController],
getHsUrl: function() {
return this.refs.serverConfig.getHsUrl();
},
getIsUrl: function() {
return this.refs.serverConfig.getIsUrl();
},
/**
* Gets the form field values for the current login stage
*/
getFormVals: function() {
return {
'username': this.refs.user.getDOMNode().value,
'password': this.refs.pass.getDOMNode().value
};
},
componentForStep: function(step) {
switch (step) {
case 'choose_hs':
return (
<div>
<form onSubmit={this.onHSChosen}>
<ServerConfig ref="serverConfig" />
<input type="submit" value="Continue" />
</form>
</div>
);
// XXX: clearly these should be separate organisms
case 'stage_m.login.password':
return (
<div>
<form onSubmit={this.onUserPassEntered}>
<input ref="user" type="text" placeholder="username" /><br />
<input ref="pass" type="password" placeholder="password" /><br />
<input type="submit" value="Log in" />
</form>
</div>
);
}
},
loginContent: function() {
if (this.state.busy) {
return (
<Loader />
);
} else {
return (
<div>
<h1>Please log in:</h1>
{this.componentForStep(this.state.step)}
<div className="error">{this.state.errorText}</div>
<a onClick={this.showRegister} href="#">Create a new account</a>
</div>
);
}
},
render: function() {
return (
<div className="mx_Login">
<ProgressBar value={this.state.currentStep} max={this.state.totalSteps} />
{this.loginContent()}
</div>
);
}
});

View File

@@ -1,131 +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 ComponentBroker = require("../../../../src/ComponentBroker");
var Loader = require("react-loader");
var RegisterController = require("../../../../src/controllers/templates/Register");
var ServerConfig = ComponentBroker.get("molecules/ServerConfig");
module.exports = React.createClass({
displayName: 'Register',
mixins: [RegisterController],
getRegFormVals: function() {
return {
email: this.refs.email.getDOMNode().value,
username: this.refs.username.getDOMNode().value,
password: this.refs.password.getDOMNode().value,
confirmPassword: this.refs.confirmPassword.getDOMNode().value
};
},
getHsUrl: function() {
return this.refs.serverConfig.getHsUrl();
},
getIsUrl: function() {
return this.refs.serverConfig.getIsUrl();
},
componentForStep: function(step) {
switch (step) {
case 'initial':
return (
<div>
<form onSubmit={this.onInitialStageSubmit}>
Email: <input type="text" ref="email" defaultValue={this.savedParams.email} /><br />
Username: <input type="text" ref="username" defaultValue={this.savedParams.username} /><br />
Password: <input type="password" ref="password" defaultValue={this.savedParams.password} /><br />
Confirm Password: <input type="password" ref="confirmPassword" defaultValue={this.savedParams.confirmPassword} /><br />
<ServerConfig ref="serverConfig" />
<input type="submit" value="Continue" />
</form>
</div>
);
// XXX: clearly these should be separate organisms
case 'stage_m.login.email.identity':
return (
<div>
Please check your email to continue registration.
</div>
);
case 'stage_m.login.recaptcha':
return (
<div ref="recaptchaContainer">
This Home Server would like to make sure you're not a robot
<div id="mx_recaptcha"></div>
</div>
);
}
},
registerContent: function() {
if (this.state.busy) {
return (
<Loader />
);
} else {
return (
<div>
<h1>Create a new account:</h1>
{this.componentForStep(this.state.step)}
<div className="error">{this.state.errorText}</div>
<a onClick={this.showLogin} href="#">Sign in with existing account</a>
</div>
);
}
},
onBadFields: function(bad) {
var keys = Object.keys(bad);
var strings = [];
for (var i = 0; i < keys.length; ++i) {
switch (bad[keys[i]]) {
case this.FieldErrors.PasswordMismatch:
strings.push("Passwords don't match");
break;
case this.FieldErrors.Missing:
strings.push("Missing "+keys[i]);
break;
case this.FieldErrors.TooShort:
strings.push(keys[i]+" is too short");
break;
case this.FieldErrors.InUse:
strings.push(keys[i]+" is already taken");
break;
}
}
var errtxt = strings.join(', ');
this.setState({
errorText: errtxt
});
},
render: function() {
return (
<div className="mx_Register">
{this.registerContent()}
</div>
);
}
});

53
src/Avatar.js Normal file
View File

@@ -0,0 +1,53 @@
/*
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 MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
module.exports = {
avatarUrlForMember: function(member, width, height, resizeMethod) {
var url = member.getAvatarUrl(
MatrixClientPeg.get().getHomeserverUrl(),
width,
height,
resizeMethod
);
if (!url) {
// member can be null here currently since on invites, the JS SDK
// does not have enough info to build a RoomMember object for
// the inviter.
url = this.defaultAvatarUrlForString(member ? member.userId : '');
}
return url;
},
defaultAvatarUrlForString: function(s) {
var total = 0;
for (var i = 0; i < s.length; ++i) {
total += s.charCodeAt(i);
}
switch (total % 3) {
case 0:
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9QjNbxSKP4eagAFnTseHFErFYLBaLxWKxWCwWi8Vi8cX4CzAABSwCRWJw31gAAAAASUVORK5CYII=";
case 1:
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9chOaxgCP4eagAFk9seHFErFYLBaLxWKxWCwWi8Vi8cX4CzAAtKMCks/JG8MAAAAASUVORK5CYII=";
case 2:
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9YzNayQCP4eagADldseHFErFYLBaLxWKxWCwWi8Vi8cX4CzAAyiACeHwPiu4AAAAASUVORK5CYII=";
}
}
}

View File

@@ -1,92 +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';
function load(name) {
var module = require("../skins/base/views/"+name);
return module;
};
var ComponentBroker = function() {
this.components = {};
};
ComponentBroker.prototype = {
get: function(name) {
if (this.components[name]) {
return this.components[name];
}
this.components[name] = load(name);
return this.components[name];
},
set: function(name, module) {
this.components[name] = module;
}
};
// We define one Component Broker globally, because the intention is
// very much that it is a singleton. Relying on there only being one
// copy of the module can be dicey and not work as browserify's
// behaviour with multiple copies of files etc. is erratic at best.
// XXX: We can still end up with the same file twice in the resulting
// JS bundle which is nonideal.
if (global.componentBroker === undefined) {
global.componentBroker = new ComponentBroker();
}
module.exports = global.componentBroker;
// We need to tell browserify to include all the components
// by direct require syntax in here, but we don't want them
// to be evaluated in this file because then we wouldn't be
// able to override them. if (0) does this.
// Must be in this file (because the require is file-specific) and
// must be at the end because the components include this file.
if (0) {
require('../skins/base/views/atoms/LogoutButton');
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/Presets');
require('../skins/base/views/atoms/EditableText');
require('../skins/base/views/molecules/MatrixToolbar');
require('../skins/base/views/molecules/RoomTile');
require('../skins/base/views/molecules/MessageTile');
require('../skins/base/views/molecules/SenderProfile');
require('../skins/base/views/molecules/UnknownMessageTile');
require('../skins/base/views/molecules/MTextTile');
require('../skins/base/views/molecules/MNoticeTile');
require('../skins/base/views/molecules/MEmoteTile');
require('../skins/base/views/molecules/MImageTile');
require('../skins/base/views/molecules/MFileTile');
require('../skins/base/views/molecules/MRoomMemberTile');
require('../skins/base/views/molecules/RoomHeader');
require('../skins/base/views/molecules/MessageComposer');
require('../skins/base/views/molecules/ProgressBar');
require('../skins/base/views/molecules/ServerConfig');
require('../skins/base/views/organisms/MemberList');
require('../skins/base/views/molecules/MemberTile');
require('../skins/base/views/organisms/RoomList');
require('../skins/base/views/organisms/RoomView');
require('../skins/base/views/templates/Login');
require('../skins/base/views/templates/Register');
require('../skins/base/views/organisms/Notifier');
require('../skins/base/views/organisms/CreateRoom');
require('../skins/base/views/molecules/UserSelector');
}

View File

@@ -1,82 +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 q = require('q');
var extend = require('./extend');
function infoForImageFile(imageFile) {
var deferred = q.defer();
// Load the file into an html element
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e) {
img.src = e.target.result;
// Once ready, returns its size
img.onload = function() {
deferred.resolve({
w: img.width,
h: img.height
});
};
img.onerror = function(e) {
deferred.reject(e);
};
};
reader.onerror = function(e) {
deferred.reject(e);
};
reader.readAsDataURL(imageFile);
return deferred.promise;
}
function sendContentToRoom(file, roomId, matrixClient) {
var content = {
body: file.name,
info: {
size: file.size,
mimetype: file.type
}
};
var def = q.defer();
if (file.type.indexOf('image/') == 0) {
content.msgtype = 'm.image';
infoForImageFile(file).then(function(imageInfo) {
extend(content.info, imageInfo);
def.resolve();
});
} else {
content.msgtype = 'm.file';
def.resolve();
}
return def.promise.then(function() {
return matrixClient.uploadContent(file);
}).then(function(url) {
content.url = url;
return matrixClient.sendMessage(roomId, content);
});
}
module.exports = {
sendContentToRoom: sendContentToRoom
};

81
src/ContextualMenu.js Normal file
View File

@@ -0,0 +1,81 @@
/*
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');
// Shamelessly ripped off Modal.js. There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and
// pass in a custom control as the actual body.
module.exports = {
ContextualMenuContainerId: "mx_ContextualMenu_Container",
getOrCreateContainer: function() {
var container = document.getElementById(this.ContextualMenuContainerId);
if (!container) {
container = document.createElement("div");
container.id = this.ContextualMenuContainerId;
document.body.appendChild(container);
}
return container;
},
createMenu: function (Element, props) {
var self = this;
var closeMenu = function() {
React.unmountComponentAtNode(self.getOrCreateContainer());
if (props && props.onFinished) props.onFinished.apply(null, arguments);
};
var position = {
top: props.top - 20,
};
var chevron = null;
if (props.left) {
chevron = <img className="mx_ContextualMenu_chevron_left" src="img/chevron-left.png" width="9" height="16" />
position.left = props.left + 8;
} else {
chevron = <img className="mx_ContextualMenu_chevron_right" src="img/chevron-right.png" width="9" height="16" />
position.right = props.right + 8;
}
var className = 'mx_ContextualMenu_wrapper';
// FIXME: If a menu uses getDefaultProps it clobbers the onFinished
// property set here so you can't close the menu from a button click!
var menu = (
<div className={className}>
<div className="mx_ContextualMenu" style={position}>
{chevron}
<Element {...props} onFinished={closeMenu}/>
</div>
<div className="mx_ContextualMenu_background" onClick={closeMenu}></div>
</div>
);
React.render(menu, this.getOrCreateContainer());
return {close: closeMenu};
},
};

View File

@@ -1,76 +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';
// A thing that holds your Matrix Client
var Matrix = require("matrix-js-sdk");
var matrixClient = null;
var localStorage = window.localStorage;
function createClient(hs_url, is_url, user_id, access_token) {
var opts = {
baseUrl: hs_url,
idBaseUrl: is_url,
accessToken: access_token,
userId: user_id
};
matrixClient = Matrix.createClient(opts);
}
if (localStorage) {
var hs_url = localStorage.getItem("mx_hs_url");
var is_url = localStorage.getItem("mx_is_url") || 'https://matrix.org';
var access_token = localStorage.getItem("mx_access_token");
var user_id = localStorage.getItem("mx_user_id");
if (access_token && user_id && hs_url) {
createClient(hs_url, is_url, user_id, access_token);
}
}
module.exports = {
get: function() {
return matrixClient;
},
replaceUsingUrls: function(hs_url, is_url) {
matrixClient = Matrix.createClient({
baseUrl: hs_url,
idBaseUrl: is_url
});
},
replaceUsingAccessToken: function(hs_url, is_url, user_id, access_token) {
createClient(hs_url, is_url, user_id, access_token);
if (localStorage) {
try {
localStorage.clear();
localStorage.setItem("mx_hs_url", hs_url);
localStorage.setItem("mx_is_url", is_url);
localStorage.setItem("mx_user_id", user_id);
localStorage.setItem("mx_access_token", access_token);
} catch (e) {
console.warn("Error using local storage: can't persist session!");
}
} else {
console.warn("No local storage available: can't persist session!");
}
}
};

View File

@@ -1,68 +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');
module.exports = {
propTypes: {
onValueChanged: React.PropTypes.func,
initalValue: React.PropTypes.string,
},
Phases: {
Display: "display",
Edit: "edit",
},
getDefaultProps: function() {
return {
onValueChanged: function() {},
initalValue: '',
};
},
getInitialState: function() {
return {
value: this.props.initalValue,
phase: this.Phases.Display,
}
},
getValue: function() {
return this.state.value;
},
setValue: function(val) {
this.setState({
value: val,
phase: this.Phases.Display,
});
this.onValueChanged();
},
cancelEdit: function() {
this.setState({
phase: this.Phases.Display,
});
},
onValueChanged: function() {
this.props.onValueChanged(this.state.value);
},
};

View File

@@ -1,67 +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';
module.exports = {
notificationsAvailable: function() {
return !!global.Notification;
},
havePermission: function() {
return global.Notification.permission == 'granted';
},
enabled: function() {
if (!this.havePermission()) return false;
if (!global.localStorage) return true;
var enabled = global.localStorage.getItem('notifications_enabled');
if (enabled === null) return true;
return enabled === 'true';
},
disable: function() {
if (!global.localStorage) return;
global.localStorage.setItem('notifications_enabled', 'false');
this.forceUpdate();
},
enable: function() {
if (!this.havePermission()) {
var that = this;
global.Notification.requestPermission(function() {
that.forceUpdate();
});
}
if (!global.localStorage) return;
global.localStorage.setItem('notifications_enabled', 'true');
this.forceUpdate();
},
onClick: function() {
if (!this.notificationsAvailable()) {
return;
}
if (!this.enabled()) {
this.enable();
} else {
this.disable();
}
},
};

View File

@@ -1,27 +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 dis = require("../../dispatcher");
module.exports = {
onClick: function() {
dis.dispatch({
action: 'logout'
});
},
};

View File

@@ -1,21 +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';
module.exports = {
};

View File

@@ -1,35 +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');
module.exports = {
propTypes: {
onCreateRoom: React.PropTypes.func,
},
getDefaultProps: function() {
return {
onCreateRoom: function() {},
};
},
onClick: function() {
this.props.onCreateRoom();
},
};

View File

@@ -1,41 +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');
module.exports = {
propTypes: {
default_preset: React.PropTypes.string
},
getDefaultProps: function() {
return {
default_preset: 'private_chat',
};
},
getInitialState: function() {
return {
preset: this.props.default_preset,
}
},
getPreset: function() {
return this.state.preset;
},
};

View File

@@ -1,41 +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');
module.exports = {
propTypes: {
default_name: React.PropTypes.string
},
getDefaultProps: function() {
return {
default_name: '',
};
},
getInitialState: function() {
return {
room_name: this.props.default_name,
}
},
getName: function() {
return this.state.room_name;
},
};

View File

@@ -1,21 +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';
module.exports = {
};

View File

@@ -1,44 +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 filesize = require('filesize');
module.exports = {
presentableTextForFile: function(content) {
var linkText = 'Attachment';
if (content.body && content.body.length > 0) {
linkText = content.body;
}
var additionals = [];
if (content.info) {
if (content.info.mimetype && content.info.mimetype.length > 0) {
additionals.push(content.info.mimetype);
}
if (content.info.size) {
additionals.push(filesize(content.info.size));
}
}
if (additionals.length > 0) {
linkText += ' (' + additionals.join(', ') + ')';
}
return linkText;
}
};

View File

@@ -1,21 +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';
module.exports = {
};

View File

@@ -1,28 +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 linkify = require('linkifyjs');
var linkifyElement = require('linkifyjs/element');
var linkifyMatrix = require('../../linkify-matrix.js');
linkifyMatrix(linkify);
module.exports = {
componentDidMount: function() {
linkifyElement(this.refs.content.getDOMNode(), linkifyMatrix.options);
}
};

View File

@@ -1,21 +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';
module.exports = {
};

View File

@@ -1,30 +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 linkify = require('linkifyjs');
var linkifyElement = require('linkifyjs/element');
var linkifyMatrix = require('../../linkify-matrix');
linkifyMatrix(linkify);
module.exports = {
componentDidMount: function() {
linkifyElement(this.refs.content.getDOMNode(), linkifyMatrix.options);
}
};

View File

@@ -1,21 +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';
module.exports = {
};

View File

@@ -1,30 +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 dis = require("../../dispatcher");
var MatrixClientPeg = require("../../MatrixClientPeg");
module.exports = {
onClick: function() {
dis.dispatch({
action: 'view_user',
user_id: this.props.member.userId
});
},
};

View File

@@ -1,67 +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 MatrixClientPeg = require("../../MatrixClientPeg");
var dis = require("../../dispatcher");
module.exports = {
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
},
componentWillUnmount: function() {
dis.unregister(this.dispatcherRef);
},
onAction: function(payload) {
switch (payload.action) {
case 'focus_composer':
this.refs.textarea.getDOMNode().focus();
break;
}
},
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
};
}
MatrixClientPeg.get().sendMessage(this.props.roomId, content).then(function() {
dis.dispatch({
action: 'message_sent'
});
});
this.refs.textarea.getDOMNode().value = '';
ev.preventDefault();
}
},
};

View File

@@ -1,28 +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 MatrixClientPeg = require("../../MatrixClientPeg");
module.exports = {
shouldHighlight: function() {
var actions = MatrixClientPeg.get().getPushActionsForEvent(this.props.mxEvent);
if (!actions || !actions.tweaks) { return false; }
return actions.tweaks.highlight;
}
};

View File

@@ -1,21 +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';
module.exports = {
};

View File

@@ -1,28 +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 dis = require("../../dispatcher");
module.exports = {
onClick: function() {
dis.dispatch({
action: 'view_room',
room_id: this.props.room.roomId
});
},
};

View File

@@ -1,21 +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';
module.exports = {
};

View File

@@ -1,62 +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");
module.exports = {
propTypes: {
onHsUrlChanged: React.PropTypes.func,
onIsUrlChanged: React.PropTypes.func,
default_hs_url: React.PropTypes.string,
default_is_url: React.PropTypes.string
},
getDefaultProps: function() {
return {
onHsUrlChanged: function() {},
onIsUrlChanged: function() {},
default_hs_url: 'https://matrix.org/',
default_is_url: 'https://matrix.org/'
};
},
getInitialState: function() {
return {
hs_url: this.props.default_hs_url,
is_url: this.props.default_is_url,
}
},
hsChanged: function(ev) {
this.setState({hs_url: ev.target.value});
this.props.onHsUrlChanged(this.state.hs_url);
},
isChanged: function(ev) {
this.setState({is_url: ev.target.value});
this.props.onIsUrlChanged(this.state.is_url);
},
getHsUrl: function() {
return this.state.hs_url;
},
getIsUrl: function() {
return this.state.is_url;
},
};

View File

@@ -1,57 +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');
module.exports = {
propTypes: {
initially_selected: React.PropTypes.arrayOf(React.PropTypes.string),
},
getDefaultProps: function() {
return {
initially_selected: [],
};
},
getInitialState: function() {
return {
selected_users: this.props.initially_selected,
}
},
addUser: function(user_id) {
if (this.state.selected_users.indexOf(user_id == -1)) {
this.setState({
selected_users: this.state.selected_users.concat([user_id]),
});
}
},
removeUser: function(user_id) {
this.setState({
selected_users: this.state.selected_users.filter(function(e) {
return e != user_id;
}),
});
},
getUserIds: function() {
return this.state.selected_users;
}
};

View File

@@ -0,0 +1,97 @@
/*
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("matrix-react-sdk/lib/dispatcher");
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
var VectorConferenceHandler = require('../../../modules/VectorConferenceHandler');
/*
* State vars:
* this.state.call = MatrixCall|null
*
* Props:
* this.props.room = Room (JS SDK)
*
* Internal state:
* this._trackedRoom = (either from props.room or programatically set)
*/
module.exports = {
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
this._trackedRoom = null;
if (this.props.room) {
this._trackedRoom = this.props.room;
this.showCall(this._trackedRoom.roomId);
}
else {
var call = CallHandler.getAnyActiveCall();
if (call) {
console.log(
"Global CallView is now tracking active call in room %s",
call.roomId
);
this._trackedRoom = MatrixClientPeg.get().getRoom(call.roomId);
this.showCall(call.roomId);
}
}
},
componentWillUnmount: function() {
dis.unregister(this.dispatcherRef);
},
onAction: function(payload) {
// don't filter out payloads for room IDs other than props.room because
// we may be interested in the conf 1:1 room
if (payload.action !== 'call_state' || !payload.room_id) {
return;
}
this.showCall(payload.room_id);
},
showCall: function(roomId) {
var call = (
CallHandler.getCallForRoom(roomId) ||
VectorConferenceHandler.getConferenceCallForRoom(roomId)
);
if (call) {
call.setLocalVideoElement(this.getVideoView().getLocalVideoElement());
call.setRemoteVideoElement(this.getVideoView().getRemoteVideoElement());
// give a separate element for audio stream playback - both for voice calls
// and for the voice stream of screen captures
call.setRemoteAudioElement(this.getVideoView().getRemoteAudioElement());
}
if (call && call.type === "video" && call.state !== 'ended') {
// if this call is a conf call, don't display local video as the
// conference will have us in it
this.getVideoView().getLocalVideoElement().style.display = (
call.confUserId ? "none" : "initial"
);
this.getVideoView().getRemoteVideoElement().style.display = "initial";
}
else {
this.getVideoView().getLocalVideoElement().style.display = "none";
this.getVideoView().getRemoteVideoElement().style.display = "none";
dis.dispatch({action: 'video_fullscreen', fullscreen: false});
}
}
};

View File

@@ -1,92 +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 MatrixClientPeg = require("../../MatrixClientPeg");
module.exports = {
propTypes: {
onRoomCreated: React.PropTypes.func,
},
phases: {
CONFIG: "CONFIG", // We're waiting for user to configure and hit create.
CREATING: "CREATING", // We're sending the request.
CREATED: "CREATED", // We successfully created the room.
ERROR: "ERROR", // There was an error while trying to create room.
},
getDefaultProps: function() {
return {
onRoomCreated: function() {},
};
},
getInitialState: function() {
return {
phase: this.phases.CONFIG,
error_string: "",
};
},
onCreateRoom: function() {
var options = {};
var room_name = this.getName();
if (room_name) {
options.name = room_name;
}
var preset = this.getPreset();
if (preset) {
options.preset = preset;
}
var invited_users = this.getInvitedUsers();
if (invited_users) {
options.invite = invited_users;
}
var cli = MatrixClientPeg.get();
if (!cli) {
// TODO: Error.
console.error("Cannot create room: No matrix client.");
return;
}
var deferred = MatrixClientPeg.get().createRoom(options);
this.setState({
phase: this.phases.CREATING,
});
var self = this;
deferred.then(function () {
self.setState({
phase: self.phases.CREATED,
});
self.props.onRoomCreated();
}, function(err) {
self.setState({
phase: self.phases.ERROR,
error_string: err.toString(),
});
});
}
};

View File

@@ -1,82 +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 MatrixClientPeg = require("../../MatrixClientPeg");
var INITIAL_LOAD_NUM_MEMBERS = 50;
module.exports = {
getInitialState: function() {
var members = this.roomMembers(INITIAL_LOAD_NUM_MEMBERS);
return {
memberDict: members
};
},
componentWillMount: function() {
var cli = MatrixClientPeg.get();
cli.on("RoomState.members", this.onRoomStateMember);
},
componentWillUnmount: function() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
}
},
componentDidMount: function() {
var that = this;
setTimeout(function() {
if (!that.isMounted()) return;
that.setState({
memberDict: that.roomMembers()
});
}, 50);
},
// Remember to set 'key' on a MemberList to the ID of the room it's for
/*componentWillReceiveProps: function(newProps) {
},*/
onRoomStateMember: function(ev, state, member) {
var members = this.roomMembers();
this.setState({
memberDict: members
});
},
roomMembers: function(limit) {
var cli = MatrixClientPeg.get();
var all_members = cli.getRoom(this.props.roomId).currentState.members;
var all_user_ids = Object.keys(all_members);
var to_display = {};
var count = 0;
for (var i = 0; i < all_user_ids.length && (limit === undefined || count < limit); ++i) {
var user_id = all_user_ids[i];
var m = all_members[user_id];
if (m.membership == 'join' || m.membership == 'invite') {
to_display[user_id] = m;
++count;
}
}
return to_display;
}
};

View File

@@ -1,46 +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 MatrixClientPeg = require("../../MatrixClientPeg");
module.exports = {
start: function() {
this.boundOnRoomTimeline = this.onRoomTimeline.bind(this);
MatrixClientPeg.get().on('Room.timeline', this.boundOnRoomTimeline);
},
stop: function() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener('Room.timeline', this.boundOnRoomTimeline);
}
},
onRoomTimeline: function(ev, room, toStartOfTimeline) {
if (toStartOfTimeline) return;
if (ev.sender && ev.sender.userId == MatrixClientPeg.get().credentials.userId) return;
var enabled = global.localStorage.getItem('notifications_enabled');
if (enabled === 'false') return;
var actions = MatrixClientPeg.get().getPushActionsForEvent(ev);
if (actions && actions.notify) {
this.displayNotification(ev, room);
}
}
};

View File

@@ -17,12 +17,15 @@ limitations under the License.
'use strict';
var React = require("react");
var MatrixClientPeg = require("../../MatrixClientPeg");
var RoomListSorter = require("../../RoomListSorter");
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
var RoomListSorter = require("matrix-react-sdk/lib/RoomListSorter");
var dis = require("matrix-react-sdk/lib/dispatcher");
var ComponentBroker = require('../../ComponentBroker');
var sdk = require('matrix-react-sdk');
var VectorConferenceHandler = require("../../modules/VectorConferenceHandler");
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
var RoomTile = ComponentBroker.get("molecules/RoomTile");
var HIDE_CONFERENCE_CHANS = true;
module.exports = {
componentWillMount: function() {
@@ -30,6 +33,8 @@ module.exports = {
cli.on("Room", this.onRoom);
cli.on("Room.timeline", this.onRoomTimeline);
cli.on("Room.name", this.onRoomName);
cli.on("RoomState.events", this.onRoomStateEvents);
cli.on("RoomMember.name", this.onRoomMemberName);
var rooms = this.getRoomList();
this.setState({
@@ -38,16 +43,38 @@ module.exports = {
});
},
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
},
onAction: function(payload) {
switch (payload.action) {
// listen for call state changes to prod the render method, which
// may hide the global CallView if the call it is tracking is dead
case 'call_state':
this._recheckCallElement(this.props.selectedRoom);
break;
case 'view_tooltip':
this.tooltip = payload.tooltip;
this._repositionTooltip();
if (this.tooltip) this.tooltip.style.display = 'block';
break
}
},
componentWillUnmount: function() {
dis.unregister(this.dispatcherRef);
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("Room", this.onRoom);
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
}
},
componentWillReceiveProps: function(newProps) {
this.state.activityMap[newProps.selectedRoom] = undefined;
this._recheckCallElement(newProps.selectedRoom);
this.setState({
activityMap: this.state.activityMap
});
@@ -73,13 +100,11 @@ module.exports = {
if (actions && actions.tweaks && actions.tweaks.highlight) {
hl = 2;
}
if (actions.notify) {
// obviously this won't deep copy but this shouldn't be necessary
var amap = this.state.activityMap;
amap[room.roomId] = Math.max(amap[room.roomId] || 0, hl);
// obviously this won't deep copy but this shouldn't be necessary
var amap = this.state.activityMap;
amap[room.roomId] = Math.max(amap[room.roomId] || 0, hl);
newState.activityMap = amap;
}
newState.activityMap = amap;
}
this.setState(newState);
},
@@ -88,6 +113,15 @@ module.exports = {
this.refreshRoomList();
},
onRoomStateEvents: function(ev, state) {
setTimeout(this.refreshRoomList, 0);
},
onRoomMemberName: function(ev, member) {
setTimeout(this.refreshRoomList, 0);
},
refreshRoomList: function() {
var rooms = this.getRoomList();
this.setState({
@@ -96,23 +130,65 @@ module.exports = {
},
getRoomList: function() {
return RoomListSorter.mostRecentActivityFirst(MatrixClientPeg.get().getRooms());
return RoomListSorter.mostRecentActivityFirst(
MatrixClientPeg.get().getRooms().filter(function(room) {
var me = room.getMember(MatrixClientPeg.get().credentials.userId);
var shouldShowRoom = (
me && (me.membership == "join" || me.membership == "invite")
);
// hiding conf rooms only ever toggles shouldShowRoom to false
if (shouldShowRoom && HIDE_CONFERENCE_CHANS) {
// we want to hide the 1:1 conf<->user room and not the group chat
var joinedMembers = room.getJoinedMembers();
if (joinedMembers.length === 2) {
var otherMember = joinedMembers.filter(function(m) {
return m.userId !== me.userId
})[0];
if (VectorConferenceHandler.isConferenceUser(otherMember)) {
// console.log("Hiding conference 1:1 room %s", room.roomId);
shouldShowRoom = false;
}
}
}
return shouldShowRoom;
})
);
},
_recheckCallElement: function(selectedRoomId) {
// if we aren't viewing a room with an ongoing call, but there is an
// active call, show the call element - we need to do this to make
// audio/video not crap out
var activeCall = CallHandler.getAnyActiveCall();
var callForRoom = CallHandler.getCallForRoom(selectedRoomId);
var showCall = (activeCall && !callForRoom);
this.setState({
show_call_element: showCall
});
},
_repositionTooltip: function(e) {
if (this.tooltip && this.tooltip.parentElement) {
var scroll = this.getDOMNode();
this.tooltip.style.top = (scroll.parentElement.offsetTop + this.tooltip.parentElement.offsetTop - scroll.scrollTop) + "px";
}
},
makeRoomTiles: function() {
var that = this;
var self = this;
var RoomTile = sdk.getComponent("molecules.RoomTile");
return this.state.roomList.map(function(room) {
var selected = room.roomId == that.props.selectedRoom;
var selected = room.roomId == self.props.selectedRoom;
return (
<RoomTile
room={room}
key={room.roomId}
collapsed={self.props.collapsed}
selected={selected}
unread={that.state.activityMap[room.roomId] === 1}
highlight={that.state.activityMap[room.roomId] === 2}
unread={self.state.activityMap[room.roomId] === 1}
highlight={self.state.activityMap[room.roomId] === 2}
/>
);
});
},
}
};

View File

@@ -14,36 +14,39 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
var MatrixClientPeg = require("../../MatrixClientPeg");
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
var React = require("react");
var q = require("q");
var ContentMessages = require("../../ContentMessages");
var ContentMessages = require("matrix-react-sdk/lib//ContentMessages");
var WhoIsTyping = require("matrix-react-sdk/lib/WhoIsTyping");
var Modal = require("matrix-react-sdk/lib/Modal");
var sdk = require('matrix-react-sdk/lib/index');
var CallHandler = require('matrix-react-sdk/lib/CallHandler');
var VectorConferenceHandler = require('../../modules/VectorConferenceHandler');
var dis = require("../../dispatcher");
var dis = require("matrix-react-sdk/lib/dispatcher");
var PAGINATE_SIZE = 20;
var INITIAL_SIZE = 100;
var ComponentBroker = require('../../ComponentBroker');
var tileTypes = {
'm.room.message': ComponentBroker.get('molecules/MessageTile'),
'm.room.member': ComponentBroker.get('molecules/MRoomMemberTile')
};
var INITIAL_SIZE = 20;
module.exports = {
getInitialState: function() {
return {
room: this.props.roomId ? MatrixClientPeg.get().getRoom(this.props.roomId) : null,
messageCap: INITIAL_SIZE
messageCap: INITIAL_SIZE,
editingRoomSettings: false,
uploadingRoomSettings: false,
numUnreadMessages: 0,
draggingFile: false,
}
},
componentWillMount: function() {
this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().on("Room.name", this.onRoomName);
MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
this.atBottom = true;
},
@@ -51,19 +54,47 @@ module.exports = {
if (this.refs.messageWrapper) {
var messageWrapper = this.refs.messageWrapper.getDOMNode();
messageWrapper.removeEventListener('drop', this.onDrop);
messageWrapper.removeEventListener('dragover', this.onDragOver);
messageWrapper.removeEventListener('dragleave', this.onDragLeaveOrEnd);
messageWrapper.removeEventListener('dragend', this.onDragLeaveOrEnd);
}
dis.unregister(this.dispatcherRef);
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
MatrixClientPeg.get().removeListener("RoomMember.typing", this.onRoomMemberTyping);
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
}
},
onAction: function(payload) {
switch (payload.action) {
case 'message_send_failed':
case 'message_sent':
case 'message_resend_started':
this.setState({
room: MatrixClientPeg.get().getRoom(this.props.roomId)
});
this.forceUpdate();
break;
case 'notifier_enabled':
this.forceUpdate();
break;
case 'call_state':
if (CallHandler.getCallForRoom(this.props.roomId)) {
// Call state has changed so we may be loading video elements
// which will obscure the message log.
// scroll to bottom
var messageWrapper = this.refs.messageWrapper;
if (messageWrapper) {
messageWrapper = messageWrapper.getDOMNode();
messageWrapper.scrollTop = messageWrapper.scrollHeight;
}
}
// possibly remove the conf call notification if we're now in
// the conf
this._updateConfCallNotification();
break;
}
},
@@ -87,13 +118,31 @@ 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;
this.atBottom = (
messageWrapper.scrollHeight - messageWrapper.scrollTop <=
(messageWrapper.clientHeight + 150)
);
}
var currentUnread = this.state.numUnreadMessages;
if (!toStartOfTimeline &&
(ev.getSender() !== MatrixClientPeg.get().credentials.userId)) {
// update unread count when scrolled up
if (this.atBottom) {
currentUnread = 0;
}
else {
currentUnread += 1;
}
}
this.setState({
room: MatrixClientPeg.get().getRoom(this.props.roomId)
room: MatrixClientPeg.get().getRoom(this.props.roomId),
numUnreadMessages: currentUnread
});
if (toStartOfTimeline && !this.state.paginating) {
@@ -101,17 +150,63 @@ module.exports = {
}
},
onRoomName: function(room) {
if (room.roomId == this.props.roomId) {
this.setState({
room: room
});
}
},
onRoomMemberTyping: function(ev, member) {
this.forceUpdate();
},
onRoomStateMember: function(ev, state, member) {
if (member.roomId !== this.props.roomId ||
member.userId !== VectorConferenceHandler.getConferenceUserIdForRoom(member.roomId)) {
return;
}
this._updateConfCallNotification();
},
_updateConfCallNotification: function() {
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
if (!room) return;
var confMember = room.getMember(
VectorConferenceHandler.getConferenceUserIdForRoom(this.props.roomId)
);
if (!confMember) {
return;
}
var confCall = VectorConferenceHandler.getConferenceCallForRoom(confMember.roomId);
// A conf call notification should be displayed if there is an ongoing
// conf call but this cilent isn't a part of it.
this.setState({
displayConfCallNotification: (
(!confCall || confCall.call_state === "ended") &&
confMember.membership === "join"
)
});
},
componentDidMount: function() {
if (this.refs.messageWrapper) {
var messageWrapper = this.refs.messageWrapper.getDOMNode();
messageWrapper.addEventListener('drop', this.onDrop);
messageWrapper.addEventListener('dragover', this.onDragOver);
messageWrapper.addEventListener('dragleave', this.onDragLeaveOrEnd);
messageWrapper.addEventListener('dragend', this.onDragLeaveOrEnd);
messageWrapper.scrollTop = messageWrapper.scrollHeight;
this.fillSpace();
}
this._updateConfCallNotification();
},
componentDidUpdate: function() {
@@ -128,10 +223,14 @@ module.exports = {
}
} else if (this.atBottom) {
messageWrapper.scrollTop = messageWrapper.scrollHeight;
if (this.state.numUnreadMessages !== 0) {
this.setState({numUnreadMessages: 0});
}
}
},
fillSpace: function() {
if (!this.refs.messageWrapper) return;
var messageWrapper = this.refs.messageWrapper.getDOMNode();
if (messageWrapper.scrollTop < messageWrapper.clientHeight && this.state.room.oldState.paginationToken) {
this.setState({paginating: true});
@@ -146,12 +245,12 @@ module.exports = {
this.waiting_for_paginate = true;
var cap = this.state.messageCap + PAGINATE_SIZE;
this.setState({messageCap: cap, paginating: true});
var that = this;
var self = this;
MatrixClientPeg.get().scrollback(this.state.room, PAGINATE_SIZE).finally(function() {
that.waiting_for_paginate = false;
if (that.isMounted()) {
that.setState({
room: MatrixClientPeg.get().getRoom(that.props.roomId)
self.waiting_for_paginate = false;
if (self.isMounted()) {
self.setState({
room: MatrixClientPeg.get().getRoom(self.props.roomId)
});
}
// wait and set paginating to false when the component updates
@@ -164,14 +263,14 @@ module.exports = {
},
onJoinButtonClicked: function(ev) {
var that = this;
var self = this;
MatrixClientPeg.get().joinRoom(this.props.roomId).then(function() {
that.setState({
self.setState({
joining: false,
room: MatrixClientPeg.get().getRoom(that.props.roomId)
room: MatrixClientPeg.get().getRoom(self.props.roomId)
});
}, function(error) {
that.setState({
self.setState({
joining: false,
joinError: error
});
@@ -184,7 +283,11 @@ module.exports = {
onMessageListScroll: function(ev) {
if (this.refs.messageWrapper) {
var messageWrapper = this.refs.messageWrapper.getDOMNode();
var wasAtBottom = this.atBottom;
this.atBottom = messageWrapper.scrollHeight - messageWrapper.scrollTop <= messageWrapper.clientHeight;
if (this.atBottom && !wasAtBottom) {
this.forceUpdate(); // remove unread msg count
}
}
if (!this.state.paginating) this.fillSpace();
},
@@ -198,6 +301,7 @@ module.exports = {
var items = ev.dataTransfer.items;
if (items.length == 1) {
if (items[0].kind == 'file') {
this.setState({ draggingFile : true });
ev.dataTransfer.dropEffect = 'copy';
}
}
@@ -206,33 +310,194 @@ module.exports = {
onDrop: function(ev) {
ev.stopPropagation();
ev.preventDefault();
this.setState({ draggingFile : false });
var files = ev.dataTransfer.files;
if (files.length == 1) {
ContentMessages.sendContentToRoom(
files[0], this.props.roomId, MatrixClientPeg.get()
).progress(function(ev) {
//console.log("Upload: "+ev.loaded+" / "+ev.total);
}).done(undefined, function() {
// display error message
});
this.uploadFile(files[0]);
}
},
onDragLeaveOrEnd: function(ev) {
ev.stopPropagation();
ev.preventDefault();
this.setState({ draggingFile : false });
},
uploadFile: function(file) {
this.setState({
upload: {
fileName: file.name,
uploadedBytes: 0,
totalBytes: file.size
}
});
var self = this;
ContentMessages.sendContentToRoom(
file, this.props.roomId, MatrixClientPeg.get()
).progress(function(ev) {
//console.log("Upload: "+ev.loaded+" / "+ev.total);
self.setState({
upload: {
fileName: file.name,
uploadedBytes: ev.loaded,
totalBytes: ev.total
}
});
}).finally(function() {
self.setState({
upload: undefined
});
}).done(undefined, function() {
// display error message
});
},
getWhoIsTypingString: function() {
return WhoIsTyping.whoIsTypingString(this.state.room);
},
getEventTiles: function() {
var DateSeparator = sdk.getComponent('molecules.DateSeparator');
var ret = [];
var count = 0;
var EventTile = sdk.getComponent('molecules.EventTile');
for (var i = this.state.room.timeline.length-1; i >= 0 && count < this.state.messageCap; --i) {
var mxEv = this.state.room.timeline[i];
var TileType = tileTypes[mxEv.getType()];
if (!TileType) continue;
if (!EventTile.supportsEventType(mxEv.getType())) {
continue;
}
var continuation = false;
var last = false;
var dateSeparator = null;
if (i == this.state.room.timeline.length - 1) {
last = true;
}
if (i > 0 && count < this.state.messageCap - 1) {
if (this.state.room.timeline[i].sender &&
this.state.room.timeline[i - 1].sender &&
(this.state.room.timeline[i].sender.userId ===
this.state.room.timeline[i - 1].sender.userId) &&
(this.state.room.timeline[i].getType() ==
this.state.room.timeline[i - 1].getType())
)
{
continuation = true;
}
var ts0 = this.state.room.timeline[i - 1].getTs();
var ts1 = this.state.room.timeline[i].getTs();
if (new Date(ts0).toDateString() !== new Date(ts1).toDateString()) {
dateSeparator = <DateSeparator key={ts1} ts={ts1}/>;
continuation = false;
}
}
if (i === 1) { // n.b. 1, not 0, as the 0th event is an m.room.create and so doesn't show on the timeline
var ts1 = this.state.room.timeline[i].getTs();
dateSeparator = <li key={ts1}><DateSeparator ts={ts1}/></li>;
continuation = false;
}
ret.unshift(
<TileType key={mxEv.getId()} mxEvent={mxEv} />
<li key={mxEv.getId()}><EventTile mxEvent={mxEv} continuation={continuation} last={last}/></li>
);
if (dateSeparator) {
ret.unshift(dateSeparator);
}
++count;
}
return ret;
},
uploadNewState: function(new_name, new_topic, new_join_rule, new_history_visibility, new_power_levels) {
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', '');
if (old_history_visibility) {
old_history_visibility = old_history_visibility.getContent().history_visibility;
} else {
old_history_visibility = "shared";
}
var deferreds = [];
if (old_name != new_name && new_name != undefined && new_name) {
deferreds.push(
MatrixClientPeg.get().setRoomName(this.state.room.roomId, new_name)
);
}
if (old_topic != new_topic && new_topic != undefined) {
deferreds.push(
MatrixClientPeg.get().setRoomTopic(this.state.room.roomId, new_topic)
);
}
if (old_join_rule != new_join_rule && new_join_rule != undefined) {
deferreds.push(
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) {
deferreds.push(
MatrixClientPeg.get().sendStateEvent(
this.state.room.roomId, "m.room.history_visibility", {
history_visibility: new_history_visibility,
}, ""
)
);
}
if (new_power_levels) {
deferreds.push(
MatrixClientPeg.get().sendStateEvent(
this.state.room.roomId, "m.room.power_levels", new_power_levels, ""
)
);
}
if (deferreds.length) {
var self = this;
q.all(deferreds).fail(function(err) {
var ErrorDialog = sdk.getComponent("organisms.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to set state",
description: err.toString()
});
}).finally(function() {
self.setState({
uploadingRoomSettings: false,
});
});
} else {
this.setState({
editingRoomSettings: false,
uploadingRoomSettings: false,
});
}
}
};

View File

@@ -1,202 +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';
// should be atomised
var Loader = require("react-loader");
var MatrixClientPeg = require("../../MatrixClientPeg");
var RoomListSorter = require("../../RoomListSorter");
var dis = require("../../dispatcher");
var ComponentBroker = require('../../ComponentBroker');
var Notifier = ComponentBroker.get('organisms/Notifier');
module.exports = {
getInitialState: function() {
return {
logged_in: !!(MatrixClientPeg.get() && MatrixClientPeg.get().credentials),
ready: false
};
},
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
if (this.state.logged_in) {
this.startMatrixClient();
}
this.focusComposer = false;
document.addEventListener("keydown", this.onKeyDown);
window.addEventListener("focus", this.onFocus);
if (this.state.logged_in) {
this.notifyNewScreen('');
} else {
this.notifyNewScreen('login');
}
},
componentWillUnmount: function() {
dis.unregister(this.dispatcherRef);
document.removeEventListener("keydown", this.onKeyDown);
},
componentDidUpdate: function() {
if (this.focusComposer) {
dis.dispatch({action: 'focus_composer'});
this.focusComposer = false;
}
},
onAction: function(payload) {
var roomIndexDelta = 1;
switch (payload.action) {
case 'logout':
this.replaceState({
logged_in: false,
ready: false
});
if (window.localStorage) {
window.localStorage.clear();
}
Notifier.stop();
MatrixClientPeg.get().removeAllListeners();
MatrixClientPeg.replace(null);
break;
case 'start_registration':
if (this.state.logged_in) return;
var newState = payload.params || {};
newState.screen = 'register';
if (
payload.params &&
payload.params.client_secret &&
payload.params.session_id &&
payload.params.hs_url &&
payload.params.is_url &&
payload.params.sid
) {
newState.register_client_secret = payload.params.client_secret;
newState.register_session_id = payload.params.session_id;
newState.register_hs_url = payload.params.hs_url;
newState.register_is_url = payload.params.is_url;
newState.register_id_sid = payload.params.sid;
}
this.replaceState(newState);
this.notifyNewScreen('register');
break;
case 'start_login':
if (this.state.logged_in) return;
this.replaceState({
screen: 'login'
});
this.notifyNewScreen('login');
break;
case 'view_room':
this.focusComposer = true;
this.setState({
currentRoom: payload.room_id
});
break;
case 'view_prev_room':
roomIndexDelta = -1;
case 'view_next_room':
var allRooms = RoomListSorter.mostRecentActivityFirst(
MatrixClientPeg.get().getRooms()
);
var roomIndex = -1;
for (var i = 0; i < allRooms.length; ++i) {
if (allRooms[i].roomId == this.state.currentRoom) {
roomIndex = i;
break;
}
}
roomIndex = (roomIndex + roomIndexDelta) % allRooms.length;
this.setState({
currentRoom: allRooms[roomIndex].roomId
});
break;
}
},
onLoggedIn: function() {
this.setState({
screen: undefined,
logged_in: true
});
this.startMatrixClient();
this.notifyNewScreen('');
},
startMatrixClient: function() {
var cli = MatrixClientPeg.get();
var that = this;
cli.on('syncComplete', function() {
var firstRoom = null;
if (cli.getRooms() && cli.getRooms().length) {
firstRoom = RoomListSorter.mostRecentActivityFirst(
cli.getRooms()
)[0].roomId;
}
that.setState({ready: true, currentRoom: firstRoom});
dis.dispatch({action: 'focus_composer'});
});
Notifier.start();
cli.startClient();
},
onKeyDown: function(ev) {
if (ev.altKey) {
switch (ev.keyCode) {
case 38:
dis.dispatch({action: 'view_prev_room'});
ev.stopPropagation();
break;
case 40:
dis.dispatch({action: 'view_next_room'});
ev.stopPropagation();
break;
}
}
},
onFocus: function(ev) {
dis.dispatch({action: 'focus_composer'});
},
showScreen: function(screen, params) {
if (screen == 'register') {
dis.dispatch({
action: 'start_registration',
params: params
});
} else if (screen == 'login') {
dis.dispatch({
action: 'start_login',
params: params
});
}
},
notifyNewScreen: function(screen) {
if (this.props.onNewScreen) {
this.props.onNewScreen(screen);
}
}
};

View File

@@ -1,98 +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 MatrixClientPeg = require("../../MatrixClientPeg");
var Matrix = require("matrix-js-sdk");
var dis = require("../../dispatcher");
var ComponentBroker = require("../../ComponentBroker");
module.exports = {
getInitialState: function() {
return {
step: 'choose_hs',
busy: false,
currentStep: 0,
totalSteps: 1
};
},
setStep: function(step) {
this.setState({ step: step, errorText: '', busy: false });
},
onHSChosen: function(ev) {
ev.preventDefault();
MatrixClientPeg.replaceUsingUrls(
this.getHsUrl(),
this.getIsUrl()
);
this.setState({
hs_url: this.getHsUrl(),
is_url: this.getIsUrl()
});
this.setStep("fetch_stages");
var cli = MatrixClientPeg.get();
this.setState({busy: true});
var that = this;
cli.loginFlows().done(function(result) {
that.setState({
flows: result.flows,
currentStep: 1,
totalSteps: result.flows.length+1
});
that.setStep('stage_'+result.flows[0].type);
}, function(error) {
that.setStep("choose_hs");
that.setState({errorText: 'Unable to contact the given Home Server'});
});
},
onUserPassEntered: function(ev) {
ev.preventDefault();
this.setState({busy: true});
var that = this;
var formVals = this.getFormVals();
MatrixClientPeg.get().login('m.login.password', {
'user': formVals.username,
'password': formVals.password
}).done(function(data) {
MatrixClientPeg.replaceUsingAccessToken(
that.state.hs_url, that.state.is_url,
data.user_id, data.access_token
);
if (that.props.onLoggedIn) {
that.props.onLoggedIn();
}
}, function(error) {
that.setStep("stage_m.login.password");
that.setState({errorText: 'Login failed.'});
});
},
showRegister: function(ev) {
ev.preventDefault();
dis.dispatch({
action: 'start_registration'
});
}
};

View File

@@ -16,326 +16,43 @@ limitations under the License.
'use strict';
var React = require('react');
var extend = require('matrix-react-sdk/lib/extend');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var BaseRegisterController = require('matrix-react-sdk/lib/controllers/templates/Register.js');
var MatrixClientPeg = require("../../MatrixClientPeg");
var Matrix = require("matrix-js-sdk");
var dis = require("../../dispatcher");
var RegisterController = {};
extend(RegisterController, BaseRegisterController);
var ComponentBroker = require("../../ComponentBroker");
RegisterController.onRegistered = function(user_id, access_token) {
MatrixClientPeg.replaceUsingAccessToken(
this.state.hs_url, this.state.is_url, user_id, access_token
);
module.exports = {
FieldErrors: {
PasswordMismatch: 'PasswordMismatch',
TooShort: 'TooShort',
Missing: 'Missing',
InUse: 'InUse'
},
this.setState({
step: 'profile',
busy: true
});
getInitialState: function() {
return {
step: 'initial',
busy: false,
currentStep: 0,
totalSteps: 1
};
},
componentWillMount: function() {
this.savedParams = {
email: '',
username: '',
password: '',
confirmPassword: ''
};
this.readNewProps();
},
componentWillReceiveProps: function() {
this.readNewProps();
},
readNewProps: function() {
if (this.props.clientSecret && this.props.hsUrl &&
this.props.isUrl && this.props.sessionId &&
this.props.idSid) {
this.authSessionId = this.props.sessionId;
MatrixClientPeg.replaceUsingUrls(
this.props.hsUrl,
this.props.isUrl
);
this.setState({
hs_url: this.props.hsUrl,
is_url: this.props.isUrl
});
this.savedParams = {client_secret: this.props.clientSecret};
this.setState({busy: true});
var isLocation = document.createElement('a');
isLocation.href = this.props.isUrl;
var auth = {
type: 'm.login.email.identity',
threepid_creds: {
sid: this.props.idSid,
client_secret: this.savedParams.client_secret,
id_server: isLocation.host
}
};
this.tryRegister(auth);
}
},
componentDidUpdate: function() {
// Just putting a script tag into the returned jsx doesn't work, annoyingly,
// so we do this instead.
if (this.refs.recaptchaContainer) {
var scriptTag = document.createElement('script');
window.mx_on_recaptcha_loaded = this.onCaptchaLoaded;
scriptTag.setAttribute('src', "https://www.google.com/recaptcha/api.js?onload=mx_on_recaptcha_loaded&render=explicit");
this.refs.recaptchaContainer.getDOMNode().appendChild(scriptTag);
}
},
setStep: function(step) {
this.setState({ step: step, errorText: '', busy: false });
},
getSupportedStageTypes: function() {
return ['m.login.email.identity', 'm.login.recaptcha'];
},
chooseFlow: function(flows) {
// this is fairly simple right now
var supportedTypes = this.getSupportedStageTypes();
var emailFlow = null;
var otherFlow = null;
for (var flowI = 0; flowI < flows.length; ++flowI) {
var flow = flows[flowI];
var flowHasEmail = false;
var flowSupported = true;
for (var stageI = 0; stageI < flow.stages.length; ++stageI) {
var stage = flow.stages[stageI];
if (supportedTypes.indexOf(stage) == -1) {
flowSupported = false;
}
if (stage == 'm.login.email.identity') {
flowHasEmail = true;
}
}
if (flowSupported) {
if (flowHasEmail) {
emailFlow = flow;
} else {
otherFlow = flow;
}
}
}
if (
this.savedParams.email != '' ||
this.completedStages.indexOf('m.login.email.identity') > -1
) {
return emailFlow;
} else {
return otherFlow;
}
},
firstUncompletedStageIndex: function(flow) {
if (this.completedStages === undefined) return 0;
for (var i = 0; i < flow.stages.length; ++i) {
if (this.completedStages.indexOf(flow.stages[i]) == -1) {
return i;
}
}
},
numCompletedStages: function(flow) {
if (this.completedStages === undefined) return 0;
var nCompleted = 0;
for (var i = 0; i < flow.stages.length; ++i) {
if (this.completedStages.indexOf(flow.stages[i]) > -1) {
++nCompleted;
}
}
return nCompleted;
},
onInitialStageSubmit: function(ev) {
ev.preventDefault();
var formVals = this.getRegFormVals();
this.savedParams = formVals;
var badFields = {};
if (formVals.password != formVals.confirmPassword) {
badFields.confirmPassword = this.FieldErrors.PasswordMismatch;
}
if (formVals.password == '') {
badFields.password = this.FieldErrors.Missing;
} else if (formVals.password.length < 6) {
badFields.password = this.FieldErrors.Length;
}
if (formVals.username == '') {
badFields.username = this.FieldErrors.Missing;
}
if (Object.keys(badFields).length > 0) {
this.onBadFields(badFields);
return;
}
MatrixClientPeg.replaceUsingUrls(
this.getHsUrl(),
this.getIsUrl()
);
this.setState({
hs_url: this.getHsUrl(),
is_url: this.getIsUrl()
});
var cli = MatrixClientPeg.get();
this.setState({busy: true});
var self = this;
this.savedParams = {
email: formVals.email,
username: formVals.username,
password: formVals.password
};
this.tryRegister();
},
startStage: function(stageName) {
var self = this;
this.setStep('stage_'+stageName);
switch(stageName) {
case 'm.login.email.identity':
self.setState({
busy: true
});
var cli = MatrixClientPeg.get();
this.savedParams.client_secret = cli.generateClientSecret();
this.savedParams.send_attempt = 1;
var nextLink = this.props.registrationUrl +
'?client_secret=' +
encodeURIComponent(this.savedParams.client_secret) +
"&hs_url=" +
encodeURIComponent(this.state.hs_url) +
"&is_url=" +
encodeURIComponent(this.state.is_url) +
"&session_id=" +
encodeURIComponent(this.authSessionId);
cli.requestEmailToken(
this.savedParams.email,
this.savedParams.client_secret,
this.savedParams.send_attempt,
nextLink
).done(function(response) {
self.setState({
busy: false,
});
self.setStep('stage_m.login.email.identity');
}, function(error) {
self.setState({
busy: false,
errorText: 'Unable to contact the given Home Server'
});
});
break;
case 'm.login.recaptcha':
if (!this.authParams || !this.authParams['m.login.recaptcha'].public_key) {
this.setState({
errorText: "This server has not supplied enough information for Recaptcha authentication"
});
}
break;
}
},
onRegistered: function(user_id, access_token) {
MatrixClientPeg.replaceUsingAccessToken(
this.state.hs_url, this.state.is_url, user_id, access_token
);
if (this.props.onLoggedIn) {
this.props.onLoggedIn();
}
},
onCaptchaLoaded: function() {
if (this.refs.recaptchaContainer) {
var sitekey = this.authParams['m.login.recaptcha'].public_key;
global.grecaptcha.render('mx_recaptcha', {
'sitekey': sitekey,
'callback': this.onCaptchaDone
});
}
},
onCaptchaDone: function(captcha_response) {
this.tryRegister({
type: 'm.login.recaptcha',
response: captcha_response
var self = this;
var cli = MatrixClientPeg.get();
cli.getProfileInfo(cli.credentials.userId).done(function(result) {
self.setState({
avatarUrl: result.avatar_url,
busy: false
});
},
tryRegister: function(auth) {
var self = this;
MatrixClientPeg.get().register(
this.savedParams.username,
this.savedParams.password,
this.authSessionId,
auth
).done(function(result) {
self.onRegistered(result.user_id, result.access_token);
}, function(error) {
if (error.httpStatus == 401 && error.data.flows) {
self.authParams = error.data.params;
self.authSessionId = error.data.session;
self.completedStages = error.data.completed || [];
var flow = self.chooseFlow(error.data.flows);
var flowStage = self.firstUncompletedStageIndex(flow);
var numDone = self.numCompletedStages(flow);
self.setState({
busy: false,
flows: flow,
currentStep: 1+numDone,
totalSteps: flow.stages.length+1,
flowStage: flowStage
});
self.startStage(flow.stages[flowStage]);
} else {
self.setStep("initial");
var newState = {
busy: false,
errorText: "Unable to contact the given Home Server"
};
if (error.name == 'M_USER_IN_USE') {
delete newState.errorText;
self.onBadFields({
username: self.FieldErrors.InUse
});
} else if (error.httpStatus == 401) {
newState.errorText = "Authorisation failed!";
}
self.setState(newState);
}
function(err) {
console.err(err);
self.setState({
busy: false
});
},
});
};
showLogin: function(ev) {
ev.preventDefault();
dis.dispatch({
action: 'start_login'
});
RegisterController.onAccountReady = function() {
if (this.props.onLoggedIn) {
this.props.onLoggedIn();
}
};
module.exports = RegisterController;

View File

@@ -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 flux = require("flux");
var extend = require("./extend");
var MatrixDispatcher = function() {
flux.Dispatcher.call(this);
};
extend(MatrixDispatcher.prototype, flux.Dispatcher.prototype);
MatrixDispatcher.prototype.dispatch = function(payload) {
if (this.dispatching) {
setTimeout(flux.Dispatcher.prototype.dispatch.bind(this, payload), 0);
} else {
this.dispatching = true;
flux.Dispatcher.prototype.dispatch.call(this, payload);
this.dispatching = false;
}
}
module.exports = new MatrixDispatcher();

View File

@@ -1,26 +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';
module.exports = function(dest, src) {
for (var i in src) {
if (src.hasOwnProperty(i)) {
dest[i] = src[i];
}
}
return dest;
}

View File

@@ -1,19 +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';
module.exports.MatrixChat = require("../skins/base/views/pages/MatrixChat");

View File

@@ -1,116 +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 extend = require('./extend');
function matrixLinkify(linkify) {
// Text tokens
var TT = linkify.scanner.TOKENS;
var TextToken = TT.Base;
// Multi tokens
var MT = linkify.parser.TOKENS;
var MultiToken = MT.Base;
var S_START = linkify.parser.start;
var ROOMALIAS = function(value) {
MultiToken.call(this, value);
this.type = 'roomalias';
this.isLink = true;
};
ROOMALIAS.prototype = new MultiToken();
var S_HASH = new linkify.parser.State();
var S_HASH_NAME = new linkify.parser.State();
var S_HASH_NAME_COLON = new linkify.parser.State();
var S_HASH_NAME_COLON_DOMAIN = new linkify.parser.State();
var S_HASH_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
var S_ROOMALIAS = new linkify.parser.State(ROOMALIAS);
var roomname_tokens = [
TT.DOT,
TT.PLUS,
TT.NUM,
TT.DOMAIN,
TT.TLD
];
S_START.on(TT.POUND, S_HASH);
S_HASH.on(roomname_tokens, S_HASH_NAME);
S_HASH_NAME.on(roomname_tokens, S_HASH_NAME);
S_HASH_NAME.on(TT.DOMAIN, S_HASH_NAME);
S_HASH_NAME.on(TT.COLON, S_HASH_NAME_COLON);
S_HASH_NAME_COLON.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN);
S_HASH_NAME_COLON_DOMAIN.on(TT.DOT, S_HASH_NAME_COLON_DOMAIN_DOT);
S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN);
S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_ROOMALIAS);
var USERID = function(value) {
MultiToken.call(this, value);
this.type = 'userid';
this.isLink = true;
};
USERID.prototype = new MultiToken();
var S_AT = new linkify.parser.State();
var S_AT_NAME = new linkify.parser.State();
var S_AT_NAME_COLON = new linkify.parser.State();
var S_AT_NAME_COLON_DOMAIN = new linkify.parser.State();
var S_AT_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
var S_USERID = new linkify.parser.State(USERID);
var username_tokens = [
TT.DOT,
TT.PLUS,
TT.NUM,
TT.DOMAIN,
TT.TLD
];
S_START.on(TT.AT, S_AT);
S_AT.on(username_tokens, S_AT_NAME);
S_AT_NAME.on(username_tokens, S_AT_NAME);
S_AT_NAME.on(TT.DOMAIN, S_AT_NAME);
S_AT_NAME.on(TT.COLON, S_AT_NAME_COLON);
S_AT_NAME_COLON.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
S_AT_NAME_COLON_DOMAIN.on(TT.DOT, S_AT_NAME_COLON_DOMAIN_DOT);
S_AT_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID);
}
matrixLinkify.options = {
formatHref: function (href, type) {
switch (type) {
case 'roomalias':
return '#';
case 'userid':
return '#';
default:
return href;
}
}
}
module.exports = matrixLinkify;

View File

@@ -0,0 +1,134 @@
/*
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 q = require("q");
var Matrix = require("matrix-js-sdk");
var Room = Matrix.Room;
var CallHandler = require('matrix-react-sdk/lib/CallHandler');
// FIXME: This currently forces Vector to try to hit the matrix.org AS for conferencing.
// This is bad because it prevents people running their own ASes from being used.
// This isn't permanent and will be customisable in the future: see the proposal
// at docs/conferencing.md for more info.
var USER_PREFIX = "fs_";
var DOMAIN = "matrix.org";
function ConferenceCall(matrixClient, groupChatRoomId) {
this.client = matrixClient;
this.groupRoomId = groupChatRoomId;
this.confUserId = module.exports.getConferenceUserIdForRoom(this.groupRoomId);
}
ConferenceCall.prototype.setup = function() {
var self = this;
return this._joinConferenceUser().then(function() {
return self._getConferenceUserRoom();
}).then(function(room) {
// return a call for *this* room to be placed. We also tack on
// confUserId to speed up lookups (else we'd need to loop every room
// looking for a 1:1 room with this conf user ID!)
var call = Matrix.createNewMatrixCall(self.client, room.roomId);
call.confUserId = self.confUserId;
return call;
});
};
ConferenceCall.prototype._joinConferenceUser = function() {
// Make sure the conference user is in the group chat room
var groupRoom = this.client.getRoom(this.groupRoomId);
if (!groupRoom) {
return q.reject("Bad group room ID");
}
var member = groupRoom.getMember(this.confUserId);
if (member && member.membership === "join") {
return q();
}
return this.client.invite(this.groupRoomId, this.confUserId);
};
ConferenceCall.prototype._getConferenceUserRoom = function() {
// Use an existing 1:1 with the conference user; else make one
var rooms = this.client.getRooms();
var confRoom = null;
for (var i = 0; i < rooms.length; i++) {
var confUser = rooms[i].getMember(this.confUserId);
if (confUser && confUser.membership === "join" &&
rooms[i].getJoinedMembers().length === 2) {
confRoom = rooms[i];
break;
}
}
if (confRoom) {
return q(confRoom);
}
return this.client.createRoom({
preset: "private_chat",
invite: [this.confUserId]
}).then(function(res) {
return new Room(res.room_id);
});
};
/**
* Check if this room member is in fact a conference bot.
* @param {RoomMember} The room member to check
* @return {boolean} True if it is a conference bot.
*/
module.exports.isConferenceUser = function(roomMember) {
if (roomMember.userId.indexOf("@" + USER_PREFIX) !== 0) {
return false;
}
var base64part = roomMember.userId.split(":")[0].substring(1 + USER_PREFIX.length);
if (base64part) {
var decoded = new Buffer(base64part, "base64").toString();
// ! $STUFF : $STUFF
return /^!.+:.+/.test(decoded);
}
return false;
};
module.exports.getConferenceUserIdForRoom = function(roomId) {
// abuse browserify's core node Buffer support (strip padding ='s)
var base64RoomId = new Buffer(roomId).toString("base64").replace(/=/g, "");
return "@" + USER_PREFIX + base64RoomId + ":" + DOMAIN;
};
module.exports.createNewMatrixCall = function(client, roomId) {
var confCall = new ConferenceCall(
client, roomId
);
return confCall.setup();
};
module.exports.getConferenceCallForRoom = function(roomId) {
// search for a conference 1:1 call for this group chat room ID
var activeCall = CallHandler.getAnyActiveCall();
if (activeCall && activeCall.confUserId) {
var thisRoomConfUserId = module.exports.getConferenceUserIdForRoom(
roomId
);
if (thisRoomConfUserId === activeCall.confUserId) {
return activeCall;
}
}
return null;
};
module.exports.ConferenceCall = ConferenceCall;
module.exports.slot = 'conference';

View File

@@ -14,9 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_Login {
width: 600px;
height: 350px;
position: relative;
.mx_MemberAvatar {
z-index: 20;
border-radius: 20px;
background-color: #dbdbdb;
}

View File

@@ -15,6 +15,4 @@ limitations under the License.
*/
.mx_MessageTimestamp {
display: table-cell;
white-space: pre;
}

View File

@@ -0,0 +1,171 @@
/*
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.
*/
html {
/* hack to stop overscroll bounce on OSX and iOS.
N.B. Breaks things when we have legitimate horizontal overscroll */
height: 100%;
overflow: hidden;
}
body {
font-family: 'Lato', Helvetica, Arial, Sans-Serif;
font-size: 16px;
color: #454545;
border: 0px;
margin: 0px;
}
div.error {
color: red;
}
h2 {
color: #80cef4;
font-weight: 400;
font-size: 20px;
margin-top: 16px;
margin-bottom: 16px;
}
a:hover,
a:link,
a:visited {
color: #80CEF4;
}
.mx_ContextualMenu_background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 1.0;
z-index: 2000;
}
.mx_ContextualMenu {
border: 1px solid #a9dbf4;
border-radius: 8px;
background-color: #fff;
color: #747474;
position: fixed;
z-index: 2001;
padding: 6px;
}
.mx_ContextualMenu_chevron_right {
padding: 12px;
position: absolute;
right: -21px;
top: 0px;
}
.mx_ContextualMenu_chevron_left {
padding: 12px;
position: absolute;
left: -21px;
top: 0px;
}
.mx_ContextualMenu_field {
padding: 3px 6px 3px 6px;
cursor: pointer;
}
.mx_ContextualMenu_spinner {
display: block;
margin: 0 auto;
}
.mx_Dialog_background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000;
opacity: 0.2;
z-index: 2000;
}
.mx_Dialog_wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
}
.mx_Dialog {
background-color: #fff;
color: #747474;
text-align: center;
z-index: 2010;
font-weight: 300;
font-size: 16px;
position: relative;
border-radius: 8px;
max-width: 75%;
}
.mx_ImageView {
margin: 6px;
/* hack: flexbox bug? */
margin-bottom: 4px;
}
.mx_Dialog_content {
margin: 24px;
}
.mx_Dialog_buttons {
padding-bottom: 24px;
}
.mx_Dialog button {
border: 0px;
height: 36px;
border-radius: 36px;
font-weight: 400;
font-size: 16px;
color: #fff;
background-color: #80cef4;
margin-left: 8px;
margin-right: 8px;
padding-left: 1em;
padding-right: 1em;
}
.mx_ErrorDialogTitle,
.mx_QuestionDialogTitle {
min-height: 16px;
padding: 12px;
border-bottom: 1px solid #a9dbf4;
font-weight: bold;
font-size: 20px;
line-height: 1.4;
}

View File

@@ -0,0 +1,10 @@
.mx_RoomDropTarget,
.mx_RoomList_favourites_label,
.mx_RoomList_archive_label,
.mx_RoomHeader_search,
.mx_RoomSettings_encrypt,
.mx_CreateRoom_encrypt,
.mx_RightPanel_filebutton
{
display: none !important;
}

View File

@@ -0,0 +1,112 @@
/*
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_EventTile {
max-width: 100%;
clear: both;
margin-top: 32px;
margin-left: 56px;
}
.mx_EventTile_avatar {
padding-left: 12px;
padding-right: 12px;
margin-left: -64px;
margin-top: -7px;
float: left;
}
.mx_EventTile_avatar img {
background-color: #dbdbdb;
border-radius: 20px;
border: 0px;
}
.mx_EventTile_continuation {
margin-top: 8px ! important;
}
.mx_EventTile .mx_SenderProfile {
color: #454545;
opacity: 0.5;
font-size: 14px;
margin-bottom: 4px;
display: block;
}
.mx_EventTile .mx_MessageTimestamp {
color: #454545;
opacity: 0.5;
font-size: 14px;
float: right;
}
.mx_EventTile_content {
padding-right: 100px;
display: block;
}
.mx_EventTile_notice .mx_MessageTile_content {
opacity: 0.5;
}
.mx_EventTile_sending {
color: #ddd;
}
.mx_EventTile_notSent {
color: #f11;
}
.mx_EventTile_highlight {
color: #FF0064;
}
.mx_EventTile_msgOption {
float: right;
}
.mx_MessageTimestamp {
display: none;
}
.mx_EventTile_last .mx_MessageTimestamp {
display: block;
}
.mx_EventTile:hover .mx_MessageTimestamp {
display: block;
}
.mx_EventTile_editButton {
float: right;
display: none;
border: 0px;
outline: none;
margin-right: 3px;
}
.mx_EventTile:hover .mx_EventTile_editButton {
display: inline-block;
}
.mx_EventTile.menu .mx_EventTile_editButton {
display: inline-block;
}
.mx_EventTile.menu .mx_MessageTimestamp {
display: inline-block;
}

View File

@@ -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_MImageTile_thumbnail {
/*
background-color: #fff;
border: 2px solid #fff;
border-radius: 1px;
*/
}
.mx_MImageTile_download {
color: #80cef4;
cursor: pointer;
}
.mx_MImageTile_download a {
color: #80cef4;
text-decoration: none;
}
.mx_MImageTile_download img {
padding-right: 8px;
}

View File

@@ -15,4 +15,5 @@ limitations under the License.
*/
.mx_MNoticeTile {
opacity: 0.5;
}

View File

@@ -0,0 +1,34 @@
/*
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_MatrixToolbar {
text-align: center;
background-color: #ff0064;
color: #fff;
font-weight: bold;
padding: 6px;
}
.mx_MatrixToolbar button {
margin-left: 12px;
}
.mx_MatrixToolbar_close {
float: right;
margin-top: 3px;
margin-right: 12px;
cursor: pointer;
}

View File

@@ -14,5 +14,3 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RoomList {
}

View File

@@ -0,0 +1,134 @@
/*
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 {
display: table-row;
height: 49px;
position: relative;
}
.mx_MemberTile_avatar {
display: table-cell;
padding-left: 14px;
padding-right: 12px;
padding-top: 3px;
padding-bottom: 3px;
vertical-align: middle;
width: 40px;
height: 40px;
position: relative;
}
.mx_MemberTile_inviteTile {
cursor: pointer;
}
.mx_MemberTile_inviteEditing {
display: initial ! important;
}
.mx_MemberTile_inviteEditing .mx_MemberTile_avatar {
display: none;
}
.mx_MemberTile_inviteEditing .mx_MemberTile_name {
width: 200px;
}
.mx_MemberTile_inviteEditing .mx_MemberTile_name input {
border-radius: 3px;
border: 1px solid #c7c7c7;
font-weight: 300;
font-size: 14px;
padding: 9px;
margin-top: 6px;
margin-left: 14px;
}
.mx_MemberTile_power {
position: absolute;
width: 48px;
height: 48px;
left: 10px;
top: -1px;
}
.mx_MemberTile_name {
display: table-cell;
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
}
.mx_MemberTile_details {
display: table-cell;
padding-right: 14px;
vertical-align: middle;
}
.mx_MemberTile_hover {
background-color: #f0f0f0;
font-size: 12px;
color: #747474;
}
.mx_MemberTile_userId {
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
}
.mx_MemberTile_leave {
cursor: pointer;
margin-top: 8px;
margin-right: -4px;
margin-left: 6px;
float: right;
}
/*
.mx_MemberTile_nameWrapper {
display: table-cell;
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
}
.mx_MemberTile_nameSpan {
}
*/
.mx_MemberTile_unavailable .mx_MemberTile_avatar,
.mx_MemberTile_unavailable .mx_MemberTile_name,
.mx_MemberTile_unavailable .mx_MemberTile_nameSpan
{
opacity: 0.66;
}
.mx_MemberTile_offline .mx_MemberTile_avatar,
.mx_MemberTile_offline .mx_MemberTile_name,
.mx_MemberTile_offline .mx_MemberTile_nameSpan
{
opacity: 0.25;
}
.mx_MemberTile_zalgo {
font-family: Helvetica, Arial, Sans-Serif;
}
.mx_MemberTile:hover .mx_MessageTimestamp {
display: block;
}

View File

@@ -0,0 +1,84 @@
/*
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_MessageComposer_wrapper {
max-width: 720px;
height: 50px;
vertical-align: middle;
margin: auto;
background-color: #fff;
border-radius: 25px;
border: 1px solid #a9dbf4;
}
.mx_MessageComposer_row {
display: table-row;
width: 100%;
height: 50px;
}
.mx_MessageComposer .mx_MessageComposer_avatar {
display: table-cell;
padding-left: 5px;
padding-right: 10px;
height: 50px;
}
.mx_MessageComposer .mx_MessageComposer_avatar img {
margin-top: 5px;
border-radius: 20px;
background-color: #dbdbdb;
}
.mx_MessageComposer_input {
display: table-cell;
width: 100%;
vertical-align: middle;
height: 50px;
}
.mx_MessageComposer_input textarea {
font-size: 15px;
width: 100%;
height: 1.2em;
padding-top: 0.7em;
padding-bottom: 0.7em;
border: 0px;
resize: none;
outline: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
/* needed for FF */
font-family: 'Lato', Helvetica, Arial, Sans-Serif;
}
/* hack for FF as vertical alignment of custom placeholder text is broken */
.mx_MessageComposer_input textarea::-moz-placeholder {
line-height: 100%;
}
.mx_MessageComposer_upload {
display: table-cell;
vertical-align: middle;
padding-right: 15px;
cursor: pointer;
}
.mx_MessageComposer_upload img {
margin-top: 5px;
}

View File

@@ -14,10 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
body {
font-family: Helvetica, Arial, Sans-Serif;
}
div.error {
color: red;
.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;
}

View File

@@ -0,0 +1,173 @@
/*
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_RoomHeader {
}
.mx_RoomHeader_wrapper {
max-width: 720px;
margin: auto;
height: 88px;
border-bottom: 1px solid #a8dbf3;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
.mx_RoomHeader_leftRow {
height: 48px;
margin-top: 18px;
-webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1;
-ms-flex-order: 1;
-webkit-order: 1;
order: 1;
-webkit-flex: 1;
flex: 1;
}
.mx_RoomHeader_textButton {
height: 48px;
margin-top: 18px;
background-color: #80cef4;
border-radius: 48px;
margin-right: 8px;
color: #fff;
line-height: 48px;
text-align: center;
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
-ms-flex-order: 2;
-webkit-order: 2;
order: 2;
cursor: pointer;
/*
-webkit-flex: 0 0 90px;
flex: 0 0 90px;
*/
padding-left: 12px;
padding-right: 12px;
}
.mx_RoomHeader_rightRow {
height: 48px;
margin-top: 18px;
background-color: #fff;
border-radius: 48px;
border: 1px solid #a9dbf4;
-webkit-box-ordinal-group: 3;
-moz-box-ordinal-group: 3;
-ms-flex-order: 3;
-webkit-order: 3;
order: 3;
}
.mx_RoomHeader_info {
display: table-cell;
height: 48px;
vertical-align: middle;
}
.mx_RoomHeader_simpleHeader {
line-height: 88px;
color: #80cef4;
font-weight: 400;
font-size: 20px;
overflow: hidden;
text-overflow: ellipsis;
}
.mx_RoomHeader_name {
vertical-align: middle;
height: 28px;
color: #80cef4;
font-weight: 400;
font-size: 20px;
padding-left: 16px;
padding-right: 16px;
text-overflow: ellipsis;
}
.mx_RoomHeader_nameEditing {
padding-left: 16px;
padding-right: 16px;
margin-top: -5px;
}
.mx_RoomHeader_name input, .mx_RoomHeader_nameInput {
border-radius: 3px;
width: 260px;
border: 1px solid #c7c7c7;
font-weight: 300;
font-size: 14px;
padding: 9px;
}
.mx_RoomHeader_nameInput {
margin-top: 6px;
}
.mx_RoomHeader_topic {
vertical-align: bottom;
float: left;
max-height: 38px;
color: #70b5d7;
font-weight: 300;
padding-left: 16px;
padding-right: 16px;
overflow: hidden;
text-overflow: ellipsis;
}
.mx_RoomHeader_avatar {
display: table-cell;
width: 48px;
height: 50px;
vertical-align: middle;
}
.mx_RoomHeader_avatar img {
border-radius: 24px;
}
.mx_RoomHeader_button {
height: 48px;
display: table-cell;
vertical-align: middle;
padding-left: 8px;
padding-right: 8px;
}
.mx_RoomHeader_button img {
cursor: pointer;
}
.mx_RoomHeader_voipButton {
display: table-cell;
}
.mx_RoomHeader_voipButtons {
margin-top: 18px;
}

View File

@@ -0,0 +1,70 @@
/*
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_RoomSettings {
max-height: 250px;
padding-top: 12px;
}
.mx_RoomSettings_settings {
display: table;
margin: 5px 0;
}
.mx_RoomSettings_settings > div {
display: table-row;
}
.mx_RoomSettings_settings > div > * {
display: table-cell;
margin: 0 10px;
}
.mx_RoomSettings input,
.mx_RoomSettings textarea {
border-radius: 3px;
border: 1px solid #c7c7c7;
font-weight: 300;
font-size: 14px;
padding: 9px;
margin-top: 6px;
}
.mx_RoomSettings_description {
width: 330px;
}
.mx_RoomSettings_buttons {
text-align: right;
margin-bottom: 16px;
}
.mx_RoomSettings_button {
display: inline;
border: 0px;
height: 36px;
border-radius: 36px;
font-weight: 400;
font-size: 16px;
color: #fff;
background-color: #80cef4;
width: auto;
margin: auto;
padding: 6px;
padding-left: 1em;
padding-right: 1em;
}

View File

@@ -0,0 +1,104 @@
/*
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_RoomTile {
cursor: pointer;
display: table-row;
color: #818794;
}
.mx_RoomTile_avatar {
display: table-cell;
padding-right: 10px;
padding-top: 3px;
padding-bottom: 3px;
padding-left: 10px;
vertical-align: middle;
width: 36px;
height: 36px;
position: relative;
}
.mx_RoomTile_avatar img {
border-radius: 20px;
background-color: #dbdbdb;
}
.mx_RoomTile_name {
display: table-cell;
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 16px;
}
.collapsed .mx_RoomTile_name {
display: none;
}
/*
.mx_RoomTile_nameBadge {
display: table;
width: 100%;
height: 50px;
}
.mx_RoomTile_badgeCell {
display: table-cell;
vertical-align: middle;
width: 26px;
}
.mx_RoomTile_badge {
background-color: #80cef4;
color: #fff;
border-radius: 26px;
font-weight: 400;
font-size: 14px;
line-height: 28px;
width: 26px;
height: 26px;
text-align: center;
}
*/
.mx_RoomTile_badge {
background-color: #ff0064;
border: 3px solid #fff;
border-radius: 16px;
width: 9px;
height: 9px;
position: absolute;
right: 9px;
bottom: 3px;
}
.mx_RoomTile_unread,
.mx_RoomTile_highlight,
.mx_RoomTile_invited
{
font-weight: bold;
color: #000;
}
.mx_RoomTile_selected {
background-color: #f3f8fa;
color: #80cef4;
font-weight: bold;
}
.mx_RoomTile:hover {
}

View File

@@ -0,0 +1,33 @@
/*
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_RoomTooltip {
display: none;
position: fixed;
border: 1px solid #a9dbf4;
border-radius: 8px;
background-color: #fff;
z-index: 1000;
margin-top: 6px;
left: 64px;
padding: 6px;
}
.mx_RoomTooltip_chevron {
position: absolute;
left: -9px;
top: 8px;
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_SenderProfile {
display: table-cell;
padding: 0px 1em 0em 1em;
.mx_SenderProfile_zalgo {
font-family: Helvetica, Arial, Sans-Serif;
display: table-row ! important;
}

View File

@@ -14,22 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_MessageTile {
display: table-row;
.mx_ServerConfig {
margin-top: 7px;
}
.mx_MessageTile_content {
display: table-cell;
.mx_ServerConfig .mx_Login_field {
margin-top: 4px;
margin-bottom: 5px;
}
.mx_MessageTile_sending {
color: #ddd;
}
.mx_MessageTile_notSent {
color: #f11;
}
.mx_MessageTile_highlight {
color: #00f;
}
.mx_ServerConfig_help:link {
opacity: 0.8;
font-size: 14px;
font-weight: 300;
color: #4a4a4a;
}

View File

@@ -12,9 +12,4 @@ 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';
module.exports = {
};
*/

View File

@@ -0,0 +1,68 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_IncomingCallBox {
text-align: center;
border: 1px solid #a9dbf4;
border-radius: 8px;
background-color: #fff;
position: absolute;
z-index: 1000;
left: 235px;
top: 155px;
padding: 6px;
}
.mx_IncomingCallBox_chevron {
padding: 12px;
position: absolute;
left: -21px;
top: 0px;
}
.mx_IncomingCallBox_title {
padding: 6px;
font-weight: bold;
}
.mx_IncomingCallBox_buttons {
display: table-row;
}
.mx_IncomingCallBox_buttons_cell {
vertical-align: middle;
display: table-cell;
padding: 6px;
width: 50%;
}
.mx_IncomingCallBox_buttons_decline,
.mx_IncomingCallBox_buttons_accept {
vertical-align: middle;
width: 80px;
height: 36px;
line-height: 36px;
border-radius: 36px;
color: #fff;
}
.mx_IncomingCallBox_buttons_decline {
background-color: #f48080;
}
.mx_IncomingCallBox_buttons_accept {
background-color: #80f480;
}

View File

@@ -14,18 +14,26 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
function tsOfNewestEvent(room) {
return room.timeline[room.timeline.length - 1].getTs();
.mx_VideoView {
width: 100%;
position: relative;
z-index: 30;
}
function mostRecentActivityFirst(roomList) {
return roomList.sort(function(a,b) {
return tsOfNewestEvent(b) - tsOfNewestEvent(a);
});
.mx_VideoView video {
width: 100%;
}
module.exports = {
mostRecentActivityFirst: mostRecentActivityFirst
};
.mx_VideoView_remoteVideoFeed {
width: 100%;
background-color: #000;
z-index: 50;
}
.mx_VideoView_localVideoFeed {
width: 20%;
position: absolute;
left: 16px;
bottom: 28px;
z-index: 100;
}

View File

@@ -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_CreateRoom {
width: 720px;
margin-left: auto;
margin-right: auto;
color: #4a4a4a;
}
.mx_CreateRoom input,
.mx_CreateRoom textarea {
border-radius: 3px;
border: 1px solid #c7c7c7;
font-weight: 300;
font-size: 14px;
padding: 9px;
margin-top: 6px;
}
.mx_CreateRoom_description {
width: 330px;
}

View File

@@ -0,0 +1,69 @@
/*
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;
}
.mx_LeftPanel_hideButton {
position: absolute;
top: 10px;
right: 0px;
padding: 8px;
cursor: pointer;
}
.mx_LeftPanel .mx_RoomList {
-webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1;
-ms-flex-order: 1;
-webkit-order: 1;
order: 1;
overflow-y: auto;
-webkit-flex: 1 1 0;
flex: 1 1 0;
}
.mx_LeftPanel .mx_BottomLeftMenu {
-webkit-box-ordinal-group: 3;
-moz-box-ordinal-group: 3;
-ms-flex-order: 3;
-webkit-order: 3;
order: 3;
-webkit-flex: 0 0 170px;
flex: 0 0 170px;
border-top: 1px solid #f3f8fa;
}
.mx_LeftPanel .mx_BottomLeftMenu .mx_RoomTile {
color: #378bb4;
}
.mx_LeftPanel .mx_BottomLeftMenu .mx_BottomLeftMenu_options {
margin-top: 12px;
width: 100%;
}

View File

@@ -0,0 +1,60 @@
/*
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 {
height: 100%;
margin-bottom: 100px;
padding: 8px;
-webkit-flex: 1;
flex: 1;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
flex-direction: column;
-webkit-flex-direction: column;
}
.mx_MemberList_chevron {
position: absolute;
right: 35px;
margin-top: -15px;
}
.mx_MemberList_border {
border: 1px solid #a9dbf4;
overflow-y: auto;
border-radius: 8px;
background-color: #fff;
order: 1;
-webkit-flex: 1 1 0;
flex: 1 1 0px;
}
.mx_MemberList_wrapper {
display: table;
table-layout: fixed;
width: 100%;
}
.mx_MemberList h2 {
margin: 14px;
}

View File

@@ -14,69 +14,54 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RoomView {
word-wrap: break-word;
.mx_RightPanel {
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;
width: 100%;
top: 32px;
bottom: 0px;
display: flex;
flex-direction: column;
-webkit-flex-direction: column;
}
.mx_RoomView_messagePanel {
.mx_RightPanel_header {
-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; */
-webkit-flex: 0 0 66px;
flex: 0 0 66px;
}
.mx_RoomView_messageListWrapper {
height: 100%;
overflow-y: scroll;
/** Fixme - factor this out with the main header **/
.mx_RightPanel_headerButtonGroup {
margin-top: 18px;
height: 48px;
float: right;
background-color: #fff;
border-radius: 48px;
border: 1px solid #a9dbf4;
margin-right: 22px;
}
.mx_RoomView_MessageList {
display: table;
.mx_RightPanel_headerButton {
cursor: pointer;
height: 48px;
display: table-cell;
vertical-align: middle;
padding-left: 8px;
padding-right: 8px;
}
.mx_RoomView_invitePrompt {
}
.mx_RoomView .mx_MemberList {
.mx_RightPanel .mx_MemberList {
-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%;
}
.mx_RoomView .mx_MemberList ul {
margin: 0px;
padding: 0px;
}
.mx_RoomView .mx_MessageComposer {
width: 100%;
bottom: 0px;
}

View File

@@ -0,0 +1,99 @@
/*
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_RoomDirectory {
width: 720px;
margin-left: auto;
margin-right: auto;
margin-bottom: 12px;
color: #4a4a4a;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
flex-direction: column;
-webkit-flex-direction: column;
}
.mx_RoomDirectory_list {
-webkit-flex: 1;
flex: 1;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
flex-direction: column;
-webkit-flex-direction: column;
}
.mx_RoomDirectory_input {
margin: auto;
border-radius: 3px;
border: 1px solid #c7c7c7;
font-weight: 300;
font-size: 14px;
padding: 9px;
margin-top: 12px;
margin-bottom: 12px;
}
.mx_RoomDirectory_tableWrapper {
overflow-y: auto;
-webkit-flex: 1 1 0;
flex: 1 1 0;
}
.mx_RoomDirectory_table {
width: 100%;
text-align: left;
table-layout: fixed;
}
.mx_RoomDirectory_table th {
font-weight: 400;
font-size: 12px;
}
.mx_RoomDirectory_table tbody {
cursor: pointer;
}
.mx_RoomDirectory_table td {
font-weight: 300;
font-size: 16px;
overflow-x: hidden;
text-overflow: ellipsis;
}
.mx_RoomDirectory_table .mx_RoomDirectory_name {
font-weight: 400;
}
.mx_RoomDirectory_table .mx_RoomDirectory_topic {
font-weight: 400;
font-size: 12px;
}
.mx_RoomDirectory_table td,
.mx_RoomDirectory_table th, {
padding: 6px;
}

View File

@@ -14,7 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_MessageComposer textarea {
width: 100%;
margin: auto;
.mx_RoomList {
}
.mx_RoomList_recents {
margin-top: -12px;
display: table;
table-layout: fixed;
width: 100%;
}
.mx_RoomList h2 {
padding-left: 16px;
padding-right: 16px;
padding-bottom: 10px;
}

View File

@@ -0,0 +1,255 @@
/*
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_RoomView {
word-wrap: break-word;
position: relative;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
width: 100%;
flex-direction: column;
-webkit-flex-direction: column;
}
.mx_RoomView .mx_RoomHeader {
-webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1;
-ms-flex-order: 1;
-webkit-order: 1;
order: 1;
-webkit-flex: 0 0 88px;
flex: 0 0 88px;
}
.mx_RoomView_fileDropTarget {
min-width: 0px;
max-width: 720px;
width: 100%;
font-size: 20px;
text-align: center;
pointer-events: none;
padding-left: 12px;
padding-right: 12px;
margin-left: -12px;
-webkit-border-top-left-radius: 10px;
-webkit-border-top-right-radius: 10px;
-moz-border-radius-topleft: 10px;
-moz-border-radius-topright: 10px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
background-color: rgba(255, 255, 255, 0.9);
border: 2px dashed #80cef4;
border-bottom: none;
position: absolute;
top: 88px;
bottom: 0px;
z-index: 3000;
}
.mx_RoomView_fileDropTargetLabel {
top: 50%;
width: 100%;
margin-top: -50px;
position: absolute;
}
.mx_RoomView_auxPanel {
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
-ms-flex-order: 2;
-webkit-order: 2;
order: 2;
min-width: 0px;
max-width: 720px;
width: 100%;
margin: auto;
overflow: auto;
border-bottom: 1px solid #a8dbf3;
-webkit-flex: 0 0 auto;
flex: 0 0 auto;
}
.mx_RoomView_messagePanel {
-webkit-box-ordinal-group: 3;
-moz-box-ordinal-group: 3;
-ms-flex-order: 3;
-webkit-order: 3;
order: 3;
-webkit-flex: 1 1 0;
flex: 1 1 0;
width: 100%;
overflow-y: auto;
}
.mx_RoomView_messageListWrapper {
max-width: 720px;
margin: auto;
}
.mx_RoomView_MessageList {
width: 100%;
list-style-type: none;
padding: 0px;
}
.mx_RoomView_MessageList li {
clear: both;
}
.mx_RoomView_MessageList h2 {
clear: both;
margin-top: 32px;
margin-bottom: 8px;
padding-bottom: 6px;
border-bottom: 1px solid #a8dbf3;
}
.mx_RoomView_invitePrompt {
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
-ms-flex-order: 2;
-webkit-order: 2;
order: 2;
min-width: 0px;
max-width: 720px;
width: 100%;
margin: auto;
margin-top: 12px;
margin-bottom: 12px;
}
.mx_RoomView_statusArea {
-webkit-box-ordinal-group: 4;
-moz-box-ordinal-group: 4;
-ms-flex-order: 4;
-webkit-order: 4;
order: 4;
width: 100%;
-webkit-flex: 0 0 58px;
flex: 0 0 58px;
}
.mx_RoomView_statusAreaBox {
max-width: 720px;
margin: auto;
border-top: 1px solid #a8dbf3;
}
.mx_RoomView_unreadMessagesBar {
margin-top: 13px;
color: #fff;
font-weight: bold;
background-color: #ff0064;
border-radius: 30px;
height: 30px;
line-height: 30px;
cursor: pointer;
}
.mx_RoomView_unreadMessagesBar img {
padding-left: 22px;
padding-right: 22px;
}
.mx_RoomView_typingBar {
margin-top: 17px;
margin-left: 56px;
color: #818794;
}
.mx_RoomView_typingBar img {
padding-left: 12px;
padding-right: 12px;
margin-left: -64px;
margin-top: -7px;
float: left;
}
.mx_RoomView .mx_MessageComposer {
-webkit-box-ordinal-group: 5;
-moz-box-ordinal-group: 5;
-ms-flex-order: 5;
-webkit-order: 5;
order: 5;
width: 100%;
-webkit-flex: 0 0 63px;
flex: 0 0 63px;
margin-right: 2px;
}
.mx_RoomView_uploadProgressOuter {
width: 100%;
background-color: rgba(169, 219, 244, 0.5);
height: 4px;
}
.mx_RoomView_uploadProgressInner {
background-color: #80cef4;
height: 4px;
}
.mx_RoomView_uploadFilename {
margin-top: 15px;
margin-left: 56px;
}
.mx_RoomView_uploadIcon {
float: left;
margin-top: 6px;
margin-left: 5px;
}
.mx_RoomView_uploadCancel {
float: right;
margin-top: 6px;
margin-right: 10px;
}
.mx_RoomView_uploadBytes {
float: right;
opacity: 0.5;
margin-top: 15px;
margin-right: 10px;
}
.mx_RoomView_ongoingConfCallNotification {
width: 100%;
text-align: center;
background-color: #ff0064;
color: #fff;
font-weight: bold;
padding: 6px;
}

View File

@@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RoomHeader {
height: 1em;
padding: 0px;
.mx_UserSettings {
width: 720px;
margin-left: auto;
margin-right: auto;
}

View File

@@ -0,0 +1,3 @@
.mx_ViewSource pre {
text-align: left;
}

Some files were not shown because too many files have changed in this diff Show More