Compare commits

..

903 Commits

Author SHA1 Message Date
Matthew Hodgson
dbce60a025 oops 2016-02-25 01:18:01 +01:00
Matthew Hodgson
95e173008c karma experiments 2016-02-25 01:17:30 +01:00
Matthew Hodgson
f2fc4a88ae gemini up roomdirectory 2016-02-22 09:35:11 +00:00
Matthew Hodgson
77b45e7231 oooooooops - remember opensans v13 2016-02-22 09:18:56 +00:00
Matthew Hodgson
484736bf57 oops, add sanitize-html 2016-02-21 00:05:44 +00:00
Matthew Hodgson
e91a108738 Merge pull request #972 from vector-im/matthew/room-directory
Skin RoomDirectory almost as per design
2016-02-20 23:59:02 +00:00
Matthew Hodgson
2ca5529faa support hyperlinked topics 2016-02-20 23:54:47 +00:00
Matthew Hodgson
a35ab6bcef tart up room directory 2016-02-20 13:36:48 +00:00
Matthew Hodgson
e33e9b5d4a upgrade OpenSans and add semibold 2016-02-20 13:36:33 +00:00
Matthew Hodgson
3910877f8f ensure local activity bumps rooms up the roomlist 2016-02-19 02:09:04 +00:00
Matthew Hodgson
f538a0d5de scale local video feed to fit on the page properly 2016-02-19 01:16:55 +00:00
Matthew Hodgson
4e5b971d3a accomodate 800px wide thumbs 2016-02-18 19:09:32 +00:00
Matthew Hodgson
ffb1584e10 horizontally scale images properly 2016-02-18 18:59:45 +00:00
Matthew Hodgson
dbf3439e35 fix statusbar layout some more 2016-02-18 18:13:23 +00:00
Matthew Hodgson
11ac6defed tint searchbar 2016-02-18 17:32:15 +00:00
Richard van der Hoff
718c1cbe6f Merge branch 'rav/update_status_bar' into develop 2016-02-17 21:16:22 +00:00
Matthew Hodgson
27222a54c7 somewhat cryptic hack to make empty RoomStatusBars not take up 41px rather than 36px of height 2016-02-17 18:54:46 +00:00
Matthew Hodgson
3263076ea6 Merge branch 'develop' into rav/update_status_bar 2016-02-17 18:37:40 +00:00
Matthew Hodgson
3c659dcf57 experimental fix for https://github.com/vector-im/vector-web/issues/947 and https://github.com/vector-im/vector-web/issues/946. may well introduce more problems 2016-02-17 12:43:42 +00:00
Matthew Hodgson
2cd3150c56 tart up mx_EventTile_selected 2016-02-15 20:22:45 +00:00
Matthew Hodgson
cdc1447804 fix search highlight css 2016-02-15 20:19:30 +00:00
Matthew Hodgson
11c9aff69a fix radiobutton css 2016-02-15 22:06:16 +02:00
Matthew Hodgson
58959d014a show vaguely accurate default avatar 2016-02-15 22:01:30 +02:00
Matthew Hodgson
8e008572e5 CSS for setting display name prompt 2016-02-15 19:37:19 +02:00
Matthew Hodgson
177fba360d shrink 3pid invite placeholder text 2016-02-15 11:13:24 +02:00
Matthew Hodgson
ad9935739c proper fix for https://github.com/vector-im/vector-web/issues/917 and resolve https://github.com/vector-im/vector-web/issues/928 2016-02-15 09:56:52 +02:00
Matthew Hodgson
a2193d61b0 show the leave button by default for now as it causes too much pain otherwise 2016-02-14 21:34:32 +02:00
Matthew Hodgson
0ca6efdfca fix the nightmarish https://github.com/vector-im/vector-web/issues/917 2016-02-14 21:28:01 +02:00
Matthew Hodgson
f3df0d07f8 filter room directory case insensitively 2016-02-14 13:32:15 +02:00
David Baker
95a3354b90 Merge pull request #914 from vector-im/dbkr/package_use_tar
Use tar for packaging because zip can't traverse directory symlinks
2016-02-11 15:09:49 +00:00
David Baker
82b498017d Bumb webpack micro version (although it would have installed the latest micro version anyway) to maybe get a webpack that doesn't throw stack depth errors. 2016-02-11 15:01:32 +00:00
David Baker
b929f80be8 Use tar for packaging because zip can't traverse directory symlinks, hence ditch windows support for packaging. 2016-02-11 14:59:22 +00:00
David Baker
05a30e7c68 Merge pull request #902 from vector-im/dbkr/add_package_script
Add 'package' script to build a webapp bundle
2016-02-11 14:18:06 +00:00
David Baker
3c75c43d37 Bail if build step fails 2016-02-11 13:59:40 +00:00
David Baker
369e357742 We expect the mkdir to fail when the dir exists, so use ; not && 2016-02-11 13:40:26 +00:00
David Baker
93f8fcbacc Add 'package' script to build a webapp bundle for straight unzipping on a production server. 2016-02-10 15:35:06 +00:00
Matthew Hodgson
155728b136 make babel actually do full ES6 emulation for Safari 8 2016-02-10 14:54:55 +00:00
David Baker
98551c3f9a Merge pull request #900 from vector-im/dbkr/parse_queries_in_hash
Always parse the hash of a URL as we do elsewhere
2016-02-10 13:51:36 +00:00
David Baker
1732805f31 Always parse the hash of a URL as we do elsewhere by looking for a query string part, otherwise we end up passing the query into showscreen which then spreads havok. 2016-02-10 13:45:24 +00:00
Richard van der Hoff
bab9de1899 CSS fixes to match matrix-org/matrix-react-sdk#30b4b91.
This mostly works, but there is some weirdness with the status bar being too
high by default, and getting smaller when it has content in it.
2016-02-09 14:44:59 +00:00
Kegan Dougal
27791c06ee Cache-bust on /version request 2016-02-05 15:53:33 +00:00
David Baker
01bfb67b5b Merge branch 'dbkr/rate_limit_funcs' into develop 2016-02-05 10:58:18 +00:00
David Baker
485343864c semicolon 2016-02-05 10:57:49 +00:00
David Baker
842584177f Merge pull request #864 from vector-im/dbkr/rate_limit_funcs
Rate limit UI updates to avoid browser death
2016-02-05 10:16:03 +00:00
David Baker
ab9dfd185c Add note to not use npm start in production 2016-02-04 18:43:23 +00:00
David Baker
f035b8c50e Rate limit UI updates to avoid browser death 2016-02-04 18:09:24 +00:00
David Baker
15fec7f27c Merge pull request #862 from vector-im/dbkr/style_dialog_submit_button
Style submit input controls in dialogs the way we style buttons.
2016-02-04 15:07:44 +00:00
David Baker
c0c7ae1596 Style submit input controls in dialogs the way we style buttons. 2016-02-04 11:50:29 +00:00
Kegsay
6c5a00162c Merge pull request #856 from vector-im/kegan/version-stamp
Add a version update checker and NewVersionBar to show on the UI.
2016-02-03 17:09:24 +00:00
Kegan Dougal
b307a6d64e Invoke onVersion when we know the current version even if there is no new version (for settings) 2016-02-03 16:50:05 +00:00
Kegan Dougal
4628cf82a7 Split out response text to its own var to prevent trim() messing up comparisons 2016-02-03 16:23:17 +00:00
Kegan Dougal
5eed734325 Add a version update checker and NewVersionBar to show on the UI. 2016-02-03 16:16:14 +00:00
David Baker
f0a1f6d926 Merge pull request #846 from vector-im/dbkr/no_auto_join
Don't trigger room join from room directory: always peek / show join prompt bar
2016-02-03 15:52:05 +00:00
Kegan Dougal
deb1aa468f Listen on 0.0.0.0 and not localhost 2016-02-03 13:20:07 +00:00
Kegan Dougal
c76b1e7479 Actually listen on the right port 2016-02-03 13:11:51 +00:00
Kegan Dougal
4129c9bc24 Allow --symlink 2016-02-03 12:00:17 +00:00
Kegan Dougal
e22d36fc08 Add deploy directory with redeploy script 2016-02-03 11:26:24 +00:00
Kegan Dougal
043f6991a4 Dump vector/react/jssdk SHAs in filename 2016-02-02 17:03:48 +00:00
Kegan Dougal
2b0f4d5db1 Be more specific about the git dir 2016-02-02 16:29:25 +00:00
Kegan Dougal
1c267c69ac Include react SDK SHA in filename 2016-02-02 16:20:02 +00:00
Kegan Dougal
2a7b24e969 Update jenkins.sh to include the git commit 2016-02-02 16:09:33 +00:00
David Baker
d132c75263 Remove the autoPeek stuff and always either peek or show the join prompt bar 2016-02-02 15:51:23 +00:00
Kegan Dougal
b363eafbc8 Make jenkins.sh executable 2016-02-02 15:45:30 +00:00
Kegan Dougal
2986b241c4 Add jenkins.sh for builds 2016-02-02 15:44:41 +00:00
David Baker
d1dc082489 Remove empty if block 2016-02-01 18:02:52 +00:00
Richard van der Hoff
f94272c539 Add some crude CSS for highlighting the selected event
(To be useful, this needs functionality which hasn't yet landed in react-sdk).
2016-01-30 00:43:47 +00:00
David Baker
3b18b9b54b Fix connection lost bar CSS 2016-01-29 10:07:22 +00:00
David Baker
3585437af9 Merge pull request #800 from vector-im/dbkr/guest_warning_bar
CSS that changes the connection lost bar into a more general 'warning bar'
2016-01-28 13:44:09 +00:00
David Baker
6a36b022e4 New style guest warning bar 2016-01-28 13:00:44 +00:00
David Baker
35600f11ad CSS that changes the connection lost bar into a more general 'warning bar' so we can use it for a guest access warning 2016-01-28 09:19:28 +00:00
Matthew Hodgson
75886c4143 make badges scale with size of RoomTile 2016-01-24 14:50:24 -05:00
Matthew Hodgson
cd853ab5b4 try for a simpler invite placeholder look & feel 2016-01-24 19:02:49 +00:00
Matthew Hodgson
292af1e59c improve settings layout and fix FF bugs 2016-01-24 18:14:52 +00:00
Matthew Hodgson
d3bc0feb83 fix ugly wrapping bug 2016-01-24 17:54:01 +00:00
Matthew Hodgson
19bfd829d0 add scrollToBottomBar and fix spacing for status bars in general 2016-01-24 01:52:21 +00:00
Matthew Hodgson
759b318bb5 fix safari 2016-01-23 01:24:04 +00:00
Matthew Hodgson
dd19d2aaee red bar for highlights even if there's a unreadNotify too 2016-01-22 18:04:54 +00:00
Matthew Hodgson
e0ecde6760 put a black badge on unread notifications, and a red one for unread highlights 2016-01-22 17:23:04 +00:00
Matthew Hodgson
5e21059144 Merge pull request #729 from vector-im/matthew/truncateroomlist
truncate room list
2016-01-22 16:09:28 +00:00
Matthew Hodgson
0a32874b39 oops, reset truncate state on hide, not collapse 2016-01-22 16:09:06 +00:00
Kegan Dougal
302c63058b Invoke onShowMoreRooms to allow parents to kick their scrollbars.. 2016-01-22 15:46:58 +00:00
Matthew Hodgson
0ee1892a0b truncate room list 2016-01-22 15:31:42 +00:00
David Baker
12afbcbc45 Merge pull request #727 from vector-im/dbkr/rule_kinds
Add vector rules with the appropriate kind
2016-01-22 14:15:49 +00:00
David Baker
e11ae99a9f Add vector rules with the appropriate kind, otherwise the room_message rule takes precedence over content / display name rules etc and prevents bings. 2016-01-22 14:12:29 +00:00
Kegan Dougal
0752c3a6d5 Add start:prod - same as 'npm run start' but with NODE_ENV=production 2016-01-22 13:17:09 +00:00
manuroe
87f3603047 Merge pull request #721 from vector-im/push-rules-dont-notify
Push settings: Use a dont_notify rule when 1:1 or group chat rooms are set to OFF
2016-01-22 11:37:58 +01:00
manuroe
ce45f0b1e6 Push settings: Use a dont_notify rule when 1:1 or group chat rooms are set to OFF 2016-01-22 09:30:31 +01:00
Matthew Hodgson
a76167d175 correct layout for truncated lists 2016-01-21 17:38:46 +00:00
manuroe
3a23189435 Merge pull request #716 from vector-im/push-rules-add-bot-rule
Added notif settings for "Messages sent by bot" (#692)
2016-01-21 16:39:19 +01:00
manuroe
f3064a2994 Put back removing of "When people join or leave a room" settings push rule 2016-01-21 16:37:17 +01:00
manuroe
029cf754ee Added notif settings for "Messages sent by bot" (https://github.com/vector-im/vector-web/issues/692)
In order to do that, the rules definitions have been update to support "dont_notify" hs default push rules
2016-01-21 16:16:44 +01:00
David Baker
1a248c8e5c Merge pull request #710 from vector-im/unread_sync
Use read receipts to calculate unread room status
2016-01-21 13:29:49 +00:00
David Baker
568f9bb19d Merge pull request #713 from vector-im/dbkr/remove_member_event_rule
Remove member event rule as per SYN-607
2016-01-21 12:30:03 +00:00
David Baker
b913e72735 Remove member event rule as per SYN-607 2016-01-21 12:01:28 +00:00
David Baker
4d4c6e06ec Merge remote-tracking branch 'origin/develop' into unread_sync 2016-01-21 10:39:35 +00:00
David Baker
2d917910da Merge pull request #556 from vector-im/notif_sync
Use unread count for room highlight state
2016-01-21 10:31:46 +00:00
David Baker
0a70fe2bd1 Argh, revert accidental config commit 2016-01-21 10:30:52 +00:00
David Baker
a08d00c672 Apply patch to the right branch: update for new count format 2016-01-21 10:20:45 +00:00
Matthew Hodgson
bd75234a2f make CSS work on FF 2016-01-21 00:39:26 +00:00
Matthew Hodgson
6573ba8c20 fix up Start Chat behaviour as per Amandine's feedback 2016-01-21 00:16:26 +00:00
Matthew Hodgson
f4a2b6ab7e Merge pull request #697 from vector-im/matthew/roompreview
Lots of CSS bugfixes and polishing
2016-01-20 22:32:08 +00:00
Matthew Hodgson
6117e09a3f implement the correct design for memberlist 2016-01-20 22:04:32 +00:00
Matthew Hodgson
1fd60f1e44 revert read marker css 2016-01-20 17:23:33 +00:00
David Baker
d979511696 Re-remove extra icons as they break favico 2016-01-20 17:20:34 +00:00
David Baker
ac2e69ba28 Use new unread count methods 2016-01-20 17:20:19 +00:00
Matthew Hodgson
48052415b7 usersettings button layout 2016-01-20 17:09:53 +00:00
Matthew Hodgson
e87e22a438 rhsbutton 2016-01-20 17:06:13 +00:00
Matthew Hodgson
5b2f921190 Fix bold avatar letters 2016-01-20 17:01:19 +00:00
Matthew Hodgson
b830f43371 remove RoomAvatar; stale border-radius; fix aliases table 2016-01-20 16:59:53 +00:00
Matthew Hodgson
6332e3908e roomsettings css fixes 2016-01-20 16:39:14 +00:00
Matthew Hodgson
82742f9f13 oops, fix tinted read up to marker correctly 2016-01-20 16:06:35 +00:00
manuroe
39eb0f9c8f Merge pull request #687 from vector-im/push-rules-call-settings-fix
Fixed call push notifications settings that always stayed OFF
2016-01-20 17:06:01 +01:00
manuroe
888fde0f53 Fixed call push notifications settings that always stayed OFF 2016-01-20 17:01:09 +01:00
David Baker
eb62456007 Update for new unread count format 2016-01-20 15:58:21 +00:00
Matthew Hodgson
60d2d45255 readd in the .mx_EntityTile_power class. don't understand why it was killed :'( 2016-01-20 15:39:42 +00:00
Matthew Hodgson
6ecdb02e81 sanitize avatar border radii 2016-01-20 15:26:48 +00:00
Matthew Hodgson
4d3918109a skin new invite UI CSS 2016-01-20 14:58:27 +00:00
Matthew Hodgson
9a9db53e0a fix tinting of read marker again 2016-01-20 14:58:17 +00:00
Kegsay
ad6a19a0df Merge pull request #668 from vector-im/matthew/roompreview
Support non-guest peeking
2016-01-19 16:09:36 +00:00
Matthew Hodgson
3e8c6a42d3 roomsettings layout tweaks 2016-01-18 19:58:02 +00:00
Matthew Hodgson
3b8e5073b5 improve layout 2016-01-18 19:57:32 +00:00
Matthew Hodgson
a775086e81 wording from amandine 2016-01-18 19:57:17 +00:00
Matthew Hodgson
d5c291ae62 Merge branch 'kegan/invite-search' into matthew/roompreview 2016-01-18 18:00:58 +00:00
Matthew Hodgson
d6f6f32c74 WIP to support non-guest peeking, and slightly improve roomdirectory look & feel for now 2016-01-18 17:37:13 +00:00
Kegan Dougal
317e1fb9cd Merge branch 'develop' into kegan/invite-search 2016-01-18 17:33:26 +00:00
manuroe
37e8a35967 Merge pull request #641 from vector-im/push-rules-settings
Push rules settings
2016-01-18 18:25:31 +01:00
manuroe
6182c983ab PushRules settings: Applied review remarks (2/2) 2016-01-18 18:24:53 +01:00
Kegan Dougal
ac4b221690 More CSS fun for border bottom 2016-01-18 17:22:02 +00:00
manuroe
fdf5b0a4fc Merge branch 'develop' into push-rules-settings
# Conflicts:
#	src/skins/vector/css/matrix-react-sdk/structures/UserSettings.css
2016-01-18 18:14:20 +01:00
manuroe
7c0fffa79b PushRules settings: Applied easy review remarks 2016-01-18 18:07:33 +01:00
Kegan Dougal
fef02f2fd1 s/MemberTile/EntityTile/ 2016-01-18 16:43:00 +00:00
manuroe
bdcf683942 PushRules settings: Create a dedicated rule for "Messages sent to group".
The default fallback rule cannot be used because it matches with too much events.
2016-01-18 16:41:48 +01:00
manuroe
ae14210763 PushRules settings: Put keywords in the right position 2016-01-18 16:31:18 +01:00
manuroe
830160f074 PushRules settings: Enabled all radio buttons of the table.
Each rule is described in the code so that if the server does not have it in its default rules or if the user wants to use actions different from the hs one, the code will create a new rule that will override the hs one.
2016-01-18 16:24:06 +01:00
Matthew Hodgson
0ef03c5ca4 Merge pull request #653 from vector-im/matthew/roomsettings2
Finish off RoomSettings (part 2)
2016-01-18 13:39:55 +00:00
Matthew Hodgson
5a1b0a1dab Merge pull request #657 from vector-im/matthew/memberlist
Fix up MemberList and MemberInfo cosmetics a bit
2016-01-18 13:39:42 +00:00
Kegan Dougal
77621fe035 Add missing CSS from #638 2016-01-18 12:06:46 +00:00
Kegsay
7e40d81a44 Merge pull request #638 from vector-im/kegan/base-avatar
CSS for BaseAvatar
2016-01-18 10:17:57 +00:00
Matthew Hodgson
8792be4db2 moar space 2016-01-18 01:25:57 +00:00
Matthew Hodgson
1fef91b82c MemberInfo lipstick 2016-01-18 01:18:11 +00:00
Matthew Hodgson
b2a1c89e83 bring back power badges 2016-01-18 00:16:04 +00:00
Matthew Hodgson
40d2018c17 fix checkbox css 2016-01-17 12:26:54 +00:00
Matthew Hodgson
a61afa0f31 fix css thinko 2016-01-17 02:46:22 +00:00
Matthew Hodgson
4e7c58e242 fix broken icon 2016-01-17 02:46:15 +00:00
Matthew Hodgson
8771369937 more layout 2016-01-15 20:29:44 +00:00
Matthew Hodgson
394fb2373b more layout tweaks for RoomSettings 2016-01-15 16:50:12 +00:00
Matthew Hodgson
eb8064f961 fix cursors for changeavatar 2016-01-15 16:32:39 +00:00
Matthew Hodgson
531aa153bb no more textarea in roomsettings 2016-01-15 16:32:23 +00:00
manuroe
d7ffe70d44 PushRules settings: Applied Amandine's review comments 2016-01-15 17:28:57 +01:00
Kegan Dougal
17489ae350 s/MemberAvatar/BaseAvatar/ and rename classes 2016-01-15 16:12:28 +00:00
Matthew Hodgson
762dd69f0a more bottom margin on editable roomheader 2016-01-15 15:48:29 +00:00
manuroe
cb8b052dc0 PushRules settings: Show unmanaged rules into an "advanced section" 2016-01-15 16:45:27 +01:00
Matthew Hodgson
1fcb4ba94f droptarget and usersettings and roomsettings layout tweaks 2016-01-15 15:26:00 +00:00
David Baker
ea6ed81517 Merge pull request #630 from vector-im/read_marker_position
Shift read marker down by 5px
2016-01-15 13:57:25 +00:00
manuroe
2dd2acd4e0 PushRules settings: BF adding a keyword when the keywords rule is OFF 2016-01-15 14:28:50 +01:00
Matthew Hodgson
41ae851df4 fix up user settings CSS somewhat 2016-01-15 12:34:01 +00:00
manuroe
c3469b5b51 PushRules settings: coding: separate UI and data management 2016-01-15 11:33:54 +01:00
manuroe
7412fc7f97 PushRules settings: changed wordings 2016-01-15 10:51:42 +01:00
Matthew Hodgson
d1f26e3911 camera icon 2016-01-14 17:26:16 +00:00
Matthew Hodgson
c1aac1aaca roomsetting icons 2016-01-14 17:25:21 +00:00
Matthew Hodgson
f2fa9fe398 Merge branch 'develop' into matthew/roomsettings2 2016-01-14 16:49:48 +00:00
David Baker
a65a15e9bb Shift read marker down by 5px 2016-01-14 16:45:13 +00:00
Matthew Hodgson
9ada5f7ddd CSS for tab complete slashcommands 2016-01-14 16:29:03 +00:00
Matthew Hodgson
17e540d372 fix line wrapping of code blocks in multiline msgs 2016-01-14 11:57:07 +00:00
Kegsay
db2d7fdbff Merge pull request #622 from vector-im/kegan/3pid-invite-memberlist
CSS for email invite memberlist fix
2016-01-14 10:45:50 +00:00
Kegan Dougal
927ac5fe64 2016 only 2016-01-14 10:45:38 +00:00
manuroe
378f4bb85c PushRules settings: Display keywords in alphabetical order 2016-01-14 11:15:59 +01:00
manuroe
0577edb055 PushRules settings: Added master push rule 2016-01-14 11:03:51 +01:00
David Baker
513c7e3b73 Uncommit unintentional config change 2016-01-13 17:59:13 +00:00
Matthew Hodgson
56718650b9 fix comedy double-margin caused by killing off MessageTiles 2016-01-13 17:39:57 +00:00
Matthew Hodgson
e3eef45684 fix comedy double-margin caused by killing off MessageTiles 2016-01-13 17:39:49 +00:00
Matthew Hodgson
68f846e129 Merge branch 'develop' into matthew/roomsettings2 2016-01-13 17:33:32 +00:00
Matthew Hodgson
ad434cb82e GA bugfix 2016-01-13 17:33:06 +00:00
Matthew Hodgson
f2171c11f0 uncommitted WIP roomsetting CSS 2016-01-13 17:33:03 +00:00
manuroe
629883731e PushRules settings: BF when adding a new keyword with the keywords rule in Off 2016-01-13 17:56:59 +01:00
manuroe
0475bcd9de PushRules settings: BF when changing state of the keywords rule with such a sequence: on -> off -> loud. 2016-01-13 17:10:26 +01:00
Kegan Dougal
1d5e661bd0 Split out css for new PresenceLabel 2016-01-13 15:56:44 +00:00
manuroe
ac87830e4e PushRules settings: Applied new wordings: On, Loud, Off 2016-01-13 16:48:22 +01:00
manuroe
7fc5ab3c6e PushRules settings: Use the new TextInputDialog to display keywords list. We earn the focus at the end of the keywords list and the management of enter and esc keys 2016-01-13 16:36:57 +01:00
manuroe
c4cb37606b PushRules settings: Added sanity checks on new keywords 2016-01-13 15:47:00 +01:00
manuroe
e5b7a47fee PushRules settings: if a newly typed keyword was part of a push rule not managed by the Vector UI, delete the rule and create it compliant with Vector parameters 2016-01-13 12:00:04 +01:00
manuroe
1c03c208e1 PushRules settings: update keywords list hs side 2016-01-13 11:46:13 +01:00
Kegsay
7232659195 Merge pull request #612 from vector-im/kegan/guest-peek-then-join
Add css for room preview bar.
2016-01-13 10:37:13 +00:00
manuroe
10d3076d6b PushRules settings: Display keywords modal dialog 2016-01-13 09:11:56 +01:00
David Baker
cae3ab410f Merge pull request #603 from vector-im/read_marker_animate
New CSS for read markers
2016-01-12 17:58:36 +00:00
Kegan Dougal
2bada93fdc CSS for forgot password link 2016-01-12 16:39:29 +00:00
manuroe
9fb8c9f67a PushRules settings: Use a workaround for SYN-590 (Push rule update fails) 2016-01-12 17:33:57 +01:00
manuroe
b9080c770d PushRules settings: Fixed triage of matrix content rules into the unique Vector rule 2016-01-12 16:46:27 +01:00
David Baker
977b223929 Hopefully working CSS that doesn't cause the messages to jump about when a read marker disappears. 2016-01-12 14:20:05 +00:00
manuroe
7f95362dd2 PushRules settings: Translate matrix per-word rules into the global Vector rule for a list of keywords 2016-01-12 15:12:58 +01:00
Kegan Dougal
f706f75a6e Add css for room preview bar. 2016-01-12 14:11:00 +00:00
Matthew Hodgson
fc3f356dc0 GA 2016-01-12 01:23:39 +00:00
manuroe
6d510db2db PPushRules settings: Fixed React warnings 2016-01-11 17:32:37 +01:00
manuroe
ee13dd7b6c PushRules settings: Added a dedicated component to display them 2016-01-11 17:24:04 +01:00
Kegsay
f898986c73 Merge pull request #594 from vector-im/kegan/guest-access
Enable guest access
2016-01-11 15:21:57 +00:00
David Baker
6cd0aeb607 Revert 4px offset: it ends up in the middle of the line above 2016-01-11 10:56:08 +00:00
David Baker
1e57aa8c78 Make read up to line 2px and position relative so we can shift it up a little 2016-01-11 10:52:29 +00:00
Matthew Hodgson
93c4fc8785 switch EditableText to contentEditable; fix auxPanel layout bug in the general case (not just for video) 2016-01-10 13:04:15 +00:00
Matthew Hodgson
8a156dcac8 Merge pull request #605 from vector-im/matthew/roomsettings
fix leave.svg so that it can be tinted
2016-01-09 21:25:50 +00:00
Matthew Hodgson
d49f8721ce fix leave.svg so that it can be tinted 2016-01-09 00:56:10 +00:00
David Baker
c02d9890c5 New CSS for read markers 2016-01-09 00:09:11 +00:00
Matthew Hodgson
dfcc923c91 Merge pull request #599 from vector-im/matthew/roomsettings
CSS and imagery for fixed up RoomSettings
2016-01-08 11:26:34 +00:00
Matthew Hodgson
ccd518cc4c CSS and imagery for fixed up RoomSettings 2016-01-08 03:26:07 +00:00
Kegan Dougal
a369c862a0 Hit MatrixClient.peekInRoom on rooms we can only peek into. 2016-01-07 14:57:26 +00:00
Kegan Dougal
1a8a4728cd Enable guest access. Show r/w icons on room directory. 2016-01-07 14:43:12 +00:00
Matthew Hodgson
d2635373f0 Merge pull request #585 from vector-im/matthew/dynamic-svg
Make SVGs and CSS dynamically recolourable
2016-01-07 11:41:46 +00:00
David Baker
5b4457d33c Merge pull request #591 from vector-im/green_line
Add CSS for the green read-up-to marker.
2016-01-07 11:40:11 +00:00
David Baker
36e5ac3d7f Add CSS for the green read-up-to marker. 2016-01-07 11:22:41 +00:00
Matthew Hodgson
df111223fc copyrights for 2016 2016-01-07 04:17:56 +00:00
David Baker
c0f1ae0133 Use Unread to compute unread status of a room (which uses read receipts). 2016-01-06 18:29:27 +00:00
David Baker
c96ce482bc Remove the extra icons as they break the js favicon library, and should be unnecessary because the additional sizes are muxed into the ico file. 2016-01-06 17:36:30 +00:00
Matthew Hodgson
eacadbff40 remove stale onSvgLoad 2016-01-06 02:29:20 +00:00
Matthew Hodgson
cb29a04674 use factored out TintableSvg component for dynamic SVGs 2016-01-06 02:11:34 +00:00
Matthew Hodgson
f9a34d21c8 Merge branch 'develop' into matthew/dynamic-svg 2016-01-06 01:11:47 +00:00
Matthew Hodgson
bb313d1f3c vertical-align room messages to the bottom of the page 2016-01-05 18:49:47 +00:00
Matthew Hodgson
a1bdfaa8a2 vertical-align room messages to the bottom of the page 2016-01-05 18:49:21 +00:00
Matthew Hodgson
1df4f2d556 fix hyperlink position for image downloads 2016-01-05 03:38:53 +00:00
Matthew Hodgson
b996022db2 fix up dynamically loaded svgs, and fix bottomleftmenu 2016-01-05 03:34:25 +00:00
Matthew Hodgson
bbf08d99cc tinterize more svg 2016-01-05 00:47:26 +00:00
Matthew Hodgson
17b8982c75 move title attributes to the div 2016-01-03 22:35:07 +00:00
Matthew Hodgson
3abdcbf806 switch SVGs from imgs to objects, fixing CSS to make onClicks work 2016-01-03 22:30:14 +00:00
Matthew Hodgson
a78a693903 Merge pull request #581 from vector-im/matthew/css-refactor
shuffle around all the CSS to de-atomify it and make it match react components
2016-01-03 00:14:52 +00:00
Matthew Hodgson
b9a0b82537 shuffle around all the CSS to de-atomify it and make it match the react components 2016-01-03 00:10:17 +00:00
Matthew Hodgson
10e481a8d5 noscript 2015-12-28 03:25:26 +00:00
Matthew Hodgson
fa4bd09f0c fix room header height 2015-12-28 02:27:47 +00:00
Matthew Hodgson
8dd90980d8 add cancel button for lightbox and pare down pointer-events stuff a bit 2015-12-28 02:15:23 +00:00
Matthew Hodgson
e9db7b1dcc doh 2015-12-28 01:41:51 +00:00
Matthew Hodgson
388eb1ff4c use Open Sans, and fix duplication 2015-12-28 01:38:14 +00:00
Matthew Hodgson
647c01fe2a where did this img symlink go? all iamges break without it... 2015-12-28 01:34:28 +00:00
Matthew Hodgson
0ab8466a3b make tabcomplete items clickable 2015-12-24 15:12:24 +00:00
Kegan Dougal
94609db3a6 Wrangle CSS to get avatar on UserSettings in the right place 2015-12-24 09:21:02 +00:00
Kegan Dougal
f9f85ec542 More user settings CSS 2015-12-23 16:53:19 +00:00
Kegan Dougal
d3938220cf Duplicate css for applying to mx_EditableText classes so it works with ChangeDisplayName 2015-12-23 14:13:24 +00:00
Kegsay
73d9ef54c3 Merge pull request #384 from vector-im/matthew/settings
WIP experiment of turning UserSettings into a controller-less component
2015-12-23 10:23:39 +00:00
David Baker
755ea0dfb8 Merge remote-tracking branch 'origin/develop' into notif_sync 2015-12-22 14:46:57 +00:00
Matthew Hodgson
f681ce5cdb add CSS for TabCompleteBar 2015-12-22 00:47:33 +00:00
Matthew Hodgson
ceadfef942 fix missing webkit prefixes for flexbox 2015-12-21 23:20:44 +00:00
Matthew Hodgson
f665848c5e speed up search anim 2015-12-21 23:20:10 +00:00
Matthew Hodgson
031b048c07 fix missing webkit prefixes for flexbox 2015-12-21 23:19:53 +00:00
Matthew Hodgson
d82c4c5ef3 fix safari flexbox bug 2015-12-21 23:16:44 +00:00
Matthew Hodgson
ae02d8d30a Merge branch 'develop' into matthew/settings 2015-12-21 13:10:34 +00:00
Matthew Hodgson
85db381153 Merge pull request #550 from vector-im/kegan/archived-rooms
Kegan/archived rooms
2015-12-21 12:39:48 +00:00
Matthew Hodgson
67aff6b9f2 adopt MacOS style chevrons 2015-12-21 12:37:51 +00:00
Matthew Hodgson
50aa988a34 fix layout 2015-12-21 12:37:50 +00:00
Matthew Hodgson
fdc94ccf98 ensure even hyperlinks are highlighted 2015-12-21 12:37:50 +00:00
David Baker
cb1fabc578 Highlight status is now the room's unread notif count 2015-12-18 17:53:31 +00:00
Kegsay
59f419b310 Merge pull request #541 from vector-im/kegan/archived-rooms
Add more props to RoomSubList
2015-12-18 17:36:16 +00:00
Kegan Dougal
dcea0dd601 Move min-height to RoomList; remove bottommost prop 2015-12-18 17:13:57 +00:00
Kegan Dougal
dc1e2010a6 Merge branch 'develop' into kegan/archived-rooms 2015-12-18 17:00:20 +00:00
Matthew Hodgson
d7b87743f3 Merge pull request #533 from vector-im/matthew/inbound-calls
position the inbound call box correctly
2015-12-18 15:59:05 +00:00
Kegan Dougal
7cc1573f33 Add startAsHidden and showSpinner props to RoomSubList
startAsHidden: Previously we never started in the hidden state and all was well.
But with archived rooms you DO want to start hidden as you haven't fetched the
room list yet. Without this, you need to click twice (close/open) before the
archived room list will load.

showSpinner: If true, will show a spinner iff there are 0 elements being displayed.
Used when fetching the archived room list in RoomList.
2015-12-18 15:17:18 +00:00
Kegan Dougal
f7c4cca675 Add TODO after spending 15 mins trying to figure out the difference between props.collapsed and state.hidden 2015-12-18 13:32:22 +00:00
Kegan Dougal
869c08a790 Add onHeaderClick and alwaysShowHeader props to RoomSubList for archived room clicking 2015-12-18 11:56:22 +00:00
Matthew Hodgson
a7b9e54594 Merge branch 'develop' into matthew/settings 2015-12-18 00:36:46 +00:00
Kegsay
5f3a1cb6e1 Merge pull request #537 from vector-im/kegan/3pid-inv
Pass through the starting query params from the URL
2015-12-17 16:43:13 +00:00
Kegan Dougal
63d0477223 Pass through the starting query params from the URL 2015-12-17 15:01:07 +00:00
Matthew Hodgson
1a90a2c426 position the inbound call box correctly, and fix various issues with when the video preview and callview are shown 2015-12-17 02:53:53 +00:00
Kegsay
856156ef5c Merge pull request #527 from vector-im/kegan/hide-fs-user
Pass a userId rather than a RoomMember to isConferenceUser
2015-12-16 13:56:50 +00:00
Kegan Dougal
c8ca1dd8d0 Pass a userId rather than a RoomMember to isConferenceUser
Because invites do not have RoomMembers because we don't have an m.room.member
event for them, just a user ID, and we want to detect conf users at invite
time.
2015-12-16 11:55:13 +00:00
Matthew Hodgson
d945050de6 fix typing notifs 2015-12-15 15:59:40 +00:00
Matthew Hodgson
d3ecce2d2e add fullscreen button 2015-12-15 00:01:32 +00:00
Matthew Hodgson
a495aecdd8 assets for VoIP and DnD file upload 2015-12-14 23:38:24 +00:00
Matthew Hodgson
c553258aff add dedicated leave button to header 2015-12-13 13:49:54 +00:00
Matthew Hodgson
9c8984b308 fix vertical alignment of voip buttons 2015-12-13 04:14:20 +00:00
Matthew Hodgson
c2061ed439 revert dd08f53756 - do this in JS instead 2015-12-13 04:08:35 +00:00
Matthew Hodgson
96cddc5ca8 fix layout for long room names & topics 2015-12-12 17:30:08 +00:00
Matthew Hodgson
dd08f53756 don't let auxpanel push out the height of the roomview 2015-12-12 17:15:45 +00:00
Matthew Hodgson
056017007a improve look and feel of upload cancel 2015-12-12 16:41:32 +00:00
Matthew Hodgson
7cfca3ff4d Merge pull request #499 from vector-im/rav/mute_icon
Add a 'muted' icon for voip calls
2015-12-11 15:32:08 +00:00
Richard van der Hoff
c36d1df417 Add a 'muted' icon for voip calls
... because even a crappy one is better than nothing
2015-12-11 15:00:25 +00:00
Matthew Hodgson
762281cd96 fix vertical spacing of roomheader 2015-12-11 03:39:13 +00:00
Matthew Hodgson
898cb399a3 show results 2015-12-11 02:58:47 +00:00
Matthew Hodgson
3fb0c9883b escape key to cancel search box 2015-12-11 02:32:30 +00:00
Matthew Hodgson
f2fb1836df only flash whilst searching 2015-12-11 02:25:51 +00:00
Matthew Hodgson
fea3fed460 animate the search button whilst searching 2015-12-11 02:24:58 +00:00
Matthew Hodgson
4c82d86092 nice green highlights 2015-12-11 01:35:05 +00:00
Matthew Hodgson
1c9d61d731 dedicated search button 2015-12-11 01:19:48 +00:00
Matthew Hodgson
7b702c4594 don't grey out invites randomly 2015-12-11 00:40:40 +00:00
Matthew Hodgson
d6bcf80431 make the settings button more discoverable by having the whole leftRow be a hover target 2015-12-10 19:48:05 +00:00
Matthew Hodgson
e26efd475c preload warning.svg - fixes bug https://github.com/vector-im/vector-web/issues/455 2015-12-09 13:52:04 +00:00
Matthew Hodgson
9d15bf2847 clean up broken renaming of /icons 2015-12-09 13:24:56 +00:00
Matthew Hodgson
8ecf70dda0 show images with unknown height - fixes issue 475 hopefully 2015-12-09 13:24:15 +00:00
Matthew Hodgson
4b8d7a612a make the mx_RoomView_statusAreaBox_line full width as per the ribot design 2015-12-08 19:45:30 +00:00
Richard van der Hoff
1d97a5f06b Merge pull request #470 from vector-im/rav/olm
HOWTO encryption
2015-12-08 16:03:54 +00:00
Richard van der Hoff
f8e5bbef0b Add a link to E2E bug in the README 2015-12-08 16:03:12 +00:00
Matthew Hodgson
b532fd046a actually use SVGs - oops 2015-12-08 10:28:00 +00:00
Matthew Hodgson
a8e24802ab rename icons to avoid namespace clash with /icons 2015-12-08 10:27:42 +00:00
Kegsay
862ab0c115 Merge pull request #477 from vector-im/kegan/resending
Make unsent messages behave better
2015-12-07 17:00:30 +00:00
Kegan Dougal
2f905e13e1 Invoke onFinished so the context menu doesn't hang around 2015-12-07 16:04:46 +00:00
Kegan Dougal
39778330b5 Also allow not_sent messages to be cancelled entirely. 2015-12-07 13:55:10 +00:00
Kegan Dougal
1af1297afc Allow queued events to be cancelled. Make not sent events appear differently to sending events. 2015-12-07 11:38:34 +00:00
Matthew Hodgson
da5c687320 svgize coloured icons 2015-12-06 22:06:21 +00:00
David Baker
25eeaaf1e5 Use UnreadStatus to determine whether an event affects a room;s unread status. Unify rooms going bold with their sort order and don't go bold for m.notify. 2015-12-04 16:24:17 +00:00
Kegan Dougal
ac8fcbb264 Force update the RightPanel when the member in MemberInfo is updated. 2015-12-04 16:16:41 +00:00
Richard van der Hoff
759e35003b Put some warnings on the crypto stuff 2015-12-04 15:39:39 +00:00
Richard van der Hoff
97dd4e2e6b Merge branch 'develop' into rav/olm
Conflicts:
	webpack.config.js
2015-12-03 18:28:50 +00:00
Richard van der Hoff
56b7b65920 Notes on building a crypto-enabled version 2015-12-03 18:25:20 +00:00
Richard van der Hoff
782174069c Include olm in the webpack if it's been installed
.. to make it easy to build a crypto-enabled vector
2015-12-03 18:24:34 +00:00
David Baker
db5d9e2f6e Merge pull request #465 from vector-im/file_uploads
Move upload bar CSS to new classes
2015-12-03 10:58:03 +00:00
David Baker
547f59b1bc Oops, don't re-add these. 2015-12-03 10:00:29 +00:00
David Baker
2d2386ace5 Move upload bar CSS to new classes, and move into new, temporary place (since there is no new-style structure yet). 2015-12-02 18:19:03 +00:00
Matthew Hodgson
c603c1e37f dezalgo typing notigs on chrome 2015-12-02 17:37:19 +00:00
Matthew Hodgson
de144cf4cd uh, actually include Open Sans webfont :-/ 2015-12-02 15:13:41 +00:00
David Baker
8df62e3b02 Merge pull request #454 from vector-im/require-css
Build CSS with webpack
2015-12-02 10:26:41 +00:00
David Baker
939733b736 Merge branch 'develop' into require-css 2015-12-02 10:26:26 +00:00
Kegsay
6db1151699 Merge pull request #453 from vector-im/kegan/vector-references
Add vector-specific branded components
2015-12-02 09:38:39 +00:00
Kegan Dougal
0210670e91 Merge branch 'develop' into kegan/vector-references
Conflicts:
	src/component-index.js
2015-12-02 09:37:28 +00:00
Kegan Dougal
d837d02ac9 Still add highlight.js as an import as we symlink directly to the node_module for github.css :/ - Fixes ENOENT 2015-12-02 09:26:12 +00:00
Matthew Hodgson
cba27a7488 erm, surely we need to actually run reskindex after all that? 2015-12-02 01:37:26 +00:00
Matthew Hodgson
349a88d640 stop clobbering our font colours 2015-12-01 21:44:22 +00:00
David Baker
95e71a531e Merge branch 'develop' into kegan/vector-references
Update having merged skindexing PR
2015-12-01 18:31:13 +00:00
David Baker
d2c6e2195e Merge pull request #447 from vector-im/skindex-nextgen
Update skindexing for new world order
2015-12-01 18:12:47 +00:00
David Baker
a63bf7cb35 Merge branch 'develop' into skindex-nextgen 2015-12-01 18:10:57 +00:00
David Baker
7ff5e42f3e Run the CSS through webpack so we can pull in CSS files from modules with require rather than symlinking into the node_module directory which is breaking people on different npm versions. 2015-12-01 18:05:43 +00:00
Matthew Hodgson
2c12b9128b highlight binged rooms more clearly 2015-12-01 16:57:49 +00:00
Kegan Dougal
e21d435d84 Remove debug logging 2015-12-01 16:57:40 +00:00
Kegan Dougal
a2b28b826c Add CustomServerDialog for vector 2015-12-01 16:48:51 +00:00
Kegan Dougal
8d31f72f83 Add VectorLoginHeader 2015-12-01 16:27:23 +00:00
Kegan Dougal
e304a1925d Add VectorLoginFooter with vector references 2015-12-01 16:12:38 +00:00
Kegsay
819b80d30f Merge pull request #450 from vector-im/kegan/vector-components
Move remaining Vector-only components to src/components
2015-12-01 15:58:55 +00:00
David Baker
c281fe785a Merge branch 'develop' into skindex-nextgen 2015-12-01 15:53:11 +00:00
Kegan Dougal
8083e7f118 Move vector-only components to src/components. 2015-12-01 15:45:38 +00:00
David Baker
5098c7d16f Merge branch 'develop' into skindex-nextgen 2015-12-01 15:44:45 +00:00
Kegan Dougal
e07c03a7bb Merge branch 'develop' into kegan/vector-components 2015-12-01 15:39:02 +00:00
Kegsay
e7f6e09def Merge pull request #448 from vector-im/kegan/controller-merging4
Phase 4 controller merging
2015-12-01 15:34:25 +00:00
Matthew Hodgson
075d2b508d fix highlights on markdown 2015-12-01 13:13:51 +00:00
Kegan Dougal
e55e2bdd0d Remove unused class 2015-12-01 11:22:19 +00:00
Kegan Dougal
2a025201b1 Move remaining vector molecules to be components in vector (for now) 2015-12-01 11:19:54 +00:00
Matthew Hodgson
f89dcacf07 fix bottomleftmenu layout a bit 2015-12-01 11:11:32 +00:00
Matthew Hodgson
99f47b8601 match design spacing correctly 2015-12-01 11:07:12 +00:00
Matthew Hodgson
1896ab67d1 fix room avatar offset 2015-12-01 11:05:11 +00:00
Matthew Hodgson
2bc3b665d2 Merge pull request #445 from vector-im/matthew/new-font
switch to Open Sans
2015-12-01 10:59:05 +00:00
Kegan Dougal
8f5f71ec80 Move MatrixChat to react-sdk. Move all login stuff to react SDK.
Removed Modulator stuff.
2015-11-30 18:10:09 +00:00
David Baker
021056cfd1 Move copyright header 2015-11-30 18:00:54 +00:00
David Baker
6a4038daeb Add 'replaces' tag to mark that the RoomDNDView is a RoomTile 2015-11-30 17:56:55 +00:00
David Baker
cadfbcbed3 Merge branch 'develop' into skindex-nextgen 2015-11-30 17:56:40 +00:00
David Baker
6f646260aa WIP of component indexing update 2015-11-30 17:31:32 +00:00
Matthew Hodgson
badfdb5e3e actually, seems FF is happy with this again now 2015-11-30 17:24:38 +00:00
Matthew Hodgson
2345624d31 switch to Open Sans, juggling font-size appropriately (as Open Sans is physically larger for the same point size as Myriad Pro, irritatingly), and fix some really weird baseline CSS bugs in read receipts that were introduced. Hopefully this doesn't re-introduce the intermittent baseline offset bug for the initials on Chrome & FF 2015-11-30 17:17:09 +00:00
Kegan Dougal
ddc4f30bb6 Remove RoomView and port it to react-sdk. Move Resend.js to react-sdk 2015-11-30 17:16:31 +00:00
Kegan Dougal
4e7aa78ed7 Move RoomList to react-sdk. Inject a ConferenceHandler. 2015-11-30 16:56:05 +00:00
Kegan Dougal
e792ebb837 Move and merge UserSettings to react-sdk 2015-11-30 15:53:13 +00:00
Matthew Hodgson
4409f07c2e oops, don't try to delete nonexistent tags when moving a room from conversations to favs or similar 2015-11-30 15:49:27 +00:00
Kegan Dougal
b89bd35cad Merge branch 'develop' into kegan/controller-merging4 2015-11-30 15:42:32 +00:00
Matthew Hodgson
4614017b8f Merge pull request #443 from vector-im/matthew/rename-message-components
Matthew/rename message components
2015-11-30 15:36:50 +00:00
Matthew Hodgson
7636645efc rename message components as per RL discussion this morning 2015-11-30 15:25:21 +00:00
Kegan Dougal
bd906cbc69 Move and merge LogoutPrompt to react-sdk 2015-11-30 15:23:37 +00:00
Kegan Dougal
cb30cbb09a Remove MemberList and put it in react-sdk 2015-11-30 15:14:04 +00:00
Kegan Dougal
2b37e5334a Remove Notifier and put it in react-sdk 2015-11-30 15:05:00 +00:00
Matthew Hodgson
f947400131 Open Sans 2015-11-30 14:17:33 +00:00
Kegan Dougal
fd4d7eba12 Remove ErrorDialog and QuestionDialog to react-sdk 2015-11-30 14:11:28 +00:00
Matthew Hodgson
8a00e71139 remove spurious Vector layer Avatar helper class 2015-11-30 13:56:53 +00:00
Kegan Dougal
83b3702769 Merge branch 'develop' into kegan/controller-merging4 2015-11-30 10:56:14 +00:00
Kegan Dougal
450b2d4d67 Move CreateRoom to react-sdk 2015-11-30 10:55:52 +00:00
Matthew Hodgson
cd040ae0dd fix zalgo properly! remove ugly regexp hacks for detecting combining diacritics and instead set the right font ordering, as Arial combines nicely with Myriad Pro whilst Helvetica doesn't. (Myriad Pro itself has no combining diacritic characters) 2015-11-30 01:13:59 +00:00
Matthew Hodgson
9a64dc27fc improve layout for search results, fix syntax highlighting quirks in sublime, and don't crash on zero results 2015-11-29 13:32:13 +00:00
Matthew Hodgson
af6bd53d38 revert 23d45d7f33 and apply a better fix which works for both chrome & FF 2015-11-29 13:18:37 +00:00
Matthew Hodgson
01f0e61d6e fix search ordering; add room labels; hide input areas if searching 2015-11-29 04:41:17 +00:00
Matthew Hodgson
fc02331cd3 fix CSS for search timestamps 2015-11-29 03:20:19 +00:00
Matthew Hodgson
e43edee9bb call highlighted search terms highlights, and uphold them if provided by synapse 2015-11-29 03:19:51 +00:00
Matthew Hodgson
8de94d45b1 swim like a salmon and manually update skindex for a generic TextualMessage type 2015-11-28 21:11:37 +00:00
Matthew Hodgson
9e97160c85 fix inline <code/> blocks 2015-11-27 16:20:37 +00:00
Kegsay
8a5828620c Merge pull request #425 from vector-im/kegan/controller-merging3
Phase 3 controller merging
2015-11-27 16:17:39 +00:00
Kegan Dougal
07001ae35e Remove unused files 2015-11-27 16:11:58 +00:00
Kegan Dougal
cd216e218c Merge branch 'develop' into kegan/controller-merging3 2015-11-27 15:44:52 +00:00
Kegsay
054836cd50 Merge pull request #421 from vector-im/kegan/controller-merging2
Phase 2 controller merging (all atoms)
2015-11-27 15:43:49 +00:00
Kegan Dougal
0ef7c8d16d Use the right name 2015-11-27 15:43:16 +00:00
Kegan Dougal
af30ef1f72 Remove unusued imports 2015-11-27 15:39:29 +00:00
Kegan Dougal
df86e85492 Move ContextualMenu to React SDK 2015-11-27 15:37:00 +00:00
Kegan Dougal
05c9b44b81 Move velocity stuff to react sdk 2015-11-27 15:34:26 +00:00
Kegan Dougal
0f3ea9f4ce Merge branch 'develop' into kegan/controller-merging2 2015-11-27 15:01:23 +00:00
Kegan Dougal
a5d00c73b2 Move HtmlUtils to react SDK 2015-11-27 15:01:06 +00:00
Kegsay
f9a5f4b61e Merge pull request #420 from vector-im/kegan/controller-merging
Phase 1 controller merging (general structure)
2015-11-27 14:59:38 +00:00
Kegan Dougal
40b974f22d Move all Event/Message Tiles to React SDK. 2015-11-27 14:35:16 +00:00
Kegan Dougal
f969ccb50c Move and merge RoomTile/MemberTile to react SDK. Keep DND stuff in vector as RoomDNDView. 2015-11-27 11:52:29 +00:00
Kegan Dougal
b007edca63 Merge and move RoomHeader/RoomSettings into React SDK 2015-11-27 10:42:25 +00:00
Kegan Dougal
3ce29622ed Move and merge MemberInfo to React SDK 2015-11-26 17:49:55 +00:00
Kegan Dougal
1a6afc2ef0 Move and merge UserSelector 2015-11-26 17:38:01 +00:00
Kegan Dougal
6dea8e7256 Move and merge MessageComposer 2015-11-26 17:31:37 +00:00
Kegan Dougal
7595071e6a Move and merge ProgressBar 2015-11-26 17:21:35 +00:00
Kegan Dougal
fdad00790e Move and merge Change* components to React SDK. Update references. 2015-11-26 17:11:26 +00:00
Kegan Dougal
9ecf5bed64 Nuke old CallView controller 2015-11-26 16:48:32 +00:00
Kegan Dougal
ff9608c914 Move and merge voip molecules. Inject the ConferenceHandler as a prop
This keeps the vector conf logic munge separate from react SDK.
2015-11-26 16:39:58 +00:00
Kegan Dougal
49e5f18f62 Move and merge create_room atoms to react SDK 2015-11-26 15:43:57 +00:00
Kegan Dougal
c5b0ea7e9f Move VideoFeed to React SDK 2015-11-26 15:24:32 +00:00
Kegan Dougal
83eae1b64a Move and merge EditableText into React SDK 2015-11-26 15:15:45 +00:00
Kegan Dougal
35ee9c9ddd Move and merge EnableNotificationsButton to react SDK 2015-11-26 15:10:49 +00:00
Kegan Dougal
0a8f5b6223 Move ImageView 2015-11-26 14:51:30 +00:00
Kegan Dougal
3f120c7027 Nuke LogoutButton; nothing used it. 2015-11-26 14:47:11 +00:00
Kegan Dougal
343670c5c4 Move MessageTimestamp 2015-11-26 14:38:48 +00:00
Kegan Dougal
f21b6203ed Merge branch 'kegan/controller-merging' into kegan/controller-merging2 2015-11-26 14:31:31 +00:00
Kegan Dougal
8517f9f2bf Missed one 2015-11-26 14:29:26 +00:00
Kegan Dougal
3c12191cb7 Move Spinner 2015-11-26 14:25:20 +00:00
Kegan Dougal
ab22ca6a28 Also move the existing login components to the new structure 2015-11-26 14:11:45 +00:00
Kegan Dougal
8898b444af Point things at the right places 2015-11-26 13:48:37 +00:00
Kegan Dougal
d079617ce2 Nuke MemberAvatar/RoomAvatar; moved to react SDK 2015-11-26 13:25:56 +00:00
Matthew Hodgson
93c67771af Merge pull request #324 from vector-im/erikj/video
Add basic m.video view support
2015-11-24 16:06:11 +00:00
Matthew Hodgson
f9040e08ce fix conflicts 2015-11-24 16:05:58 +00:00
Matthew Hodgson
fd8864d528 STOP PEOPLE SHOUTING 2015-11-22 22:35:34 +00:00
Matthew Hodgson
841c790337 naughty override to stop RoomList panel scrolling horizontally 2015-11-22 15:47:50 +00:00
Matthew Hodgson
324c3e7dcf override more GFM css 2015-11-22 15:47:10 +00:00
Matthew Hodgson
92728ff4e6 spell out npm run build 2015-11-22 01:13:08 +00:00
Matthew Hodgson
01641543da only try to syntax highlight html 2015-11-21 12:33:45 +00:00
Matthew Hodgson
9038b984ff fix css link 2015-11-21 12:15:38 +00:00
Matthew Hodgson
da97185fcd highlight <code/> blocks via highlight.js 2015-11-21 12:14:56 +00:00
Matthew Hodgson
b6e9c1eaab oops, forgot gfm.css 2015-11-20 20:20:30 +00:00
Matthew Hodgson
76c6d6d4d6 add target=_blank onto all HTML links, and apply GFM.css for CSS for markdown 2015-11-20 20:12:23 +00:00
Matthew Hodgson
4c11de787e make h2 layout specific to the list 2015-11-20 20:11:06 +00:00
Matthew Hodgson
96c825b89f wrap whitespace on notices 2015-11-20 20:10:49 +00:00
Matthew Hodgson
29af81e827 Refactor HTML markup stuff into its own class, and whitelist h1 and h2 2015-11-20 18:58:13 +00:00
David Baker
3cf9f5248b Fix the ref we keep to be the react element and make velociraptor correctly track what nodes it had at the start (c.key not c.props.key) 2015-11-20 18:22:38 +00:00
Kegsay
9ec10e2b43 Merge pull request #404 from vector-im/kegan/gif-on-enter
Add support for playing gifs on mouse enter/leave
2015-11-20 16:43:05 +00:00
Kegan Dougal
06427d663d Add support for playing gifs on mouse enter/leave 2015-11-20 16:36:58 +00:00
David Baker
2c51a5c199 Bugfix: don't cache the read avatar rect as it's relative to the viewport and it will move when we scroll! 2015-11-20 16:01:51 +00:00
Kegsay
6dc5dd4930 Merge pull request #403 from vector-im/kegan/post-register
Re-add in post registration steps
2015-11-20 15:06:19 +00:00
Kegan Dougal
29ee7d2b13 Remove useless logging 2015-11-20 14:34:26 +00:00
Kegan Dougal
2e376b1eb9 Clear the 'screen' to load the main left/middle/right panels, then show the settings after post-reg is done 2015-11-20 14:27:39 +00:00
Kegan Dougal
37254e6243 Add PostRegistration component 2015-11-20 12:02:37 +00:00
Kegan Dougal
1edea2a62c Add a PostRegistration component; hook it up to MatrixChat. 2015-11-20 12:02:23 +00:00
Kegsay
99ccff098c Merge pull request #399 from vector-im/kegan/reg-refactor
Refactor registration
2015-11-20 10:28:26 +00:00
Kegan Dougal
3075c97bae Set busy Spinner 2015-11-20 10:27:21 +00:00
Kegan Dougal
f62312fbf3 Remove old registration files. Move CaptchaForm to React SDK. 2015-11-20 10:18:04 +00:00
Matthew Hodgson
02d5154aaf more alt tags 2015-11-19 17:45:03 +00:00
Matthew Hodgson
41eaf18470 add hoverover test for edit button 2015-11-19 17:43:55 +00:00
Kegan Dougal
d372018e61 Minor tweaks 2015-11-19 16:47:14 +00:00
Kegan Dougal
bb6eeea0d8 Factor out div ID name to avoid tight coupling with logic class. 2015-11-19 16:08:25 +00:00
Kegan Dougal
3cf9f786aa Instantiate Signup.Register in Registration component
This has to be done rather than in MatrixChat because the render() calls
will create new instances otherwise. Pass in all the strings the logic class
requires to the Registration wire component. This isn't the "best" solution
because unloading/reloading the Registration component will lose registration
state which should be persisted. Ideally we'd DI from the top to ensure this
can't happen (as opposed to relying on module globals...)
2015-11-19 15:44:17 +00:00
Kegan Dougal
2d481a6302 Recheck registration state since we may be able to immediately do an HTTP hit if we've been given good QPs 2015-11-19 14:17:18 +00:00
Kegan Dougal
e700a5a219 Add TODO on post register logic 2015-11-19 13:58:52 +00:00
Matthew Hodgson
f7127ab701 Merge pull request #397 from vector-im/z_indices
Sort out dialog z index so read receipts avatars are behind the dialog background
2015-11-19 13:53:51 +00:00
Kegan Dougal
eaafc11064 Factor out Captcha UI 2015-11-19 13:44:11 +00:00
Richard van der Hoff
3a003341ad Merge pull request #387 from vector-im/rav/suppress_unread_on_memberchange
Don't mark rooms as unread on m.room.member changes
2015-11-19 13:22:37 +00:00
David Baker
f7fe871fee If read receipts avatar isn't on screen, animate it from the top of the screen. 2015-11-19 11:33:15 +00:00
David Baker
09b0d221df Kill the last getDOMNode() 2015-11-19 11:03:33 +00:00
David Baker
ed3d3a9e23 Shift css around a bit so it more closely matches DOM order 2015-11-19 10:49:24 +00:00
David Baker
eb1c6b347d Move z-index to the dialog wrapper because that's the shallowest positioned element in the DOM and therefore what creates the first stacking context 2015-11-19 10:46:49 +00:00
Kegan Dougal
5f57cd9559 Merge branch 'develop' into kegan/reg-refactor 2015-11-19 09:50:08 +00:00
David Baker
0dd85d9adf Hidden localstorage option to enable bouncy read receipts :p 2015-11-19 09:44:24 +00:00
Matthew Hodgson
23d45d7f33 fix initials behaviour on FF 2015-11-18 23:46:43 +00:00
Matthew Hodgson
69fdd485e6 general faff to make the new edit button position interact properly with dave's 'click to show all read receipts' 2015-11-18 23:41:38 +00:00
Matthew Hodgson
bf3e90bb47 dirty hack to fix the uneven spacing 2015-11-18 23:04:12 +00:00
Matthew Hodgson
68a005bf1f stop edit option from colliding with scrollbar again 2015-11-18 22:24:54 +00:00
Matthew Hodgson
884d0de90b s/React/ReactDOM/ to fix another 0.14 warning 2015-11-18 22:22:19 +00:00
Matthew Hodgson
6e3afcde53 dodgy fudge to put the edit button alongside the read receipts. in future I think we should turn it into a chevron next to the timestamp 2015-11-18 22:19:21 +00:00
Matthew Hodgson
d66006893a fix react 0.14 warning from getDOMNode() 2015-11-18 22:10:08 +00:00
Matthew Hodgson
8fed464cf6 and the new voice icon 2015-11-18 21:18:16 +00:00
Matthew Hodgson
08ba0457e8 add a temporary voice call button 2015-11-18 21:17:58 +00:00
Matthew Hodgson
098491e350 avoid hoverover artefacts on avatar initials 2015-11-18 20:56:43 +00:00
Matthew Hodgson
46541a3f2e logout button on splashscreen to avoid wedging users whose server has gone awol 2015-11-18 20:47:14 +00:00
Matthew Hodgson
c9fe0b96b7 fix whitespace 2015-11-18 20:46:39 +00:00
Matthew Hodgson
742ae354e5 clicking anywhere in the composer pane should focus on the textarea 2015-11-18 20:15:15 +00:00
Kegan Dougal
bc55959fad Load the Recaptcha script if we have a container for it
This is complex enough that the Registration component shouldn't have to
care about it, so it should probably be split into a pure UI component.
2015-11-18 17:46:17 +00:00
Kegan Dougal
5424567a66 Hook up onFormSubmit to make registration (dummy only) work again. 2015-11-18 17:15:20 +00:00
David Baker
f0df3f29b9 Show all read avatars on click 2015-11-18 17:12:17 +00:00
Kegan Dougal
b4c0625961 Show validation errors 2015-11-18 15:32:44 +00:00
David Baker
025b9e2fc8 depend on react sdk dev 2015-11-18 14:54:32 +00:00
David Baker
1099892784 Merge pull request #379 from vector-im/read_receipts
Read receipts
2015-11-18 14:53:29 +00:00
Richard van der Hoff
c42d4f901b Don't mark rooms as unread on m.room.member changes
A quick and hacky fix to issue #169.
2015-11-18 11:01:47 +00:00
Kegan Dougal
ed3527e243 Merge branch 'develop' into kegan/reg-refactor 2015-11-17 17:43:22 +00:00
Kegan Dougal
8e8b27c893 Add RegistrationForm UI component and new Registration wire component
Hook it up to MatrixChat instead of the existing logic (this breaks reg). WIP.
2015-11-17 17:40:31 +00:00
David Baker
c63dd376d8 Fix member avatar initials (I failed at git conflict merging) 2015-11-17 17:31:03 +00:00
David Baker
da55081c68 Add member name to avatars as the title since if displayed without accompanying text (as with read receipts) they can be somewhat unhelpful. May as well have them all the time I think. 2015-11-17 15:59:44 +00:00
David Baker
80c2bd0c7f Remove bouncing, set animation time to be constant (prevents temporary overalpping) and exclude ourselves. 2015-11-17 15:51:00 +00:00
Kegan Dougal
714c96283e Setting defaults from config.json got lost 2015-11-17 15:12:55 +00:00
Kegan Dougal
c57fb44c71 Fix path resolution 2015-11-17 13:26:23 +00:00
Kegan Dougal
8602e0665d PR feedback from #355 2015-11-17 10:57:44 +00:00
Kegsay
af1e3373ea Merge pull request #355 from vector-im/kegan/login-refactor
Refactor login page
2015-11-17 10:47:56 +00:00
Matthew Hodgson
79e39429b7 add todo 2015-11-17 02:40:19 +00:00
Matthew Hodgson
7b3eea0b58 experiment with trying to turn UserSettings into a controller-less 'wiring component' which wires together a series of smaller components (in this case, so small they're mainly <input/s> 2015-11-17 02:15:55 +00:00
Matthew Hodgson
88c5a5e074 missing copyright 2015-11-17 02:14:06 +00:00
David Baker
e23b90abd5 More s/messageWrapper/messagePanel/ 2015-11-16 16:52:07 +00:00
David Baker
7f61a0252f remove logging 2015-11-16 16:45:28 +00:00
David Baker
816f20e068 comma 2015-11-16 16:36:01 +00:00
David Baker
bb59e9276b Merge remote-tracking branch 'origin/develop' into read_receipts 2015-11-16 16:33:39 +00:00
David Baker
d6b86598e5 Bouncy bouncy! 2015-11-16 16:13:21 +00:00
Matthew Hodgson
bf91155e60 implement multiline input 2015-11-15 03:36:10 +00:00
Matthew Hodgson
ef181f55d5 make modal dialogs higher in z-index 2015-11-14 00:14:41 +00:00
Matthew Hodgson
1c7e7cd111 kill stale z-index param 2015-11-14 00:13:13 +00:00
Matthew Hodgson
063e387a65 turn off the placeholder drag & drop function to get an opinion from folks 2015-11-13 23:51:48 +00:00
Matthew Hodgson
ca07c8f429 Merge pull request #365 from vector-im/avatar_initial_a11y
Mark up the avatar initials so they're not read out by screen readers
2015-11-13 18:37:10 +00:00
Matthew Hodgson
2fd7196cdd also handle a11y on room avatars 2015-11-13 18:36:46 +00:00
Matthew Hodgson
ff59fc84c5 don't bold the selected room just because, as it bold = new msgs 2015-11-13 18:25:10 +00:00
David Baker
9d620dfb1d Hopefully now mostly complete animations: we iterate through zero or more start states and then settle on the final place. 2015-11-13 16:43:54 +00:00
David Baker
bc2c744bed more bits of read receipt animation implemented 2015-11-13 11:42:51 +00:00
David Baker
2fabf69ce3 Mark up the avatar initials so they're not read out by screen readers 2015-11-13 09:28:56 +00:00
Matthew Hodgson
f8d628d336 fix composer avatar 2015-11-13 02:44:46 +00:00
Matthew Hodgson
20f84ce322 override gemini-scrollbar CSS to stop the scrollview from pushing out the container, causing FF's flexbox to adapt and keep growing infinitely 2015-11-13 02:29:59 +00:00
Matthew Hodgson
2cf0ceb260 back out previous bodges to flexbox to make geminiscrollbar work in FF 2015-11-13 02:29:18 +00:00
Matthew Hodgson
36b7deac35 clear unread message count more aggressively (and revert previous thinko) 2015-11-13 01:42:09 +00:00
Matthew Hodgson
04305460db make firefox slightly happier 2015-11-13 01:19:40 +00:00
Matthew Hodgson
caa2fd97d1 sacrifice dead goats to make gemini-scrollbars work on firefox 42 and chrome 48 and later. the problem is that flexbox interacts badly with gemini-scrollbars, as gemini looks at the offsetWidth of the container in order to make the width of its enclosed scrollable view = width+scrollbarwidth. The problem is that flexbox then sees that the scrollable view has expanded, and unhelpfully flexes the container to fit it. This fixes the problem by providing more explicit widths for the containers to stop them flexing. I'm not sure I want to know why we don't also see the same problem with heights. 2015-11-13 00:46:50 +00:00
David Baker
e0efb6862e Merge pull request #354 from vector-im/ignore-non-mxc
Display some sensible UI for non-mxc content URLs.
2015-11-12 17:43:20 +00:00
David Baker
1ac47f32fe Fix scrolling on browsers where gemini scrollbars don't kick in. 2015-11-12 17:18:22 +00:00
Kegan Dougal
b1438355e2 Github and Sublime don't like this not being escaped. Displays fine though in React like this. 2015-11-12 15:58:12 +00:00
Kegan Dougal
021eaf5c29 Vector is the default IS in Vector 2015-11-12 15:54:07 +00:00
Kegan Dougal
726afd30bb Swap old login for new 2015-11-12 15:49:32 +00:00
Kegan Dougal
58472b8251 Move Cas/PasswordLogin to react-sdk. Use them as normal components. 2015-11-12 15:38:04 +00:00
Kegan Dougal
8826eb60cc Call through to password login 2015-11-12 15:16:29 +00:00
David Baker
c8a8306165 Display some sensible UI for non-mxc content URLs. 2015-11-12 14:16:57 +00:00
Matthew Hodgson
c12c716dc0 fix URLs on image 2015-11-12 13:34:00 +00:00
Kegan Dougal
05eda88ea2 Split out logic/UI for logging in
- Add 'PasswordLogin' UI component
- Add 'LoginPage' wire component which, along with Signup from react SDK,
  replaces the 'Login' page.
- Move UI code (state/props) from ServerConfig which was lobotomoised in the
  React SDK.

Unfinished.
2015-11-12 11:57:33 +00:00
Matthew Hodgson
2cae5e7a00 revert bad fix to managing history 2015-11-11 02:31:37 +01:00
Matthew Hodgson
2fff6f4d5f fix spinner layout yet more 2015-11-11 02:31:17 +01:00
Matthew Hodgson
81128ef06e hopefully fix https://github.com/vector-im/vector-web/issues/226 2015-11-11 02:07:41 +01:00
Matthew Hodgson
dd3427d8d0 remove unused component 2015-11-11 02:01:11 +01:00
Matthew Hodgson
2c9273a86c avoid the initial sync from clobbering the location bar 2015-11-11 02:00:51 +01:00
Matthew Hodgson
bc3ee949f5 fix warning about missing thead 2015-11-11 02:00:18 +01:00
Matthew Hodgson
5aa468f1e3 skin simpleheader 2015-11-11 01:59:56 +01:00
Matthew Hodgson
c2af09fbaa fix Spinner CSS a bit 2015-11-11 00:57:31 +01:00
Matthew Hodgson
bbd7124ac7 improve comment on how our dynamic height CSS works 2015-11-11 00:57:16 +01:00
Matthew Hodgson
adb7915b3e suppress warning 2015-11-11 00:56:51 +01:00
Matthew Hodgson
5c92b09da1 improve spacing on login screen 2015-11-11 00:56:44 +01:00
Matthew Hodgson
2e9e03bd45 oops, refresh the login options on mount. make autofocus work too. 2015-11-11 00:39:48 +01:00
Matthew Hodgson
19b31ff30d oops, make this actually work. 2015-11-11 00:06:49 +01:00
Matthew Hodgson
801154fd8a apply jsx 2015-11-11 00:05:35 +01:00
Matthew Hodgson
f628591e27 fix login page vertical scroll and centering 2015-11-10 19:19:23 +00:00
Matthew Hodgson
9cbd4ae2e4 fix raging typos 2015-11-10 19:15:14 +00:00
Matthew Hodgson
0825e0a2e2 retrieve last used HS/IS URL from local storage, and associated tweaks 2015-11-10 19:09:24 +00:00
Matthew Hodgson
68c1ddd5d2 replace react-loader with Spinner everywhere 2015-11-10 18:12:26 +00:00
David Baker
9a6624d1c7 Do read receipt avatars with absolute positioning: this should be a lot easier to animate. Also mess around with the MemberAvatar a bit so it's easier to style. 2015-11-10 17:44:59 +00:00
David Baker
c9823d07fd Limit number of read avatars, lay them out as per the design & order them. 2015-11-10 13:51:11 +00:00
David Baker
450036a6ed Merge remote-tracking branch 'origin/develop' into read_receipts 2015-11-10 11:26:42 +00:00
Matthew Hodgson
ef7a38e558 gemini scrollbar on the memberlist too 2015-11-10 02:26:46 +00:00
Matthew Hodgson
2ca64d9c15 add gemini-scrollbar to the main roomview 2015-11-10 02:04:21 +00:00
Matthew Hodgson
cb887c699e use gemini-scrollbar to provide fake scrollbars for the room list 2015-11-10 01:40:08 +00:00
Matthew Hodgson
2ccd881665 port to react 0.14, removing getDOMNode()s for DOM components and turning them into ReactDOM.findDOMNode()s for React components 2015-11-09 23:54:10 +00:00
Matthew Hodgson
87bb7c9b7b upgrade to react 0.14 2015-11-09 23:13:46 +00:00
Matthew Hodgson
6d9817e5e7 Merge pull request #342 from vector-im/matthew/orderable-roomlist
Implement reorderable rooms via room tagging.
2015-11-09 16:05:00 +00:00
Matthew Hodgson
23c93de82e Merge branch 'develop' into matthew/orderable-roomlist 2015-11-09 16:04:20 +00:00
Matthew Hodgson
bea64082a9 put the DragDropContext on LeftPanel rather than MatrixChat to allow index.js to continue to abuse MatrixChat by directly invoking the showScreen method on it 2015-11-09 15:44:08 +00:00
Kegsay
c3385d597a Merge pull request #332 from vector-im/kegan/syncing
Implement connection lost bar + resend all
2015-11-09 15:35:38 +00:00
Matthew Hodgson
752f8bdbb8 remove random bold initials 2015-11-09 14:04:43 +00:00
Matthew Hodgson
1f69760173 fix comedy scrolling parallax avatar initial bug 2015-11-09 12:41:23 +00:00
Matthew Hodgson
66add5673b de-hash rooms 2015-11-09 11:53:50 +00:00
Matthew Hodgson
a3082753ef shove initials onto default room & member avatars as per the design 2015-11-09 02:12:26 +00:00
Matthew Hodgson
eaa2f94327 warning png 2015-11-09 00:13:40 +00:00
Matthew Hodgson
615879ffdd skin to match CSS (spacing will need to be fixed once matthew/ordered-roomlist lands) 2015-11-09 00:13:25 +00:00
Matthew Hodgson
05d921256f re-skin the notification bar 2015-11-08 23:37:14 +00:00
Matthew Hodgson
9526deb024 add error dialogs and order search results by recents 2015-11-08 16:19:53 +00:00
Matthew Hodgson
567176ea6c put a load of margin on the bottommost sublist to increase its hit target size and avoid problems when toggling its hiddenness 2015-11-08 14:08:17 +00:00
Matthew Hodgson
5494a4ea6c s/deprioritize/demote/ 2015-11-08 13:50:36 +00:00
Matthew Hodgson
827c0da33c commented out debug 2015-11-08 13:42:45 +00:00
Matthew Hodgson
f0dbb422f6 update the actual target list, which may not be the same as the one we dropped on 2015-11-08 13:13:01 +00:00
Matthew Hodgson
5c406856ed adjust column widths to match design 2015-11-08 12:59:19 +00:00
Matthew Hodgson
b15def84bc fix spacing of the layout to match latest designs 2015-11-08 12:48:23 +00:00
Matthew Hodgson
bbbe074d92 hide all the debugging behind if (debug) 2015-11-08 12:24:32 +00:00
Matthew Hodgson
36da1accca click on CallView preview to jump to call 2015-11-08 12:14:10 +00:00
Matthew Hodgson
e289235e17 fix tooltip positioning when collapsed 2015-11-08 12:02:26 +00:00
Matthew Hodgson
c60e8736c1 handle collapsed drop-targets better 2015-11-08 11:50:15 +00:00
Matthew Hodgson
69899e3718 position sublist chevron better when collapsed 2015-11-08 11:44:13 +00:00
Matthew Hodgson
ed4c5b9f73 switch initial spinner to mx_Spinner 2015-11-07 20:16:44 +00:00
Matthew Hodgson
4e170a2831 fix onRoomTags signature 2015-11-07 20:16:05 +00:00
Matthew Hodgson
07200d7953 Merge branch 'develop' into matthew/orderable-roomlist 2015-11-07 17:29:18 +00:00
Matthew Hodgson
4a195dd3f0 sacrifice a small mountainside of goats to make placeholder-based work correctly 2015-11-07 02:57:56 +00:00
Matthew Hodgson
fe442f5c24 fix various edge cases when dragging stuff back to the conversations list 2015-11-06 23:30:57 +01:00
Matthew Hodgson
89327bd38f precedence fail :( 2015-11-06 21:33:28 +01:00
Matthew Hodgson
f102e3b3b7 collapsible sublist graphics 2015-11-06 21:25:35 +01:00
Matthew Hodgson
1150e22190 collapsible sublists 2015-11-06 21:25:20 +01:00
Matthew Hodgson
886ffbf158 switch to m.* prefixes for tags before it's too late 2015-11-06 21:00:34 +01:00
Matthew Hodgson
c884c5fc33 actually manage manual ordering; support arbitrary tags; bug fixes 2015-11-06 20:54:07 +01:00
David Baker
d462e0b21b Merge pull request #335 from stevenhammerton/sh-cas-token-login
Replace CAS login with token login
2015-11-06 15:41:15 +00:00
Steven Hammerton
fdf79d709e Replace CAS login with token login 2015-11-06 11:22:59 +00:00
David Baker
e20388388e null check 2015-11-05 17:40:37 +00:00
Kegan Dougal
3a8c263e8e Add resending bar (and resend all option)
Factor out resend logic which was in the context menu into a separate
Resend file (it shouldn't be in the skin, but it also isn't really
suitable for a controller given 2 different views invoke it..)
2015-11-05 15:59:03 +00:00
Kegan Dougal
804af341ac Add a 'connection lost' bar. 2015-11-05 14:52:44 +00:00
David Baker
0aa90d918c bump js-sdk dep to develop 2015-11-05 14:45:16 +00:00
David Baker
4bf6992398 Don't send read receipts for our own events and null check in a few places. 2015-11-05 14:16:15 +00:00
Matthew Hodgson
8842147ec3 skin RoomDropTarget correctly 2015-11-05 11:21:45 +00:00
David Baker
942659df0d Work around the bug where some channels have no name from the js sdk which was causing vector to exception and never load. 2015-11-04 14:15:57 +00:00
Matthew Hodgson
61e55b3ca3 implement most of drag & drop. 2015-11-04 02:25:08 +00:00
Matthew Hodgson
7fe7af6026 refactor out the sections of the RoomList into RoomSubLists. Start wiring up tags 2015-11-04 00:19:37 +00:00
Erik Johnston
7dc5f91fad Remove unused code 2015-11-03 18:59:45 +00:00
Erik Johnston
5b773b99c0 Add basic m.video view support 2015-11-03 18:56:55 +00:00
Matthew Hodgson
8b9b268ec0 make our state explicit 2015-11-03 14:35:55 +00:00
Matthew Hodgson
27cf9cf561 put invites above recents 2015-11-03 14:35:48 +00:00
Matthew Hodgson
b1b2704bed avoid racey NPE on first login 2015-11-03 14:35:39 +00:00
David Baker
2a4a02f36e More on read receipts: listen for events, add keys & class / very minimal css. 2015-11-03 13:44:40 +00:00
Matthew Hodgson
ff35e02b4d Merge pull request #317 from vector-im/erikj/icons
Use relative rather than absolute paths for icons
2015-11-02 23:53:27 +00:00
Erik Johnston
4dac9bc1b8 Use relative rather than absolute paths for icons 2015-11-02 23:47:04 +00:00
David Baker
11c38014e5 Sort of display read avatars but without live updating 2015-11-02 18:55:28 +00:00
Kegsay
842d6b6c2c Merge pull request #314 from vector-im/kegan/graceful-no-voip
Add unsupported suffix on Ongoing conf notification if conf calls are…
2015-11-02 18:18:46 +00:00
Kegan Dougal
6e63153d83 Add unsupported suffix on Ongoing conf notification if conf calls are unsupported in the browser 2015-11-02 18:01:20 +00:00
David Baker
159f0c9594 Merge remote-tracking branch 'origin/develop' into read_receipts 2015-11-02 14:29:20 +00:00
David Baker
e869814f2d Don't display anything if TextForEvent doesn't give us any text. Fixes #253 (catapillar of doom). 2015-11-02 14:14:47 +00:00
Kegsay
3b82884947 Merge pull request #298 from vector-im/kegan/reject-invites
Add invite rejection
2015-11-02 09:50:17 +00:00
Kegan Dougal
38780ad492 Merge branch 'develop' into kegan/reject-invites 2015-11-02 09:47:51 +00:00
Matthew Hodgson
e25d31a9fe Merge pull request #296 from vector-im/matthew/redesign
Matthew/redesign
2015-10-30 18:30:13 +00:00
Matthew Hodgson
56d00c2ec7 make onFinished required prop for modal contents 2015-10-30 18:26:22 +00:00
Matthew Hodgson
79af89fd1b fix missing decl 2015-10-30 18:26:05 +00:00
Matthew Hodgson
11e176df66 comment for the hidden collapse button 2015-10-30 18:23:08 +00:00
Matthew Hodgson
75bc878657 comment what a CR is 2015-10-30 18:22:21 +00:00
Matthew Hodgson
ddbc8dffb3 switch from enums to string literals for SearchBar.Scope 2015-10-30 18:21:54 +00:00
Matthew Hodgson
6aad99a505 comment \u200b 2015-10-30 18:20:29 +00:00
Matthew Hodgson
35cebc56d3 rewrite the HTML message stuff to fix XSS and improve clarity 2015-10-30 18:19:20 +00:00
Kegan Dougal
668234be4c Add reject button and impl 2015-10-30 17:18:25 +00:00
Kegsay
626e8bab1a Merge pull request #283 from vector-im/kegan/blocking
Add feature-based browser blocking
2015-10-30 14:59:06 +00:00
Kegan Dougal
633bbd8f29 Review comments: add chrome blurb. 2015-10-30 14:58:47 +00:00
David Baker
ffb9ce89c7 Merge branch 'develop' into matthew/redesign 2015-10-30 11:50:34 +00:00
David Baker
ce9a91e155 bundle.css shouldn't be necessary apart from the vector/bundle.* above 2015-10-30 11:33:33 +00:00
Matthew Hodgson
fdfa0cbd0e display search results correct; support HTML markup 2015-10-30 04:10:37 +00:00
Matthew Hodgson
d315e4afcd show m.room.names 2015-10-30 02:06:34 +00:00
Matthew Hodgson
80c04048d0 cancel viewsource dialog with escape 2015-10-29 21:30:29 +00:00
Matthew Hodgson
05d96f4cfb fix filters, and stop react exploding on unrecognised event tiles 2015-10-29 18:28:30 +00:00
Matthew Hodgson
8239e57fa1 more lightbox tweaks 2015-10-29 18:28:30 +00:00
David Baker
f4ca30bb38 Throw exception if EventTile is instantiated with an event type it doesn't support. 2015-10-29 18:12:42 +00:00
Kegan Dougal
cc313f350c Merge branch 'develop' into kegan/blocking 2015-10-29 16:03:26 +00:00
Erik Johnston
ae2768af9c Remove left/right padding from ongoing call notification, so that we don't get scrollbars in chrome 2015-10-29 15:57:31 +00:00
Kegan Dougal
511b1f409c Add objectfit and localstorage to browser features 2015-10-29 15:56:03 +00:00
David Baker
f00ee95563 Merge branch 'develop' of github.com:vector-im/vector-web into read_receipts 2015-10-29 11:27:56 +00:00
Matthew Hodgson
9fd2bf0989 remove transparent background for now; specify image width & height; punt the label over to the far RHS; to get around various layout problems in Chrome 44 and Safari 8 2015-10-29 11:01:23 +00:00
Matthew Hodgson
2c05515141 simplify keys 2015-10-29 02:34:06 +00:00
Matthew Hodgson
eb6fbe6a5a theoretically scope the search, but it doesn't work 2015-10-29 02:24:35 +00:00
Matthew Hodgson
2ee840922d basic implementation of search 2015-10-29 02:03:04 +00:00
Matthew Hodgson
0ade5ff640 lightbox buttons 2015-10-29 00:39:12 +00:00
Matthew Hodgson
dc401075a7 try to make the edit button more reliable 2015-10-29 00:38:51 +00:00
Matthew Hodgson
de1e8e9f93 implement redact and links 2015-10-29 00:38:26 +00:00
Matthew Hodgson
dbac2e299e tweak spacing of label on lightbox 2015-10-28 22:49:20 +00:00
Matthew Hodgson
8eaa96b0b3 black magic fixes to the lightbox 2015-10-28 19:41:49 +00:00
Matthew Hodgson
cb095ba5a0 WIP search stuff 2015-10-28 19:41:23 +00:00
Matthew Hodgson
0bfb1416c1 WIP search stuff 2015-10-28 19:39:45 +00:00
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
Kegan Dougal
22369729f9 Remove test feature 2015-10-28 17:42:19 +00:00
Kegan Dougal
59d8cbe742 Use Modernizr to check for browser compatibility
Add a CompatibilityPage which is shown for incompatible clients. If they
continue on regardless, proceed as if it never happened.
2015-10-28 17:39:50 +00:00
Matthew Hodgson
00a7ea994a kill random grey backgrounds for transparent avatars 2015-10-28 16:52:50 +00:00
David Baker
4118c05d15 Unused variables 2015-10-28 16:23:48 +00:00
Matthew Hodgson
7fbe38e74d fix padding feckup 2015-10-28 16:02:59 +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
Matthew Hodgson
a25207960c search bar 2015-10-28 01:05:28 +00:00
Matthew Hodgson
04aff6aab7 unhide labels on recents menu for Amandine 2015-10-27 23:51:40 +00:00
Matthew Hodgson
cbaf134625 merge develop 2015-10-27 23:28:34 +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
David Baker
b8fc926255 Send read receipts 2015-10-27 14:38:46 +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
Matthew Hodgson
aac00db16b WIP for new lightbox viewer 2015-10-27 01:39:19 +00:00
Matthew Hodgson
7c445cc108 fix error when joining rooms 2015-10-27 01:17:42 +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
363e3f4e21 image viewing tweaks 2015-10-25 23:33:28 +00:00
Matthew Hodgson
78cff9f20d fix upload drop target 2015-10-25 23:13:03 +00:00
Matthew Hodgson
86fb313b9b fix upload drop target 2015-10-25 23:12:57 +00:00
Matthew Hodgson
8840895e70 fix progressbar 2015-10-25 23:08:21 +00:00
Matthew Hodgson
ed76a46739 list power like this for now 2015-10-25 23:01:16 +00:00
Matthew Hodgson
7fdb82d87f memberinfo look & feel 2015-10-25 22:55:30 +00:00
Matthew Hodgson
729babae4f quick implementation of all new MemberInfo 2015-10-25 19:09:38 +00:00
Matthew Hodgson
731881ee7b fix language 2015-10-25 12:35:52 +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
47dca51c38 spell out how to set up the deps when developing 2015-10-25 12:33:13 +00:00
Matthew Hodgson
1ecf0f0183 Merge branch 'develop' of git+ssh://github.com/vector-im/vector-web into matthew/redesign 2015-10-25 11:57:35 +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
435a9cd9e4 actually use the config file for default HS and IS URLs... 2015-10-25 02:42:41 +00:00
Matthew Hodgson
8cd6d70c0a fix voip buttons header 2015-10-25 02:36:27 +00:00
Matthew Hodgson
1d3c821672 improve spacing a bit 2015-10-25 02:26:24 +00:00
Matthew Hodgson
6d6e1366dc s/Delete/Redact/ 2015-10-25 02:13:01 +00:00
Matthew Hodgson
19d272b171 Merge branch 'develop' of git+ssh://github.com/vector-im/vector-web into matthew/redesign 2015-10-25 02:12:35 +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
Matthew Hodgson
8ebb8ba427 fix up new message layout 2015-10-25 02:09:16 +00:00
Matthew Hodgson
9c215efcbf fix up header layout some more 2015-10-25 02:09:06 +00:00
Matthew Hodgson
6e3e0a1447 implement new roomheader 2015-10-25 01:52:28 +00:00
Matthew Hodgson
d16968d528 update badge count in realtime 2015-10-25 01:16:41 +00:00
Matthew Hodgson
28c3787fb3 implement bottom-right call button 2015-10-25 01:03:22 +00:00
Matthew Hodgson
d8bc362a89 fix invites 2015-10-25 00:59:33 +01:00
Matthew Hodgson
13f3548057 fix badge pos 2015-10-24 20:58:00 +01:00
Matthew Hodgson
39871e52df fix NPE 2015-10-24 20:57:05 +01:00
Matthew Hodgson
0cffd8dd84 sort out files button & NPE 2015-10-24 20:56:27 +01:00
Matthew Hodgson
f4d21f883a Add on a membership badge 2015-10-24 20:47:48 +01:00
Matthew Hodgson
a74cef0d64 fix stupid typing warnings 2015-10-24 20:28:42 +01:00
Matthew Hodgson
e59bfe16dc sort out the membership list 2015-10-24 20:19:54 +01:00
Matthew Hodgson
e718cad053 invites section 2015-10-24 02:02:33 +01:00
Matthew Hodgson
b6cac2bc89 Merge branch 'develop' of git+ssh://github.com/vector-im/vector-web into matthew/redesign 2015-10-23 18:03:49 +01:00
Matthew Hodgson
a86861e9b9 make badges work again 2015-10-23 18:03:35 +01:00
Matthew Hodgson
6e2362e8a9 reskin file upload UI 2015-10-23 17:43:40 +01:00
Matthew Hodgson
300005243c only bold current room if it has unread msgs 2015-10-23 17:43:30 +01: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
Matthew Hodgson
4019e359ca fix visibility during contextual window 2015-10-23 12:46:08 +01:00
Matthew Hodgson
185efb00fb new buttons 2015-10-23 12:41:59 +01:00
Matthew Hodgson
d946b39671 stop annoying popping and fix layout of hoverover tile stuff 2015-10-23 12:41:51 +01:00
Matthew Hodgson
c74dc8ef47 slightly prettier source view 2015-10-23 12:41:32 +01:00
Matthew Hodgson
7292a2ced5 kill blue lozenges 2015-10-23 12:40:28 +01:00
Matthew Hodgson
baf777a418 Merge branch 'develop' into matthew/redesign 2015-10-23 11:25:20 +01:00
Matthew Hodgson
11e6cf9757 Merge branch 'develop' into matthew/redesign 2015-10-23 11:22:00 +01:00
Matthew Hodgson
30b2156278 fix typing notifs 2015-10-23 11:19:13 +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
7f65ba506b WIP of new CSS 2015-10-23 02:39:56 +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
9d8d4e4896 Support email login 2015-08-04 16:30:41 +01:00
399 changed files with 7544 additions and 10685 deletions

10
.gitignore vendored
View File

@@ -1,4 +1,8 @@
node_modules
build
bundle.css
bundle.js
vector/bundle.*
lib
.DS_Store
key.pem
cert.pem
vector/components.css
packages/

14
.modernizr.json Normal file
View File

@@ -0,0 +1,14 @@
{
"minify": true,
"classPrefix": "modernizr_",
"options": [
"setClasses"
],
"feature-detects": [
"test/css/displaytable",
"test/css/flexbox",
"test/es5/specification",
"test/css/objectfit",
"test/storage/localstorage"
]
}

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

171
README.md
View File

@@ -10,138 +10,79 @@ Getting started
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/vector`
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
Vector.
With `npm start`, any changes you make to the source files will cause a rebuild so
your changes will show up when you refresh. This development server also disables
caching, so do NOT use it in production.
For production use, run `npm run build` to build all the necessary files
into the `vector` directory and run your own server.
Development
===========
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:
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.
1. Link the react sdk package into the example:
`cd vector-web/examples/vector; npm link ../../`
2. Start a watcher for the CSS files:
`cd vector-web; npm run start:css`
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 handled by Vector's `package.json`. To get the right dependencies, check out
the `develop` branches of these libraries and then use `npm link` to tell Vector
about them:
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.
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 run build`
6. `npm start` (to start the dev rebuilder)
7. `cd ../vector-web`
8. Link the react sdk package into the example:
`npm link path/to/your/react/sdk`
IMPORTANT: If you customise components in your application (and hence require
react from your app) you must be sure to:
Similarly, you may need to `npm link path/to/your/js/sdk` in your `matrix-react-sdk`
directory.
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.
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`.
How to customise the SDK
========================
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 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.
Deployment
==========
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:
Just run `npm run build` and then mount the `vector` directory on your webserver to
actually serve up the app, which is entirely static content.
* 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.
Enabling encryption
===================
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:
End-to-end encryption in Vector and Matrix is not yet considered ready for
day-to-day use; it is experimental and should be considered only as a
proof-of-concept. See https://matrix.org/jira/browse/SPEC-162 for an overview
of the current progress.
* Views are named with upper camel case (e.g. molecules/MessageTile.js)
To build a version of vector with support for end-to-end encryption, install
the olm module with `npm i https://matrix.org/packages/npm/olm/olm-0.1.0.tgz`
before running `npm start`. The olm library will be detected and used if
available.
* The view's CSS file MUST have the same name (e.g. molecules/MessageTile.css)
To enable encryption for a room, type
* 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.
```
/encrypt on
```
* 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.
in the message bar in that room. Vector will then generate a set of keys, and
encrypt all outgoing messages in that room. (Note that other people in that
room will send messages in the clear unless they also `/encrypt on`.)
* 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.
Note that historical encrypted messages cannot currently be decoded - history
is therefore lost when the page is reloaded.
* 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.
There is currently no visual indication of whether encryption is enabled for a
room, or whether a particular message was encrypted.

4
config.json Normal file
View File

@@ -0,0 +1,4 @@
{
"default_hs_url": "http://127.0.0.1:8008",
"default_is_url": "https://vector.im"
}

170
deploy/redeploy.py Executable file
View File

@@ -0,0 +1,170 @@
#!/usr/bin/env python
from __future__ import print_function
import json, requests, tarfile, argparse, os, errno
from urlparse import urljoin
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
arg_jenkins_url, arg_extract_path, arg_should_clean, arg_symlink = (
None, None, None, None
)
def download_file(url):
local_filename = url.split('/')[-1]
r = requests.get(url, stream=True)
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
return local_filename
def untar_to(tarball, dest):
with tarfile.open(tarball) as tar:
tar.extractall(dest)
def create_symlink(source, linkname):
try:
os.symlink(source, linkname)
except OSError, e:
if e.errno == errno.EEXIST:
# atomic modification
os.symlink(source, linkname + ".tmp")
os.rename(linkname + ".tmp", linkname)
else:
raise e
@app.route("/", methods=["POST"])
def on_receive_jenkins_poke():
# {
# "name": "VectorWebDevelop",
# "build": {
# "number": 8
# }
# }
incoming_json = request.get_json()
if not incoming_json:
abort(400, "No JSON provided!")
return
print("Incoming JSON: %s" % (incoming_json,))
job_name = incoming_json.get("name")
if not isinstance(job_name, basestring):
abort(400, "Bad job name: %s" % (job_name,))
return
build_num = incoming_json.get("build", {}).get("number", 0)
if not build_num or build_num <= 0 or not isinstance(build_num, int):
abort(400, "Missing or bad build number")
return
artifact_url = urljoin(
arg_jenkins_url, "job/%s/%s/api/json" % (job_name, build_num)
)
artifact_response = requests.get(artifact_url).json()
# {
# "actions": [],
# "artifacts": [
# {
# "displayPath": "vector-043f6991a4ed-react-20f77d1224ef-js-0a7efe3e8bd5.tar.gz",
# "fileName": "vector-043f6991a4ed-react-20f77d1224ef-js-0a7efe3e8bd5.tar.gz",
# "relativePath": "vector-043f6991a4ed-react-20f77d1224ef-js-0a7efe3e8bd5.tar.gz"
# }
# ],
# "building": false,
# "description": null,
# "displayName": "#11",
# "duration": 137976,
# "estimatedDuration": 132008,
# "executor": null,
# "fullDisplayName": "VectorWebDevelop #11",
# "id": "11",
# "keepLog": false,
# "number": 11,
# "queueId": 12254,
# "result": "SUCCESS",
# "timestamp": 1454432640079,
# "url": "http://matrix.org/jenkins/job/VectorWebDevelop/11/",
# "builtOn": "",
# "changeSet": {},
# "culprits": []
# }
if artifact_response.get("result") != "SUCCESS":
abort(404, "Not deploying. Build was not marked as SUCCESS.")
return
if len(artifact_response.get("artifacts", [])) != 1:
abort(404, "Not deploying. Build has an unexpected number of artifacts.")
return
tar_gz_path = artifact_response["artifacts"][0]["relativePath"]
if not tar_gz_path.endswith(".tar.gz"):
abort(404, "Not deploying. Artifact is not a .tar.gz file")
return
tar_gz_url = urljoin(
arg_jenkins_url, "job/%s/%s/artifact/%s" % (job_name, build_num, tar_gz_path)
)
print("Retrieving .tar.gz file: %s" % tar_gz_url)
filename = download_file(tar_gz_url)
print("Downloaded file: %s" % filename)
name_str = filename.replace(".tar.gz", "")
untar_location = os.path.join(arg_extract_path, name_str)
untar_to(filename, untar_location)
if arg_should_clean:
os.remove(filename)
# stamp the version somewhere JS can get to it
with open(os.path.join(untar_location, "vector/version"), "w") as stamp_file:
stamp_file.write(name_str)
create_symlink(source=os.path.join(untar_location, "vector"), linkname=arg_symlink)
return jsonify({})
if __name__ == "__main__":
parser = argparse.ArgumentParser("Runs a Vector redeployment server.")
parser.add_argument(
"-j", "--jenkins", dest="jenkins", default="http://matrix.org/jenkins/", help=(
"The base URL of the Jenkins web server. This will be hit to get the\
built artifacts (the .gz file) for redeploying."
)
)
parser.add_argument(
"-p", "--port", dest="port", default=4000, type=int, help=(
"The port to listen on for requests from Jenkins."
)
)
parser.add_argument(
"-e", "--extract", dest="extract", default="./extracted", help=(
"The location to extract .tar.gz files to."
)
)
parser.add_argument(
"-c", "--clean", dest="clean", action="store_true", default=False, help=(
"Remove .tar.gz files after they have been downloaded and extracted."
)
)
parser.add_argument(
"-s", "--symlink", dest="symlink", default="./latest", help=(
"Write a symlink to this location pointing to the extracted tarball. \
New builds will keep overwriting this symlink. The symlink will point \
to the /vector directory INSIDE the tarball."
)
)
args = parser.parse_args()
if args.jenkins.endswith("/"): # important for urljoin
arg_jenkins_url = args.jenkins
else:
arg_jenkins_url = args.jenkins + "/"
arg_extract_path = args.extract
arg_should_clean = args.clean
arg_symlink = args.symlink
print(
"Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s" %
(args.port, arg_extract_path,
" (clean after)" if arg_should_clean else "", arg_symlink, arg_jenkins_url)
)
app.run(host="0.0.0.0", port=args.port, debug=True)

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 +0,0 @@
../../skins/base/fonts/

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/icons/mstile-70x70.png"/>
<square150x150logo src="/icons/mstile-150x150.png"/>
<square310x310logo src="/icons/mstile-310x310.png"/>
<wide310x150logo src="/icons/mstile-310x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>

View File

@@ -1 +0,0 @@
../../skins/base/img

View File

@@ -1,46 +0,0 @@
<!doctype html>
<html lang="en" style="height: 100%;">
<head>
<meta charset="utf-8">
<title>Vector</title>
<link href='fonts/Lato.css' rel='stylesheet' type='text/css'>
<link rel="apple-touch-icon" sizes="57x57" href="/icons/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/icons/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/icons/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/icons/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/icons/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/icons/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/icons/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/icons/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="/icons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/icons/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="/icons/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="/icons/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/icons/manifest.json">
<link rel="shortcut icon" href="/icons/favicon.ico">
<meta name="apple-mobile-web-app-title" content="Vector">
<meta name="application-name" content="Vector">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-TileImage" content="/icons/mstile-144x144.png">
<meta name="msapplication-config" content="/icons/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
</head>
<body style="height: 100%;">
<audio id="ringbackAudio" loop>
<source src="media/ringback.ogg" type="audio/ogg" />
<source src="media/ringback.mp3" type="audio/mpeg" />
</audio>
<audio id="callendAudio">
<source src="media/callend.ogg" type="audio/ogg" />
<source src="media/callend.mp3" type="audio/mpeg" />
</audio>
<audio id="busyAudio">
<source src="media/busy.ogg" type="audio/ogg" />
<source src="media/busy.mp3" type="audio/mpeg" />
</audio>
<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,83 +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");
// In normal usage of the module:
//var MatrixReactSdk = require("matrix-react-sdk");
// Or to import the source directly from the file system:
// (This is useful for debugging the SDK as it seems source
// maps cannot pass through two stages).
var MatrixReactSdk = require("../../src/index");
// Here, we do some crude URL analysis to allow
// deep-linking. We only support registration
// deep-links in this example.
function routeUrl(location) {
if (location.hash.indexOf('#/register') == 0) {
var hashparts = location.hash.split('?');
var params = {};
if (hashparts.length == 2) {
var pairs = hashparts[1].split('&');
for (var i = 0; i < pairs.length; ++i) {
var parts = pairs[i].split('=');
if (parts.length != 2) continue;
params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
}
}
window.matrixChat.showScreen('register', params);
} else {
window.matrixChat.showScreen(location.hash.substring(2));
}
}
function onHashChange(ev) {
routeUrl(window.location);
}
var loaded = false;
// This will be called whenever the SDK changes screens,
// so a web page can update the URL bar appropriately.
var onNewScreen = function(screen) {
if (!loaded) return;
window.location.hash = '#/'+screen;
}
// We use this to work out what URL the SDK should
// pass through when registering to allow the user to
// click back to the client having registered.
// It's up to us to recognise if we're loaded with
// this URL and tell MatrixClient to resume registration.
var makeRegistrationUrl = function() {
return window.location.protocol + '//' +
window.location.host +
window.location.pathname +
'#/register';
}
window.matrixChat = React.render(
<MatrixReactSdk.MatrixChat onNewScreen={onNewScreen} registrationUrl={makeRegistrationUrl()} />,
document.getElementById('matrixchat')
);
window.addEventListener('hashchange', onHashChange);
window.onload = function() {
routeUrl(window.location);
loaded = true;
}

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 --ignore olm -t [ envify --NODE_ENV production ] -t reactify index.js | uglifyjs -c -m -o bundle.js",
"start": "parallelshell \"watchify --ignore olm -v -d -t reactify index.js -o bundle.js\" \"http-server\""
}
}

14
jenkins.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash -l
export NVM_DIR="/home/jenkins/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm use 4
npm install
(cd node_modules/matrix-react-sdk && npm run build) # npm doesn't do this when dependencies point at github.com >:(
npm run build # Dumps artificats to /vector
# gzip up ./vector
rm vector-*.tar.gz || true # rm previous artifacts without failing if it doesn't exist
REACT_SHA=$(grep 'gitHead' node_modules/matrix-react-sdk/package.json | cut -d \" -f 4 | head -c 12) # node_modules deps from 'npm install' don't have a .git dir so can't rev-parse.
JSSDK_SHA=$(grep 'gitHead' node_modules/matrix-js-sdk/package.json | cut -d \" -f 4 | head -c 12) # But they do set the commit in package.json under 'gitHead' which we're grabbing here.
VECTOR_SHA=$(git rev-parse --short=12 HEAD) # use the ACTUAL SHA rather than assume develop
tar -zcvhf vector-$VECTOR_SHA-react-$REACT_SHA-js-$JSSDK_SHA.tar.gz vector #g[z]ip, [c]reate archive, [v]erbose, [f]ilename, [h]ard-dereference (do not archive symlinks)

28
karma.conf.js Normal file
View File

@@ -0,0 +1,28 @@
// karma.conf.js
var webpack = require('webpack');
module.exports = function (config) {
config.set({
browsers: ['Chrome'],
singleRun: true,
frameworks: ['mocha'],
files: [
'tests.webpack.js'
],
preprocessors: {
'tests.webpack.js': ['webpack']
},
reporters: ['dots'],
webpack: {
module: {
loaders: [
{test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader'}
]
},
watch: true
},
webpackServer: {
noInfo: true
}
});
};

View File

@@ -1,40 +1,72 @@
{
"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",
"matrix-react-parent": "matrix-react-sdk",
"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 -h src/header",
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
"build:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/components.css --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",
"package": "npm run build && mkdir -p packages && tar chvzf packages/vector-`git describe --dirty || echo unknown`.tar.gz vector",
"start:js": "webpack -w src/vector/index.js vector/bundle.js",
"start:js:prod": "NODE_ENV=production webpack -w src/vector/index.js vector/bundle.js",
"start:skins:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/components.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\"",
"start:prod": "parallelshell \"npm run start:js:prod\" \"npm run start:skins:css\" \"http-server -c 1 vector\"",
"clean": "rimraf lib vector/bundle.css vector/bundle.js vector/bundle.js.map vector/webpack.css*",
"prepublish": "npm run build:css && npm run build:compile"
},
"dependencies": {
"babel-polyfill": "^6.5.0",
"classnames": "^2.1.2",
"extract-text-webpack-plugin": "^0.9.1",
"filesize": "^3.1.2",
"flux": "^2.0.3",
"matrix-js-sdk": "git://github.com/matrix-org/matrix-js-sdk.git#no-trickle-ice",
"flux": "~2.0.3",
"gemini-scrollbar": "^1.3.0",
"gfm.css": "^1.1.1",
"highlight.js": "^9.0.0",
"linkifyjs": "^2.0.0-beta.4",
"matrix-js-sdk": "https://github.com/matrix-org/matrix-js-sdk.git#develop",
"matrix-react-sdk": "https://github.com/matrix-org/matrix-react-sdk.git#develop",
"modernizr": "^3.1.0",
"q": "^1.4.1",
"react": "^0.13.3",
"react-loader": "^1.4.0",
"linkifyjs": "^2.0.0-beta.4"
"react": "^0.14.2",
"react-dnd": "^2.0.2",
"react-dnd-html5-backend": "^2.0.0",
"react-dom": "^0.14.2",
"react-gemini-scrollbar": "^2.0.1",
"sanitize-html": "^1.11.1"
},
"devDependencies": {
"babel": "^5.8.23",
"babel-core": "^5.8.25",
"babel-loader": "^5.3.2",
"catw": "^1.0.1",
"css-raw-loader": "^0.1.1",
"http-server": "^0.8.4",
"json-loader": "^0.5.3",
"parallelshell": "^1.2.0",
"react-tools": "^0.13.3",
"uglifycss": "0.0.15"
"rimraf": "^2.4.3",
"source-map-loader": "^0.1.5",
"webpack": "^1.12.13",
"karma": ">=0.0.0",
"karma-cli": ">=0.0.0",
"karma-mocha": ">=0.0.0",
"karma-webpack": ">=0.0.0",
"karma-sourcemap-loader": ">=0.0.0",
"karma-chrome-launcher": ">=0.0.0",
"mocha": ">=0.0.0",
"expect": ">=0.0.0"
}
}

View File

@@ -1,124 +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.
*/
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;
}
/* FIXME: show them on hoverover, and fix for firefox */
::-webkit-scrollbar {
display: none;
}
html {
overflow: -moz-scrollbars-none;
}
/* FIXME: why is all the dialog stuff in here rather than in per-component files? */
.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;
}
.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

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

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.
*/
.mx_MemberInfo {
text-align: center;
border: 1px solid #a9dbf4;
border-radius: 8px;
background-color: #fff;
position: absolute;
width: 200px;
margin-left: -295px;
margin-top: 0px;
z-index: 1000;
padding: 6px;
}
.mx_MemberInfo_chevron {
padding: 12px;
position: absolute;
right: -21px;
top: 0px;
}
/*
* a hacky shim to extend the hitmask of the overlay to overlap
* better with the main menu itself
*/
.mx_MemberInfo_shim {
position: absolute;
left: 212px;
width: 40px;
height: 100%;
}
.mx_MemberInfo_avatar {
padding: 6px;
}
.mx_MemberInfo_avatarImg {
border-radius: 128px;
}
.mx_MemberInfo_field {
padding: 6px;
overflow: hidden;
text-overflow: ellipsis;
}
.mx_MemberInfo_button {
vertical-align: middle;
max-width: 100px;
height: 36px;
background-color: #50e3c2;
line-height: 36px;
border-radius: 36px;
color: #fff;
margin: auto;
margin-top: 6px;
margin-bottom: 6px;
}

View File

@@ -1,107 +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_MemberTile {
cursor: pointer;
display: table-row;
height: 49px;
}
.mx_MemberTile_avatar {
display: table-cell;
padding-right: 12px;
padding-top: 3px;
padding-bottom: 3px;
vertical-align: middle;
width: 40px;
height: 40px;
position: relative;
}
.mx_MemberTile_avatarImg {
z-index: 20;
border-radius: 20px;
background-color: #dbdbdb;
}
.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;
}
.mx_MemberTile_power {
z-index: 10;
position: absolute;
width: 48px;
height: 48px;
left: -4px;
top: -1px;
}
.mx_MemberTile_name {
display: table-cell;
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
}
.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.75;
}
.mx_MemberTile_offline .mx_MemberTile_avatar,
.mx_MemberTile_offline .mx_MemberTile_name,
.mx_MemberTile_offline .mx_MemberTile_nameSpan
{
opacity: 0.5;
}
.mx_MemberTile_zalgo {
font-family: Helvetica, Arial, Sans-Serif;
}
.mx_MemberTile_leave {
float: right;
}

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.
*/
.mx_MessageTile {
max-width: 100%;
clear: both;
margin-top: 32px;
margin-left: 56px;
}
.mx_MessageTile_avatar {
padding-left: 12px;
padding-right: 12px;
margin-left: -64px;
margin-top: -7px;
float: left;
}
.mx_MessageTile_avatar img {
background-color: #dbdbdb;
border-radius: 20px;
border: 0px;
}
.mx_MessageTile_continuation {
margin-top: 8px ! important;
}
.mx_MessageTile .mx_SenderProfile {
color: #454545;
opacity: 0.5;
font-size: 14px;
margin-bottom: 4px;
display: block;
}
.mx_MessageTile .mx_MessageTimestamp {
color: #454545;
opacity: 0.5;
font-size: 14px;
float: right;
}
.mx_MessageTile_content {
padding-right: 100px;
display: block;
}
.mx_MessageTile_notice .mx_MessageTile_content {
opacity: 0.5;
}
.mx_MessageTile_sending {
color: #ddd;
}
.mx_MessageTile_notSent {
color: #f11;
}
.mx_MessageTile_highlight {
color: #00f;
}
.mx_MessageTile_msgOption {
float: right;
}
.mx_MessageTimestamp {
display: none;
}
.mx_MessageTile_last .mx_MessageTimestamp {
display: block;
}
.mx_MessageTile:hover .mx_MessageTimestamp {
display: block;
}

View File

@@ -1,154 +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_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;
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;
-webkit-flex: 0 0 90px;
flex: 0 0 90px;
}
.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: scroll;
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_nameInput {
border-radius: 3px;
width: 260px;
border: 1px solid #c7c7c7;
font-weight: 300;
font-size: 14px;
padding: 9px;
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-y: scroll;
}
.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;
}

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.
*/
.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

@@ -1,166 +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_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_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;
border-bottom: 1px solid #a8dbf3;
overflow: scroll;
-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%;
margin-top: 18px;
margin-bottom: 18px;
overflow-y: scroll;
}
.mx_RoomView_messageListWrapper {
max-width: 720px;
margin: auto;
}
.mx_RoomView_MessageList {
width: 100%;
}
.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_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: black;
height: 5px;
}
.mx_RoomView_uploadProgressInner {
background-color: blue;
height: 5px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

View File

@@ -1,77 +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 EditableTextController = require("../../../../src/controllers/atoms/EditableText");
module.exports = React.createClass({
displayName: 'EditableText',
mixins: [EditableTextController],
onKeyUp: function(ev) {
if (ev.key == "Enter") {
this.onFinish(ev);
} else if (ev.key == "Escape") {
this.cancelEdit();
}
},
onClickDiv: function() {
console.log("onClickDiv triggered");
this.setState({
phase: this.Phases.Edit,
})
},
onFocus: function(ev) {
ev.target.setSelectionRange(0, ev.target.value.length);
},
onFinish: function(ev) {
if (ev.target.value) {
this.setValue(ev.target.value, ev.key === "Enter");
} else {
this.cancelEdit();
}
},
render: function() {
var editable_el;
if (this.state.phase == this.Phases.Display) {
if (this.state.value) {
editable_el = <div ref="display_div" onClick={this.onClickDiv}>{this.state.value}</div>;
} else {
editable_el = <div ref="display_div" onClick={this.onClickDiv}>{this.props.label}</div>;
}
} else if (this.state.phase == this.Phases.Edit) {
editable_el = (
<div>
<input type="text" defaultValue={this.state.value} onKeyUp={this.onKeyUp} onFocus={this.onFocus} onBlur={this.onFinish} placeholder={this.props.placeHolder} autoFocus/>
</div>
);
}
return (
<div className="mx_EditableText">
{editable_el}
</div>
);
}
});

View File

@@ -1,59 +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 ImageViewController = require("../../../../src/controllers/atoms/ImageView");
module.exports = React.createClass({
displayName: 'ImageView',
mixins: [ImageViewController],
render: function() {
// XXX: can't we just do max-width: 80%, max-height: 80% on the CSS?
var width = this.props.width || 500;
var height = this.props.height || 500;
var maxWidth = document.documentElement.clientWidth * 0.8;
var maxHeight = document.documentElement.clientHeight * 0.8;
var widthFrac = width / maxWidth;
var heightFrac = height / maxHeight;
var displayWidth;
var displayHeight;
if (widthFrac > heightFrac) {
displayWidth = Math.min(width, maxWidth);
displayHeight = (displayWidth / width) * height;
} else {
displayHeight = Math.min(height, maxHeight);
displayWidth = (displayHeight / height) * width;
}
var style = {
width: displayWidth,
height: displayHeight
};
return (
<img className="mx_ImageView" src={this.props.src} style={style} />
);
}
});

View File

@@ -1,32 +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 LogoutButtonController = require("../../../../src/controllers/atoms/LogoutButton");
module.exports = React.createClass({
displayName: 'LogoutButton',
mixins: [LogoutButtonController],
render: function() {
return (
<button className="mx_LogoutButton" onClick={this.onClick}>Sign out</button>
);
}
});

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 PresetsController = require("../../../../../src/controllers/atoms/create_room/Presets");
module.exports = React.createClass({
displayName: 'CreateRoomPresets',
mixins: [PresetsController],
onValueChanged: function(ev) {
this.props.onChange(ev.target.value)
},
render: function() {
return (
<select className="mx_Presets" onChange={this.onValueChanged} value={this.props.preset}>
<option value={this.Presets.PrivateChat}>Private Chat</option>
<option value={this.Presets.PublicChat}>Public Chat</option>
<option value={this.Presets.Custom}>Custom</option>
</select>
);
}
});

View File

@@ -1,79 +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 RoomAliasController = require("../../../../../src/controllers/atoms/create_room/RoomAlias");
module.exports = React.createClass({
displayName: 'RoomAlias',
mixins: [RoomAliasController],
onValueChanged: function(ev) {
this.props.onChange(ev.target.value);
},
onFocus: function(ev) {
var target = ev.target;
var curr_val = ev.target.value;
if (this.props.homeserver) {
if (curr_val == "") {
setTimeout(function() {
target.value = "#:" + this.props.homeserver;
target.setSelectionRange(1, 1);
}, 0);
} else {
var suffix = ":" + this.props.homeserver;
setTimeout(function() {
target.setSelectionRange(
curr_val.startsWith("#") ? 1 : 0,
curr_val.endsWith(suffix) ? (target.value.length - suffix.length) : target.value.length
);
}, 0);
}
}
},
onBlur: function(ev) {
var curr_val = ev.target.value;
if (this.props.homeserver) {
if (curr_val == "#:" + this.props.homeserver) {
ev.target.value = "";
return;
}
if (curr_val != "") {
var new_val = ev.target.value;
var suffix = ":" + this.props.homeserver;
if (!curr_val.startsWith("#")) new_val = "#" + new_val;
if (!curr_val.endsWith(suffix)) new_val = new_val + suffix;
ev.target.value = new_val;
}
}
},
render: function() {
return (
<input type="text" className="mx_RoomAlias" placeholder="Alias (optional)"
onChange={this.onValueChanged} onFocus={this.onFocus} onBlur={this.onBlur}
value={this.props.alias}/>
);
}
});

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 React = require('react');
var classNames = require('classnames');
var dis = require("../../../../src/dispatcher");
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
module.exports = React.createClass({
displayName: 'BottomLeftMenu',
onSettingsClick: function() {
dis.dispatch({action: 'view_user_settings'});
},
onRoomDirectoryClick: function() {
dis.dispatch({action: 'view_room_directory'});
},
onCreateRoomClick: function() {
dis.dispatch({action: 'view_create_room'});
},
render: function() {
return (
<div className="mx_BottomLeftMenu">
<div className="mx_BottomLeftMenu_options">
<div className="mx_RoomTile" onClick={this.onCreateRoomClick}>
<div className="mx_RoomTile_avatar">
<img src="img/create-big.png" alt="Create new room" title="Create new room" width="42" height="42"/>
</div>
<div className="mx_RoomTile_name">Create new room</div>
</div>
<div className="mx_RoomTile" onClick={this.onRoomDirectoryClick}>
<div className="mx_RoomTile_avatar">
<img src="img/directory-big.png" alt="Directory" title="Directory" width="42" height="42"/>
</div>
<div className="mx_RoomTile_name">Directory</div>
</div>
<div className="mx_RoomTile" onClick={this.onSettingsClick}>
<div className="mx_RoomTile_avatar">
<img src="img/settings-big.png" alt="Settings" title="Settings" width="42" height="42"/>
</div>
<div className="mx_RoomTile_name">Settings</div>
</div>
</div>
</div>
);
}
});

View File

@@ -1,65 +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 ChangeAvatarController = require("../../../../src/controllers/molecules/ChangeAvatar");
var Loader = require("react-loader");
module.exports = React.createClass({
displayName: 'ChangeAvatar',
mixins: [ChangeAvatarController],
onFileSelected: function(ev) {
this.setAvatarFromFile(ev.target.files[0]);
},
onError: function(error) {
this.setState({
errorText: "Failed to upload profile picture!"
});
},
render: function() {
switch (this.state.phase) {
case this.Phases.Display:
case this.Phases.Error:
return (
<div>
<div className="mx_Dialog_content">
<img src={this.state.avatarUrl}/>
</div>
<div className="mx_Dialog_content">
Upload new:
<input type="file" onChange={this.onFileSelected}/>
{this.state.errorText}
</div>
<div className="mx_Dialog_buttons">
<button onClick={this.props.onFinished}>Cancel</button>
</div>
</div>
);
case this.Phases.Uploading:
return (
<Loader />
);
}
}
});

View File

@@ -1,85 +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 ChangePasswordController = require("../../../../src/controllers/molecules/ChangePassword");
var Loader = require("react-loader");
module.exports = React.createClass({
displayName: 'ChangePassword',
mixins: [ChangePasswordController],
onClickChange: function() {
var old_password = this.refs.old_input.getDOMNode().value;
var new_password = this.refs.new_input.getDOMNode().value;
var confirm_password = this.refs.confirm_input.getDOMNode().value;
if (new_password != confirm_password) {
this.setState({
state: this.Phases.Error,
errorString: "Passwords don't match"
});
} else if (new_password == '' || old_password == '') {
this.setState({
state: this.Phases.Error,
errorString: "Passwords can't be empty"
});
} else {
this.changePassword(old_password, new_password);
}
},
render: function() {
switch (this.state.phase) {
case this.Phases.Edit:
case this.Phases.Error:
return (
<div>
<div className="mx_Dialog_content">
<div>{this.state.errorString}</div>
<div><label>Old password <input type="password" ref="old_input"/></label></div>
<div><label>New password <input type="password" ref="new_input"/></label></div>
<div><label>Confirm password <input type="password" ref="confirm_input"/></label></div>
</div>
<div className="mx_Dialog_buttons">
<button onClick={this.onClickChange}>Change Password</button>
<button onClick={this.props.onFinished}>Cancel</button>
</div>
</div>
);
case this.Phases.Uploading:
return (
<div className="mx_Dialog_content">
<Loader />
</div>
);
case this.Phases.Success:
return (
<div>
<div className="mx_Dialog_content">
Success!
</div>
<div className="mx_Dialog_buttons">
<button onClick={this.props.onFinished}>Ok</button>
</div>
</div>
)
}
}
});

View File

@@ -1,48 +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 EventAsTextTileController = require("../../../../src/controllers/molecules/EventAsTextTile");
var ComponentBroker = require('../../../../src/ComponentBroker');
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
var TextForEvent = require("../../../../src/TextForEvent");
module.exports = React.createClass({
displayName: 'EventAsTextTile',
mixins: [EventAsTextTileController],
render: function() {
var text = TextForEvent.textForEvent(this.props.mxEvent);
var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null;
return (
<div className="mx_MessageTile mx_MessageTile_notice">
<div className="mx_MessageTile_avatar">
<img src={ this.props.mxEvent.sender ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.mxEvent.sender, 40, 40, "crop") : null } width="40" height="40" alt=""/>
</div>
{ timestamp }
<span className="mx_SenderProfile"></span>
<span className="mx_MessageTile_content">
{TextForEvent.textForEvent(this.props.mxEvent)}
</span>
</div>
);
},
});

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');
var MFileTileController = require("../../../../src/controllers/molecules/MFileTile");
var MatrixClientPeg = require('../../../../src/MatrixClientPeg');
module.exports = React.createClass({
displayName: 'MFileTile',
mixins: [MFileTileController],
render: function() {
var content = this.props.mxEvent.getContent();
var cli = MatrixClientPeg.get();
return (
<span className="mx_MFileTile">
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
{this.presentableTextForFile(content)}
</a>
</span>
);
},
});

View File

@@ -1,87 +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 MImageTileController = require("../../../../src/controllers/molecules/MImageTile");
var MatrixClientPeg = require('../../../../src/MatrixClientPeg');
var Modal = require('../../../../src/Modal');
var ComponentBroker = require('../../../../src/ComponentBroker');
var ImageView = ComponentBroker.get("atoms/ImageView");
module.exports = React.createClass({
displayName: 'MImageTile',
mixins: [MImageTileController],
thumbHeight: function(fullWidth, fullHeight, thumbWidth, thumbHeight) {
if (!fullWidth || !fullHeight) {
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
// log this because it's spammy
return undefined;
}
if (fullWidth < thumbWidth && fullHeight < thumbHeight) {
// no scaling needs to be applied
return fullHeight;
}
var widthMulti = thumbWidth / fullWidth;
var heightMulti = thumbHeight / fullHeight;
if (widthMulti < heightMulti) {
// width is the dominant dimension so scaling will be fixed on that
return Math.floor(widthMulti * fullHeight);
}
else {
// height is the dominant dimension so scaling will be fixed on that
return Math.floor(heightMulti * fullHeight);
}
},
onClick: function(ev) {
var ms = ev.getModifierState();
if (ev.button == 0 && !ev.metaKey) {
ev.preventDefault();
var content = this.props.mxEvent.getContent();
var httpUrl = MatrixClientPeg.get().mxcUrlToHttp(content.url);
Modal.createDialog(ImageView, {
src: httpUrl,
width: content.info.w,
height: content.info.h
});
}
},
render: function() {
var content = this.props.mxEvent.getContent();
var cli = MatrixClientPeg.get();
var thumbHeight = null;
if (content.info) thumbHeight = this.thumbHeight(content.info.w, content.info.h, 320, 240);
var imgStyle = {};
if (thumbHeight) imgStyle['height'] = thumbHeight;
return (
<span className="mx_MImageTile">
<a href={cli.mxcUrlToHttp(content.url)} onClick={this.onClick}>
<img src={cli.mxcUrlToHttp(content.url, 320, 240)} alt={content.body} style={imgStyle} />
</a>
</span>
);
},
});

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 MNoticeTileController = require("../../../../src/controllers/molecules/MNoticeTile");
module.exports = React.createClass({
displayName: 'MNoticeTile',
mixins: [MNoticeTileController],
render: function() {
var content = this.props.mxEvent.getContent();
return (
<span ref="content" className="mx_MNoticeTile mx_MessageTile_content">
{content.body}
</span>
);
},
});

View File

@@ -1,55 +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 MRoomMemberTileController = require("../../../../src/controllers/molecules/MRoomMemberTile");
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
var ComponentBroker = require('../../../../src/ComponentBroker');
var TextForEvent = require('../../../../src/TextForEvent');
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
module.exports = React.createClass({
displayName: 'MRoomMemberTile',
mixins: [MRoomMemberTileController],
getMemberEventText: function() {
return TextForEvent.textForEvent(this.props.mxEvent);
},
render: function() {
// XXX: for now, just cheekily borrow the css from message tile...
var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null;
var text = this.getMemberEventText();
if (!text) return <div/>;
return (
<div className="mx_MessageTile mx_MessageTile_notice">
<div className="mx_MessageTile_avatar">
<img src={ this.props.mxEvent.target ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.mxEvent.target, 40, 40, "crop") : null } width="40" height="40" alt=""/>
</div>
{ timestamp }
<span className="mx_SenderProfile"></span>
<span className="mx_MessageTile_content">
{ text }
</span>
</div>
);
},
});

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 MTextTileController = require("../../../../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">
{content.body}
</span>
);
},
});

View File

@@ -1,120 +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 MemberInfoController = require("../../../../src/controllers/molecules/MemberInfo");
module.exports = React.createClass({
displayName: 'MemberInfo',
mixins: [MemberInfoController],
componentDidMount: function() {
var self = this;
var memberInfo = this.getDOMNode();
var memberListScroll = document.getElementsByClassName("mx_MemberList_border")[0];
if (memberListScroll) {
memberInfo.style.top = (memberInfo.parentElement.offsetTop - memberListScroll.scrollTop) + "px";
}
},
getDuration: function(time) {
if (!time) return;
var t = parseInt(time / 1000);
var s = t % 60;
var m = parseInt(t / 60) % 60;
var h = parseInt(t / (60 * 60)) % 24;
var d = parseInt(t / (60 * 60 * 24));
if (t < 60) {
if (t < 0) {
return "0s";
}
return s + "s";
}
if (t < 60 * 60) {
return m + "m";
}
if (t < 24 * 60 * 60) {
return h + "h";
}
return d + "d ";
},
render: function() {
var power;
if (this.props.member) {
var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
power = <img src={ img } className="mx_MemberTile_power" width="48" height="48" alt=""/>;
}
var activeAgo = "unknown";
if (this.state.active >= 0) {
activeAgo = this.getDuration(this.state.active);
}
var kickButton, banButton, muteButton, giveModButton;
if (this.state.can.kick) {
kickButton = <div className="mx_MemberInfo_button" onClick={this.onKick}>
Kick
</div>;
}
if (this.state.can.ban) {
banButton = <div className="mx_MemberInfo_button" onClick={this.onBan}>
Ban
</div>;
}
if (this.state.can.mute) {
var muteLabel = this.state.muted ? "Unmute" : "Mute";
muteButton = <div className="mx_MemberInfo_button" onClick={this.onMuteToggle}>
{muteLabel}
</div>;
}
if (this.state.can.modifyLevel) {
var giveOpLabel = this.state.isTargetMod ? "Revoke Mod" : "Make Mod";
giveModButton = <div className="mx_MemberInfo_button" onClick={this.onModToggle}>
{giveOpLabel}
</div>
}
var opLabel;
if (this.state.isTargetMod) {
var level = this.props.member.powerLevelNorm + "%";
opLabel = <div className="mx_MemberInfo_field">Moderator ({level})</div>
}
return (
<div className="mx_MemberInfo">
<img className="mx_MemberInfo_chevron" src="img/chevron-right.png" width="9" height="16" />
<div className="mx_MemberInfo_shim"></div>
<div className="mx_MemberInfo_avatar">
<img className="mx_MemberInfo_avatarImg"
src={ this.props.member ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.member, 128, 128, "crop") : null }
width="128" height="128" alt=""/>
</div>
<div className="mx_MemberInfo_field">{this.props.member.userId}</div>
{opLabel}
<div className="mx_MemberInfo_field">Presence: {this.state.presence}</div>
<div className="mx_MemberInfo_field">Last active: {activeAgo}</div>
<div className="mx_MemberInfo_button" onClick={this.onChatClick}>Start chat</div>
{muteButton}
{kickButton}
{banButton}
{giveModButton}
</div>
);
}
});

View File

@@ -1,107 +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 Modal = require("../../../../src/Modal");
var MemberTileController = require("../../../../src/controllers/molecules/MemberTile");
var MemberInfo = ComponentBroker.get('molecules/MemberInfo');
var ErrorDialog = ComponentBroker.get("organisms/ErrorDialog");
// The Lato WOFF doesn't include sensible combining diacritics, so Chrome chokes on rendering them.
// Revert to Arial when this happens, which on OSX works at least.
var zalgo = /[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/;
module.exports = React.createClass({
displayName: 'MemberTile',
mixins: [MemberTileController],
// XXX: should these be in the controller?
getInitialState: function() {
return { 'hover': false };
},
mouseEnter: function(e) {
this.setState({ 'hover': true });
},
mouseLeave: function(e) {
this.setState({ 'hover': false });
},
render: function() {
var isMyUser = MatrixClientPeg.get().credentials.userId == this.props.member.userId;
var power;
if (this.props.member) {
var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
power = <img src={ img } className="mx_MemberTile_power" width="48" height="48" alt=""/>;
}
var presenceClass = "mx_MemberTile_offline";
var mainClassName = "mx_MemberTile ";
if (this.props.member.user) {
if (this.props.member.user.presence === "online") {
presenceClass = "mx_MemberTile_online";
}
else if (this.props.member.user.presence === "unavailable") {
presenceClass = "mx_MemberTile_unavailable";
}
}
mainClassName += presenceClass;
var name = this.props.member.name;
if (isMyUser) name += " (me)";
var leave = isMyUser ? <span className="mx_MemberTile_leave" onClick={this.onLeaveClick}>X</span> : null;
var nameClass = this.state.hover ? "mx_MemberTile_nameSpan" : "mx_MemberTile_name";
if (zalgo.test(name)) {
nameClass += " mx_MemberTile_zalgo";
}
var nameEl;
if (this.state.hover) {
nameEl =
<div className="mx_MemberTile_nameWrapper">
<MemberInfo member={this.props.member} />
<span className={nameClass}>{name}</span>
{leave}
</div>
}
else {
nameEl =
<div className={nameClass}>
{name}
{leave}
</div>
}
return (
<div className={mainClassName} onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }>
<div className="mx_MemberTile_avatar">
<img className="mx_MemberTile_avatarImg"
src={ this.props.member ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.member, 40, 40, "crop") : null }
width="40" height="40" alt=""/>
{ power }
</div>
{ nameEl }
</div>
);
}
});

View File

@@ -1,65 +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 MessageComposerController = require("../../../../src/controllers/molecules/MessageComposer");
var ContentMessages = require("../../../../src/ContentMessages");
module.exports = React.createClass({
displayName: 'MessageComposer',
mixins: [MessageComposerController],
onUploadClick: function(ev) {
this.refs.uploadInput.getDOMNode().click();
},
onUploadFileSelected: function(ev) {
var files = ev.target.files;
// MessageComposer shouldn't have to rely on it's parent passing in a callback to upload a file
if (files && files.length > 0) {
this.props.uploadFile(files[0]);
}
this.refs.uploadInput.getDOMNode().value = null;
},
render: function() {
var me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
var uploadInputStyle = {display: 'none'};
return (
<div className="mx_MessageComposer">
<div className="mx_MessageComposer_wrapper">
<div className="mx_MessageComposer_row">
<div className="mx_MessageComposer_avatar">
<img src={ MatrixClientPeg.get().getAvatarUrlForMember(me, 40, 40, "crop") } width="40" height="40" alt=""/>
</div>
<div className="mx_MessageComposer_input">
<textarea ref="textarea" onKeyDown={this.onKeyDown} placeholder="Type a message" />
</div>
<div className="mx_MessageComposer_upload" onClick={this.onUploadClick}>
<img src="img/upload.png" width="32" height="32"/>
<input type="file" style={uploadInputStyle} ref="uploadInput" onChange={this.onUploadFileSelected} />
</div>
</div>
</div>
</div>
);
},
});

View File

@@ -1,87 +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 MatrixClientPeg = require("../../../../src/MatrixClientPeg");
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: ['sending', 'queued'].indexOf(
this.props.mxEvent.status
) !== -1,
mx_MessageTile_notSent: this.props.mxEvent.status == 'not_sent',
mx_MessageTile_highlight: this.shouldHighlight(),
mx_MessageTile_continuation: this.props.continuation,
mx_MessageTile_last: this.props.last,
});
var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />
var avatar, sender, resend;
if (!this.props.continuation) {
avatar = (
<div className="mx_MessageTile_avatar">
<img src={ this.props.mxEvent.sender ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.mxEvent.sender, 40, 40, "crop") : null } width="40" height="40" alt=""/>
</div>
);
sender = <SenderProfile mxEvent={this.props.mxEvent} />;
}
if (this.props.mxEvent.status === "not_sent" && !this.state.resending) {
resend = <button className="mx_MessageTile_msgOption" onClick={this.onResend}>
Resend
</button>;
}
return (
<div className={classes}>
{ avatar }
{ timestamp }
{ resend }
{ sender }
<TileType mxEvent={this.props.mxEvent} />
</div>
);
},
});

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 React = require('react');
var ProgressBarController = require("../../../../src/controllers/molecules/ProgressBar");
module.exports = React.createClass({
displayName: 'ProgressBar',
mixins: [ProgressBarController],
render: function() {
// Would use an HTML5 progress tag but if that doesn't animate if you
// use the HTML attributes rather than styles
var progressStyle = {
width: ((this.props.value / this.props.max) * 100)+"%"
};
return (
<div className="mx_ProgressBar"><div className="mx_ProgressBar_fill" style={progressStyle}></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 classNames = require('classnames');
//var RoomCreateController = require("../../../../src/controllers/molecules/RoomCreateController");
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
module.exports = React.createClass({
displayName: 'RoomCreate',
// mixins: [RoomCreateController],
render: function() {
return (
<div className="mx_RoomCreate">
<div className="mx_RoomCreate_table">
<div className="mx_RoomTile">
<div className="mx_RoomTile_avatar">
<img src="img/create.png" width="32" height="32"/>
</div>
<div className="mx_RoomTile_name">Create new room</div>
</div>
</div>
</div>
);
}
});

View File

@@ -1,126 +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 MatrixClientPeg = require("../../../../src/MatrixClientPeg");
var RoomHeaderController = require("../../../../src/controllers/molecules/RoomHeader");
var EditableText = ComponentBroker.get("atoms/EditableText");
module.exports = React.createClass({
displayName: 'RoomHeader',
mixins: [RoomHeaderController],
onNameChange: function(new_name) {
if (this.props.room.name != new_name && new_name) {
MatrixClientPeg.get().setRoomName(this.props.room.roomId, new_name);
}
},
getRoomName: function() {
return this.refs.name_edit.getDOMNode().value;
},
render: function() {
var header;
if (this.props.simpleHeader) {
header =
<div className="mx_RoomHeader_wrapper">
<div className="mx_RoomHeader_simpleHeader">
{ this.props.simpleHeader }
</div>
</div>
}
else {
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
var callButtons;
if (this.state) {
switch (this.state.call_state) {
case "ringback":
case "connected":
callButtons = (
<div className="mx_RoomHeader_textButton" onClick={this.onHangupClick}>
End call
</div>
);
break;
}
}
var name = null;
var topic_el = null;
var save_button = null;
var settings_button = null;
var actual_name = this.props.room.currentState.getStateEvents('m.room.name', '');
if (actual_name) actual_name = actual_name.getContent().name;
if (this.props.editing) {
name =
<div className="mx_RoomHeader_nameEditing">
<input className="mx_RoomHeader_nameInput" type="text" defaultValue={actual_name} placeholder="Name" ref="name_edit"/>
</div>
// if (topic) topic_el = <div className="mx_RoomHeader_topic"><textarea>{ topic.getContent().topic }</textarea></div>
} else {
name =
<div className="mx_RoomHeader_name">
<EditableText label={this.props.room.name} initialValue={actual_name} placeHolder="Name" onValueChanged={this.onNameChange} />
</div>
if (topic) topic_el = <div className="mx_RoomHeader_topic">{ topic.getContent().topic }</div>;
settings_button = (
<div className="mx_RoomHeader_button" onClick={this.props.onSettingsClick}>
<img src="img/settings.png" width="32" height="32"/>
</div>
);
}
header =
<div className="mx_RoomHeader_wrapper">
<div className="mx_RoomHeader_leftRow">
<div className="mx_RoomHeader_avatar">
<img src={ MatrixClientPeg.get().getAvatarUrlForRoom(this.props.room, 48, 48, "crop") } width="48" height="48" alt=""/>
</div>
<div className="mx_RoomHeader_info">
{ name }
{ topic_el }
</div>
</div>
{callButtons}
<div className="mx_RoomHeader_rightRow">
{ settings_button }
<div className="mx_RoomHeader_button mx_RoomHeader_search">
<img src="img/search.png" title="Search" alt="Search" width="32" height="32"/>
</div>
<div className="mx_RoomHeader_button mx_RoomHeader_video" onClick={this.onVideoClick}>
<img src="img/video.png" title="Video call" alt="Video call" width="32" height="32"/>
</div>
<div className="mx_RoomHeader_button mx_RoomHeader_voice" onClick={this.onVoiceClick}>
<img src="img/voip.png" title="VoIP call" alt="VoIP call" width="32" height="32"/>
</div>
</div>
</div>
}
return (
<div className="mx_RoomHeader">
{ header }
</div>
);
},
});

View File

@@ -1,219 +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 RoomSettingsController = require("../../../../src/controllers/molecules/RoomSettings");
module.exports = React.createClass({
displayName: 'RoomSettings',
mixins: [RoomSettingsController],
getTopic: function() {
return this.refs.topic.getDOMNode().value;
},
getJoinRules: function() {
return this.refs.is_private.getDOMNode().checked ? "invite" : "public";
},
getHistoryVisibility: function() {
return this.refs.share_history.getDOMNode().checked ? "shared" : "invited";
},
getPowerLevels: function() {
if (!this.state.power_levels_changed) return undefined;
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
power_levels = power_levels.getContent();
var new_power_levels = {
ban: parseInt(this.refs.ban.getDOMNode().value),
kick: parseInt(this.refs.kick.getDOMNode().value),
redact: parseInt(this.refs.redact.getDOMNode().value),
invite: parseInt(this.refs.invite.getDOMNode().value),
events_default: parseInt(this.refs.events_default.getDOMNode().value),
state_default: parseInt(this.refs.state_default.getDOMNode().value),
users_default: parseInt(this.refs.users_default.getDOMNode().value),
users: power_levels.users,
events: power_levels.events,
};
return new_power_levels;
},
onPowerLevelsChanged: function() {
this.setState({
power_levels_changed: true
});
},
render: function() {
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
if (topic) topic = topic.getContent().topic;
var join_rule = this.props.room.currentState.getStateEvents('m.room.join_rules', '');
if (join_rule) join_rule = join_rule.getContent().join_rule;
var history_visibility = this.props.room.currentState.getStateEvents('m.room.history_visibility', '');
if (history_visibility) history_visibility = history_visibility.getContent().history_visibility;
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
if (power_levels) {
power_levels = power_levels.getContent();
var ban_level = parseInt(power_levels.ban);
var kick_level = parseInt(power_levels.kick);
var redact_level = parseInt(power_levels.redact);
var invite_level = parseInt(power_levels.invite || 0);
var send_level = parseInt(power_levels.events_default || 0);
var state_level = parseInt(power_levels.state_default || 0);
var default_user_level = parseInt(power_levels.users_default || 0);
if (power_levels.ban == undefined) ban_level = 50;
if (power_levels.kick == undefined) kick_level = 50;
if (power_levels.redact == undefined) redact_level = 50;
var user_levels = power_levels.users || [];
var events_levels = power_levels.events || [];
var user_id = MatrixClientPeg.get().credentials.userId;
var current_user_level = user_levels[user_id];
if (current_user_level == undefined) current_user_level = default_user_level;
var power_level_level = events_levels["m.room.power_levels"];
if (power_level_level == undefined) {
power_level_level = state_level;
}
var can_change_levels = current_user_level >= power_level_level;
} else {
var ban_level = 50;
var kick_level = 50;
var redact_level = 50;
var invite_level = 0;
var send_level = 0;
var state_level = 0;
var default_user_level = 0;
var user_levels = [];
var events_levels = [];
var current_user_level = 0;
var power_level_level = 0;
var can_change_levels = false;
}
var banned = this.props.room.getMembersWithMemership("ban");
return (
<div className="mx_RoomSettings">
<textarea className="mx_RoomSettings_description" placeholder="Topic" defaultValue={topic} ref="topic"/> <br/>
<label><input type="checkbox" ref="is_private" defaultChecked={join_rule != "public"}/> Make this room private</label> <br/>
<label><input type="checkbox" ref="share_history" defaultChecked={history_visibility == "shared"}/> Share message history with new users</label> <br/>
<label className="mx_RoomSettings_encrypt"><input type="checkbox" /> Encrypt room</label> <br/>
<h3>Power levels</h3>
<div className="mx_RoomSettings_power_levels mx_RoomSettings_settings">
<div>
<label htmlFor="mx_RoomSettings_ban_level">Ban level</label>
<input type="text" defaultValue={ban_level} size="3" ref="ban" id="mx_RoomSettings_ban_level"
disabled={!can_change_levels || current_user_level < ban_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div>
<label htmlFor="mx_RoomSettings_kick_level">Kick level</label>
<input type="text" defaultValue={kick_level} size="3" ref="kick" id="mx_RoomSettings_kick_level"
disabled={!can_change_levels || current_user_level < kick_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div>
<label htmlFor="mx_RoomSettings_redact_level">Redact level</label>
<input type="text" defaultValue={redact_level} size="3" ref="redact" id="mx_RoomSettings_redact_level"
disabled={!can_change_levels || current_user_level < redact_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div>
<label htmlFor="mx_RoomSettings_invite_level">Invite level</label>
<input type="text" defaultValue={invite_level} size="3" ref="invite" id="mx_RoomSettings_invite_level"
disabled={!can_change_levels || current_user_level < invite_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div>
<label htmlFor="mx_RoomSettings_event_level">Send event level</label>
<input type="text" defaultValue={send_level} size="3" ref="events_default" id="mx_RoomSettings_event_level"
disabled={!can_change_levels || current_user_level < send_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div>
<label htmlFor="mx_RoomSettings_state_level">Set state level</label>
<input type="text" defaultValue={state_level} size="3" ref="state_default" id="mx_RoomSettings_state_level"
disabled={!can_change_levels || current_user_level < state_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div>
<label htmlFor="mx_RoomSettings_user_level">Default user level</label>
<input type="text" defaultValue={default_user_level} size="3" ref="users_default"
id="mx_RoomSettings_user_level" disabled={!can_change_levels || current_user_level < default_user_level}
onChange={this.onPowerLevelsChanged}/>
</div>
</div>
<h3>User levels</h3>
<div className="mx_RoomSettings_user_levels mx_RoomSettings_settings">
{Object.keys(user_levels).map(function(user, i) {
return (
<div key={user}>
<label htmlFor={"mx_RoomSettings_user_"+i}>{user}</label>
<input type="text" defaultValue={user_levels[user]} size="3" id={"mx_RoomSettings_user_"+i} disabled/>
</div>
);
})}
</div>
<h3>Event levels</h3>
<div className="mx_RoomSettings_event_lvels mx_RoomSettings_settings">
{Object.keys(events_levels).map(function(event_type, i) {
return (
<div key={event_type}>
<label htmlFor={"mx_RoomSettings_event_"+i}>{event_type}</label>
<input type="text" defaultValue={events_levels[event_type]} size="3" id={"mx_RoomSettings_event_"+i} disabled/>
</div>
);
})}
</div>
<h3>Banned users</h3>
<div className="mx_RoomSettings_banned">
{banned.map(function(member, i) {
return (
<div key={i}>
{member.userId}
</div>
);
})}
</div>
<div className="mx_RoomSettings_buttons">
<div className="mx_RoomSettings_button" onClick={this.props.onSaveClick}>
Save this room
</div>
</div>
</div>
);
}
});

View File

@@ -1,65 +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,
'mx_RoomTile_selected': this.props.selected,
'mx_RoomTile_unread': this.props.unread,
'mx_RoomTile_highlight': this.props.highlight,
'mx_RoomTile_invited': this.props.room.currentState.members[myUserId].membership == 'invite'
});
var name = this.props.room.name.replace(":", ":\u200b");
var badge;
if (this.props.highlight) {
badge = <div className="mx_RoomTile_badge"/>;
}
/*
if (this.props.highlight) {
badge = <div className="mx_RoomTile_badge">!</div>;
}
else if (this.props.unread) {
badge = <div className="mx_RoomTile_badge">1</div>;
}
var nameCell;
if (badge) {
nameCell = <div className="mx_RoomTile_nameBadge"><div className="mx_RoomTile_name">{name}</div><div className="mx_RoomTile_badgeCell">{badge}</div></div>;
}
else {
nameCell = <div className="mx_RoomTile_name">{name}</div>;
}
*/
return (
<div className={classes} onClick={this.onClick}>
<div className="mx_RoomTile_avatar"><img src={ MatrixClientPeg.get().getAvatarUrlForRoom(this.props.room, 40, 40, "crop") } width="40" height="40" alt=""/>{ badge }</div>
<div className="mx_RoomTile_name">{name}</div>
</div>
);
}
});

View File

@@ -1,53 +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 SenderProfileController = require("../../../../src/controllers/molecules/SenderProfile");
// The Lato WOFF doesn't include sensible combining diacritics, so Chrome chokes on rendering them.
// Revert to Arial when this happens, which on OSX works at least.
var zalgo = /[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/;
module.exports = React.createClass({
displayName: 'SenderProfile',
mixins: [SenderProfileController],
render: function() {
var mxEvent = this.props.mxEvent;
var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
var classes = classNames({
mx_SenderProfile: true,
// taken from https://en.wikipedia.org/wiki/Combining_character
mx_SenderProfile_zalgo: zalgo.test(name),
});
var msgtype = mxEvent.getContent().msgtype;
if (msgtype && msgtype == 'm.emote') {
name = ''; // emote message must include the name so don't duplicate it
}
return (
<span className={classes}>
{name}
</span>
);
},
});

View File

@@ -1,51 +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 Modal = require('../../../../src/Modal');
var ComponentBroker = require('../../../../src/ComponentBroker');
var ErrorDialog = ComponentBroker.get('organisms/ErrorDialog');
var ServerConfigController = require("../../../../src/controllers/molecules/ServerConfig");
module.exports = React.createClass({
displayName: 'ServerConfig',
mixins: [ServerConfigController],
showHelpPopup: function() {
Modal.createDialog(ErrorDialog, {
title: 'Custom Server Options',
description: "You can use the custom server options to log into other Matrix servers by specifying a different Home server URL. This allows you to use Vector with an existing Matrix account on a different Home server. You can also set a cutom Identity server but this will affect people ability to find you if you use a server in a group other than tha main Matrix.org group.",
button: "Dismiss",
focus: true
});
},
render: function() {
return (
<div className="mx_ServerConfig">
<label className="mx_Login_label mx_ServerConfig_hslabel" htmlFor="hsurl">Home server URL</label>
<input className="mx_Login_field" id="hsurl" type="text" value={this.state.hs_url} onChange={this.hsChanged} />
<label className="mx_Login_label mx_ServerConfig_islabel" htmlFor="isurl">Identity server URL</label>
<input className="mx_Login_field" type="text" value={this.state.is_url} onChange={this.isChanged} />
<a className="mx_ServerConfig_help" href="#" onClick={this.showHelpPopup}>What does this mean?</a>
</div>
);
}
});

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');
var UnknownMessageTileController = require("../../../../src/controllers/molecules/UnknownMessageTile");
module.exports = React.createClass({
displayName: 'UnknownMessageTile',
mixins: [UnknownMessageTileController],
render: function() {
var content = this.props.mxEvent.getContent();
return (
<span className="mx_UnknownMessageTile">
{content.body}
</span>
);
},
});

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 React = require('react');
var UserSelectorController = require("../../../../src/controllers/molecules/UserSelector");
module.exports = React.createClass({
displayName: 'UserSelector',
mixins: [UserSelectorController],
onAddUserId: function() {
this.addUser(this.refs.user_id_input.getDOMNode().value);
this.refs.user_id_input.getDOMNode().value = "";
},
render: function() {
var self = this;
return (
<div>
<ul className="mx_UserSelector_UserIdList" ref="list">
{this.props.selected_users.map(function(user_id, i) {
return <li key={user_id}>{user_id} - <span onClick={function() {self.removeUser(user_id);}}>X</span></li>
})}
</ul>
<input type="text" ref="user_id_input" defaultValue="" className="mx_UserSelector_userIdInput" placeholder="ex. @bob:example.com"/>
<button onClick={this.onAddUserId} className="mx_UserSelector_AddUserId">Add User</button>
</div>
);
}
});

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');
var MatrixClientPeg = require("../../../../../src/MatrixClientPeg");
var ComponentBroker = require('../../../../../src/ComponentBroker');
var CallViewController = require(
"../../../../../src/controllers/molecules/voip/CallView"
);
var VideoView = ComponentBroker.get('molecules/voip/VideoView');
module.exports = React.createClass({
displayName: 'CallView',
mixins: [CallViewController],
getVideoView: function() {
return this.refs.video;
},
render: function(){
return (
<VideoView ref="video"/>
);
}
});

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 MatrixClientPeg = require("../../../../../src/MatrixClientPeg");
var IncomingCallBoxController = require(
"../../../../../src/controllers/molecules/voip/IncomingCallBox"
);
module.exports = React.createClass({
displayName: 'IncomingCallBox',
mixins: [IncomingCallBoxController],
getRingAudio: function() {
return this.refs.ringAudio.getDOMNode();
},
render: function() {
if (!this.state.incomingCall || !this.state.incomingCall.roomId) {
return (
<div>
<audio ref="ringAudio" loop>
<source src="media/ring.ogg" type="audio/ogg" />
<source src="media/ring.mp3" type="audio/mpeg" />
</audio>
</div>
);
}
var caller = MatrixClientPeg.get().getRoom(this.state.incomingCall.roomId).name;
return (
<div className="mx_IncomingCallBox">
<img className="mx_IncomingCallBox_chevron" src="img/chevron-left.png" width="9" height="16" />
<audio ref="ringAudio" loop>
<source src="media/ring.ogg" type="audio/ogg" />
<source src="media/ring.mp3" type="audio/mpeg" />
</audio>
<div className="mx_IncomingCallBox_title">
Incoming { this.state.incomingCall ? this.state.incomingCall.type : '' } call from { caller }
</div>
<div className="mx_IncomingCallBox_buttons">
<div className="mx_IncomingCallBox_buttons_cell">
<div className="mx_IncomingCallBox_buttons_decline" onClick={this.onRejectClick}>
Decline
</div>
</div>
<div className="mx_IncomingCallBox_buttons_cell">
<div className="mx_IncomingCallBox_buttons_accept" onClick={this.onAnswerClick}>
Accept
</div>
</div>
</div>
</div>
);
}
});

View File

@@ -1,50 +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 MCallAnswerTileController = require("../../../../../src/controllers/molecules/voip/MCallAnswerTile");
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
module.exports = React.createClass({
displayName: 'MCallAnswerTile',
mixins: [MCallAnswerTileController],
getAnswerText: function(event) {
var senderName = event.sender ? event.sender.name : "Someone";
return senderName + " answered the call.";
},
render: function() {
// XXX: for now, just cheekily borrow the css from message tile...
return (
<div className="mx_MessageTile mx_MessageTile_notice">
<div className="mx_MessageTile_avatar">
<img src={ this.props.mxEvent.sender ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.mxEvent.sender, 40, 40, "crop") : null } width="40" height="40" alt=""/>
</div>
<MessageTimestamp ts={this.props.mxEvent.getTs()} />
<span className="mx_SenderProfile"></span>
<span className="mx_MessageTile_content">
{this.getAnswerText(this.props.mxEvent)}
</span>
</div>
);
},
});

View File

@@ -1,50 +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 MCallHangupTileController = require("../../../../../src/controllers/molecules/voip/MCallHangupTile");
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
module.exports = React.createClass({
displayName: 'MCallHangupTile',
mixins: [MCallHangupTileController],
getHangupText: function(event) {
var senderName = event.sender ? event.sender.name : "Someone";
return senderName + " ended the call.";
},
render: function() {
// XXX: for now, just cheekily borrow the css from message tile...
return (
<div className="mx_MessageTile mx_MessageTile_notice">
<div className="mx_MessageTile_avatar">
<img src={ this.props.mxEvent.sender ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.mxEvent.sender, 40, 40, "crop") : null } width="40" height="40" alt=""/>
</div>
<MessageTimestamp ts={this.props.mxEvent.getTs()} />
<span className="mx_SenderProfile"></span>
<span className="mx_MessageTile_content">
{this.getHangupText(this.props.mxEvent)}
</span>
</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 MatrixClientPeg = require("../../../../../src/MatrixClientPeg");
var ComponentBroker = require('../../../../../src/ComponentBroker');
var MCallInviteTileController = require("../../../../../src/controllers/molecules/voip/MCallInviteTile");
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
module.exports = React.createClass({
displayName: 'MCallInviteTile',
mixins: [MCallInviteTileController],
getInviteText: function(event) {
var senderName = event.sender ? event.sender.name : "Someone";
// FIXME: Find a better way to determine this from the event?
var type = "voice";
if (event.getContent().offer &&
event.getContent().offer.sdp.indexOf('m=video') !== -1) {
type = "video";
}
return senderName + " placed a " + type + " call.";
},
render: function() {
// XXX: for now, just cheekily borrow the css from message tile...
return (
<div className="mx_MessageTile mx_MessageTile_notice">
<div className="mx_MessageTile_avatar">
<img src={ this.props.mxEvent.sender ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.mxEvent.sender, 40, 40, "crop") : null } width="40" height="40" alt=""/>
</div>
<MessageTimestamp ts={this.props.mxEvent.getTs()} />
<span className="mx_SenderProfile"></span>
<span className="mx_MessageTile_content">
{this.getInviteText(this.props.mxEvent)}
</span>
</div>
);
},
});

View File

@@ -1,50 +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 VideoViewController = require("../../../../../src/controllers/molecules/voip/VideoView");
var VideoFeed = ComponentBroker.get('atoms/voip/VideoFeed');
module.exports = React.createClass({
displayName: 'VideoView',
mixins: [VideoViewController],
getRemoteVideoElement: function() {
return this.refs.remote.getDOMNode();
},
getLocalVideoElement: function() {
return this.refs.local.getDOMNode();
},
render: function() {
return (
<div className="mx_VideoView">
<div className="mx_VideoView_remoteVideoFeed">
<VideoFeed ref="remote"/>
</div>
<div className="mx_VideoView_localVideoFeed">
<VideoFeed ref="local"/>
</div>
</div>
);
}
});

View File

@@ -1,170 +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 PresetValues = require('../../../../src/controllers/atoms/create_room/Presets').Presets;
var CreateRoomButton = ComponentBroker.get("atoms/create_room/CreateRoomButton");
var RoomAlias = ComponentBroker.get("atoms/create_room/RoomAlias");
var Presets = ComponentBroker.get("atoms/create_room/Presets");
var UserSelector = ComponentBroker.get("molecules/UserSelector");
var RoomHeader = ComponentBroker.get("molecules/RoomHeader");
var Loader = require("react-loader");
module.exports = React.createClass({
displayName: 'CreateRoom',
mixins: [CreateRoomController],
getPreset: function() {
return this.refs.presets.getPreset();
},
getName: function() {
return this.refs.name_textbox.getName();
},
getTopic: function() {
return this.refs.topic.getTopic();
},
getAliasLocalpart: function() {
return this.refs.alias.getAliasLocalpart();
},
getInvitedUsers: function() {
return this.refs.user_selector.getUserIds();
},
onPresetChanged: function(preset) {
switch (preset) {
case PresetValues.PrivateChat:
this.setState({
preset: preset,
is_private: true,
share_history: false,
});
break;
case PresetValues.PublicChat:
this.setState({
preset: preset,
is_private: false,
share_history: true,
});
break;
case PresetValues.Custom:
this.setState({
preset: preset,
});
break;
}
},
onPrivateChanged: function(ev) {
this.setState({
preset: PresetValues.Custom,
is_private: ev.target.checked,
});
},
onShareHistoryChanged: function(ev) {
this.setState({
preset: PresetValues.Custom,
share_history: ev.target.checked,
});
},
onTopicChange: function(ev) {
this.setState({
topic: ev.target.value,
});
},
onNameChange: function(ev) {
this.setState({
room_name: ev.target.value,
});
},
onInviteChanged: function(invited_users) {
this.setState({
invited_users: invited_users,
});
},
onAliasChanged: function(alias) {
this.setState({
alias: alias
})
},
onEncryptChanged: function(ev) {
this.setState({
encrypt: ev.target.checked,
});
},
render: function() {
var curr_phase = this.state.phase;
if (curr_phase == this.phases.CREATING) {
return (
<Loader/>
);
} 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">
<RoomHeader simpleHeader="Create room" />
<div className="mx_CreateRoom_body">
<input type="text" ref="room_name" value={this.state.room_name} onChange={this.onNameChange} placeholder="Name"/> <br />
<textarea className="mx_CreateRoom_description" ref="topic" value={this.state.topic} onChange={this.onTopicChange} placeholder="Topic"/> <br />
<RoomAlias ref="alias" alias={this.state.alias} onChange={this.onAliasChanged}/> <br />
<UserSelector ref="user_selector" selected_users={this.state.invited_users} onChange={this.onInviteChanged}/> <br />
<Presets ref="presets" onChange={this.onPresetChanged} preset={this.state.preset}/> <br />
<div>
<label><input type="checkbox" ref="is_private" checked={this.state.is_private} onChange={this.onPrivateChanged}/> Make this room private</label>
</div>
<div>
<label><input type="checkbox" ref="share_history" checked={this.state.share_history} onChange={this.onShareHistoryChanged}/> Share message history with new users</label>
</div>
<div className="mx_CreateRoom_encrypt">
<label><input type="checkbox" ref="encrypt" checked={this.state.encrypt} onChange={this.onEncryptChanged}/> Encrypt room</label>
</div>
<div>
<CreateRoomButton onCreateRoom={this.onCreateRoom} /> <br />
</div>
{error_box}
</div>
</div>
);
}
}
});

View File

@@ -1,54 +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';
/*
* Usage:
* Modal.createDialog(ErrorDialog, {
* title: "some text", (default: "Error")
* description: "some more text",
* button: "Button Text",
* onClose: someFunction,
* focus: true|false (default: true)
* });
*/
var React = require('react');
var ErrorDialogController = require("../../../../src/controllers/organisms/ErrorDialog");
module.exports = React.createClass({
displayName: 'ErrorDialog',
mixins: [ErrorDialogController],
render: function() {
return (
<div className="mx_ErrorDialog">
<div className="mx_ErrorDialogTitle">
{this.props.title}
</div>
<div className="mx_Dialog_content">
{this.props.description}
</div>
<div className="mx_Dialog_buttons">
<button onClick={this.props.onFinished} autoFocus={this.props.focus}>
{this.props.button}
</button>
</div>
</div>
);
}
});

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');
var ComponentBroker = require('../../../../src/ComponentBroker');
var RoomList = ComponentBroker.get('organisms/RoomList');
var BottomLeftMenu = ComponentBroker.get('molecules/BottomLeftMenu');
var IncomingCallBox = ComponentBroker.get('molecules/voip/IncomingCallBox');
var RoomCreate = ComponentBroker.get('molecules/RoomCreate');
module.exports = React.createClass({
displayName: 'LeftPanel',
render: function() {
return (
<div className="mx_LeftPanel">
<img className="mx_LeftPanel_hideButton" src="img/hide.png" width="32" height="32" alt="<"/>
<IncomingCallBox />
<RoomList selectedRoom={this.props.selectedRoom} />
<BottomLeftMenu />
</div>
);
}
});

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 React = require('react');
var classNames = require('classnames');
var MemberListController = require("../../../../src/controllers/organisms/MemberList");
var ComponentBroker = require('../../../../src/ComponentBroker');
var MemberTile = ComponentBroker.get("molecules/MemberTile");
var EditableText = ComponentBroker.get("atoms/EditableText");
module.exports = React.createClass({
displayName: 'MemberList',
mixins: [MemberListController],
getInitialState: function() {
return { editing: false };
},
// FIXME: combine this more nicely with the MemberInfo positioning stuff...
onMemberListScroll: function(ev) {
if (this.refs.memberListScroll) {
var memberListScroll = this.refs.memberListScroll.getDOMNode();
// offset the current MemberInfo bubble
var memberInfo = document.getElementsByClassName("mx_MemberInfo")[0];
if (memberInfo) {
memberInfo.style.top = (memberInfo.parentElement.offsetTop - memberListScroll.scrollTop) + "px";
}
}
},
makeMemberTiles: function() {
var self = this;
return Object.keys(self.state.memberDict).map(function(userId) {
var m = self.state.memberDict[userId];
return (
<MemberTile key={userId} member={m} ref={userId} />
);
});
},
onPopulateInvite: function(inputText, shouldSubmit) {
// reset back to placeholder
this.refs.invite.setValue("Invite", false, true);
this.setState({ editing: false });
if (!shouldSubmit) {
return; // enter key wasn't pressed
}
this.onInvite(inputText);
},
onClickInvite: function(ev) {
this.setState({ editing: true });
this.refs.invite.onClickDiv();
ev.stopPropagation();
ev.preventDefault();
},
inviteTile: function() {
// if (this.state.inviting) {
// return (
// <div></div>
// );
// }
var classes = classNames({
mx_MemberTile: true,
mx_MemberTile_inviteEditing: this.state.editing,
});
return (
<div className={ classes } onClick={ this.onClickInvite } >
<div className="mx_MemberTile_avatar"><img src="img/create-big.png" width="40" height="40" alt=""/></div>
<div className="mx_MemberTile_name">
<EditableText ref="invite" label="Invite" placeHolder="@user:domain.com" initialValue="" onValueChanged={this.onPopulateInvite}/>
</div>
</div>
);
},
render: function() {
return (
<div className="mx_MemberList">
<div className="mx_MemberList_chevron">
<img src="img/chevron.png" width="24" height="13"/>
</div>
<div className="mx_MemberList_border" ref="memberListScroll" onScroll={ this.onMemberListScroll }>
<h2>Members</h2>
<div className="mx_MemberList_wrapper">
{this.makeMemberTiles()}
{this.inviteTile()}
</div>
</div>
</div>
);
}
});

View File

@@ -1,94 +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 NotifierController = require("../../../../src/controllers/organisms/Notifier");
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
var TextForEvent = require("../../../../src/TextForEvent");
var extend = require("../../../../src/extend");
var dis = require("../../../../src/dispatcher");
var NotifierView = {
notificationMessageForEvent: function(ev) {
return TextForEvent.textForEvent(ev);
},
displayNotification: function(ev, room) {
if (!global.Notification || global.Notification.permission != 'granted') {
return;
}
if (global.document.hasFocus()) {
return;
}
var msg = this.notificationMessageForEvent(ev);
if (!msg) return;
var title;
if (!ev.sender || room.name == ev.sender.name) {
title = room.name;
// notificationMessageForEvent includes sender,
// but we already have the sender here
if (ev.getContent().body) msg = ev.getContent().body;
} else if (ev.getType() == 'm.room.member') {
// context is all in the message here, we don't need
// to display sender info
title = room.name;
} else if (ev.sender) {
title = ev.sender.name + " (" + room.name + ")";
// notificationMessageForEvent includes sender,
// but we've just out sender in the title
if (ev.getContent().body) msg = ev.getContent().body;
}
var notification = new global.Notification(
title,
{
"body": msg,
"icon": MatrixClientPeg.get().getAvatarUrlForMember(ev.sender)
}
);
notification.onclick = function() {
dis.dispatch({
action: 'view_room',
room_id: room.roomId
});
global.focus();
};
/*var audioClip;
if (audioNotification) {
audioClip = playAudio(audioNotification);
}*/
global.setTimeout(function() {
notification.close();
}, 5 * 1000);
}
};
var NotifierClass = function() {};
extend(NotifierClass.prototype, NotifierController);
extend(NotifierClass.prototype, NotifierView);
module.exports = new NotifierClass();

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';
/*
* Usage:
* Modal.createDialog(ErrorDialog, {
* title: "some text", (default: "Error")
* description: "some more text",
* button: "Button Text",
* onClose: someFunction,
* focus: true|false (default: true)
* });
*/
var React = require('react');
var QuestionDialogController = require("../../../../src/controllers/organisms/QuestionDialog");
module.exports = React.createClass({
displayName: 'QuestionDialog',
mixins: [QuestionDialogController],
onOk: function() {
this.props.onFinished(true);
},
onCancel: function() {
this.props.onFinished(false);
},
render: function() {
return (
<div className="mx_QuestionDialog">
<div className="mx_QuestionDialogTitle">
{this.props.title}
</div>
<div className="mx_Dialog_content">
{this.props.description}
</div>
<div className="mx_Dialog_buttons">
<button onClick={this.onOk} autoFocus={this.props.focus}>
{this.props.button}
</button>
<button onClick={this.onCancel}>
Cancel
</button>
</div>
</div>
);
}
});

View File

@@ -1,78 +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 MemberList = ComponentBroker.get('organisms/MemberList');
module.exports = React.createClass({
displayName: 'RightPanel',
Phase : {
Blank: 'Blank',
None: 'None',
MemberList: 'MemberList',
FileList: 'FileList',
},
getInitialState: function() {
return {
phase : this.Phase.MemberList
}
},
onMemberListButtonClick: function() {
if (this.state.phase == this.Phase.None) {
this.setState({ phase: this.Phase.MemberList });
}
else {
this.setState({ phase: this.Phase.None });
}
},
render: function() {
var buttonGroup;
var panel;
if (this.props.roomId) {
buttonGroup =
<div className="mx_RightPanel_headerButtonGroup">
<div className="mx_RightPanel_headerButton mx_RightPanel_filebutton">
<img src="img/file.png" width="32" height="32" title="Files" alt="Files"/>
</div>
<div className="mx_RightPanel_headerButton" onClick={ this.onMemberListButtonClick }>
<img src="img/members.png" width="32" height="32" title="Members" alt="Members"/>
</div>
</div>;
if (this.state.phase == this.Phase.MemberList) {
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
}
}
return (
<div className="mx_RightPanel">
<div className="mx_RightPanel_header">
{ buttonGroup }
</div>
{ panel }
</div>
);
}
});

View File

@@ -1,147 +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 Modal = require("../../../../src/Modal");
var ComponentBroker = require('../../../../src/ComponentBroker');
var ErrorDialog = ComponentBroker.get("organisms/ErrorDialog");
var RoomHeader = ComponentBroker.get('molecules/RoomHeader');
var dis = require("../../../../src/dispatcher");
var Loader = require("react-loader");
module.exports = React.createClass({
displayName: 'RoomDirectory',
getInitialState: function() {
return {
publicRooms: [],
roomAlias: '',
loading: true,
}
},
componentDidMount: function() {
var self = this;
MatrixClientPeg.get().publicRooms(function (err, data) {
if (err) {
self.setState({ loading: false });
console.error("Failed to get publicRooms: %s", JSON.stringify(err));
Modal.createDialog(ErrorDialog, {
title: "Failed to get public room list",
description: err.message
});
}
else {
self.setState({
publicRooms: data.chunk,
loading: false,
});
self.forceUpdate();
}
});
},
joinRoom: function(roomId) {
var self = this;
self.setState({ loading: true });
// XXX: check that JS SDK suppresses duplicate attempts to join the same room
MatrixClientPeg.get().joinRoom(roomId).done(function() {
dis.dispatch({
action: 'view_room',
room_id: roomId
});
}, function(err) {
console.error("Failed to join room: %s", JSON.stringify(err));
Modal.createDialog(ErrorDialog, {
title: "Failed to join room",
description: err.message
});
});
},
getRows: function(filter) {
if (!this.state.publicRooms) return [];
var rooms = this.state.publicRooms.filter(function(a) {
// FIXME: if incrementally typing, keep narrowing down the search set
// incrementally rather than starting over each time.
return (a.aliases[0].search(filter) >= 0 && a.num_joined_members > 0);
}).sort(function(a,b) {
return a.num_joined_members - b.num_joined_members;
});
var rows = [];
var self = this;
for (var i = 0; i < rooms.length; i++) {
var name = rooms[i].name || rooms[i].aliases[0];
// <img src={ MatrixClientPeg.get().getAvatarUrlForRoom(rooms[i].room_id, 40, 40, "crop") } width="40" height="40" alt=""/>
rows.unshift(
<tbody key={ rooms[i].room_id }>
<tr onClick={self.joinRoom.bind(null, rooms[i].room_id)}>
<td className="mx_RoomDirectory_name">{ name }</td>
<td>{ rooms[i].aliases[0] }</td>
<td>{ rooms[i].num_joined_members }</td>
</tr>
<tr>
<td className="mx_RoomDirectory_topic" colSpan="3">{ rooms[i].topic }</td>
</tr>
</tbody>
);
}
return rows;
},
onKeyUp: function(ev) {
this.forceUpdate();
this.setState({ roomAlias : this.refs.roomAlias.getDOMNode().value })
if (ev.key == "Enter") {
this.joinRoom(this.refs.roomAlias.getDOMNode().value);
}
if (ev.key == "Down") {
}
},
render: function() {
if (this.state.loading) {
return (
<div className="mx_RoomDirectory">
<Loader />
</div>
);
}
return (
<div className="mx_RoomDirectory">
<RoomHeader simpleHeader="Public Rooms" />
<div className="mx_RoomDirectory_list">
<input ref="roomAlias" placeholder="Join a room (e.g. #foo:domain.com)" className="mx_RoomDirectory_input" size="64" onKeyUp={ this.onKeyUp }/>
<div className="mx_RoomDirectory_tableWrapper">
<table className="mx_RoomDirectory_table">
<tr><th width="45%">Room</th><th width="45%">Alias</th><th width="10%">Members</th></tr>
{ this.getRows(this.state.roomAlias) }
</table>
</div>
</div>
</div>
);
}
});

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.
*/
'use strict';
var React = require('react');
var ComponentBroker = require('../../../../src/ComponentBroker');
var RoomDropTarget = ComponentBroker.get('molecules/RoomDropTarget');
var RoomListController = require("../../../../src/controllers/organisms/RoomList");
module.exports = React.createClass({
displayName: 'RoomList',
mixins: [RoomListController],
render: function() {
return (
<div className="mx_RoomList">
<h2 className="mx_RoomList_favourites_label">Favourites</h2>
<RoomDropTarget text="Drop here to favourite"/>
<h2 className="mx_RoomList_recents_label">Recents</h2>
<div className="mx_RoomList_recents">
{this.makeRoomTiles()}
</div>
<h2 className="mx_RoomList_archive_label">Archive</h2>
<RoomDropTarget text="Drop here to archive"/>
</div>
);
}
});

View File

@@ -1,190 +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 filesize = require('filesize');
var q = require('q');
var MessageTile = ComponentBroker.get('molecules/MessageTile');
var RoomHeader = ComponentBroker.get('molecules/RoomHeader');
var MessageComposer = ComponentBroker.get('molecules/MessageComposer');
var CallView = ComponentBroker.get("molecules/voip/CallView");
var RoomSettings = ComponentBroker.get("molecules/RoomSettings");
var RoomViewController = require("../../../../src/controllers/organisms/RoomView");
var Loader = require("react-loader");
module.exports = React.createClass({
displayName: 'RoomView',
mixins: [RoomViewController],
onSettingsClick: function() {
this.setState({editingRoomSettings: true});
},
onSaveClick: function() {
this.setState({
editingRoomSettings: false,
uploadingRoomSettings: true,
});
var new_name = this.refs.header.getRoomName();
var new_topic = this.refs.room_settings.getTopic();
var new_join_rule = this.refs.room_settings.getJoinRules();
var new_history_visibility = this.refs.room_settings.getHistoryVisibility();
var new_power_levels = this.refs.room_settings.getPowerLevels();
this.uploadNewState(
new_name,
new_topic,
new_join_rule,
new_history_visibility,
new_power_levels
);
},
getUnreadMessagesString: function() {
if (!this.state.numUnreadMessages) {
return "";
}
return this.state.numUnreadMessages + " unread messages";
},
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">
<RoomHeader ref="header" room={this.state.room} simpleHeader="Room invite"/>
<div className="mx_RoomView_invitePrompt">
<div>{inviteEvent.user_id} has invited you to a room</div>
<br/>
<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
});
var statusBar = (
<div />
);
if (this.state.upload) {
var innerProgressStyle = {
width: ((this.state.upload.uploadedBytes / this.state.upload.totalBytes) * 100) + '%'
};
statusBar = (
<div className="mx_RoomView_uploadBar">
<span className="mx_RoomView_uploadFilename">Uploading {this.state.upload.fileName}</span>
<span className="mx_RoomView_uploadBytes">
{filesize(this.state.upload.uploadedBytes)} / {filesize(this.state.upload.totalBytes)}
</span>
<div className="mx_RoomView_uploadProgressOuter">
<div className="mx_RoomView_uploadProgressInner" style={innerProgressStyle}></div>
</div>
</div>
);
} else {
var typingString = this.getWhoIsTypingString();
var unreadMsgs = this.getUnreadMessagesString();
// unread count trumps who is typing since the unread count is only
// set when you've scrolled up
if (unreadMsgs) {
statusBar = (
<div className="mx_RoomView_typingBar">
<img src="img/typing.png" width="40" height="40" alt=""/>
{unreadMsgs}
</div>
);
}
else if (typingString) {
statusBar = (
<div className="mx_RoomView_typingBar">
<img src="img/typing.png" width="40" height="40" alt=""/>
{typingString}
</div>
);
}
}
var roomEdit = null;
if (this.state.editingRoomSettings) {
roomEdit = <RoomSettings ref="room_settings" onSaveClick={this.onSaveClick} room={this.state.room} />;
}
if (this.state.uploadingRoomSettings) {
roomEdit = <Loader/>;
}
return (
<div className="mx_RoomView">
<RoomHeader ref="header" room={this.state.room} editing={this.state.editingRoomSettings}
onSettingsClick={this.onSettingsClick}/>
<div className="mx_RoomView_auxPanel">
<CallView room={this.state.room}/>
{ roomEdit }
</div>
<div ref="messageWrapper" className="mx_RoomView_messagePanel" onScroll={ this.onMessageListScroll }>
<div className="mx_RoomView_messageListWrapper">
<div className="mx_RoomView_MessageList" aria-live="polite">
<div className={scrollheader_classes}>
</div>
{this.getEventTiles()}
</div>
</div>
</div>
<div className="mx_RoomView_statusArea">
<div className="mx_RoomView_statusAreaBox">
{statusBar}
</div>
</div>
<MessageComposer room={this.state.room} uploadFile={this.uploadFile} />
</div>
);
}
},
});

View File

@@ -1,113 +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 MatrixClientPeg = require("../../../../src/MatrixClientPeg");
var UserSettingsController = require("../../../../src/controllers/organisms/UserSettings");
var EditableText = ComponentBroker.get('atoms/EditableText');
var EnableNotificationsButton = ComponentBroker.get('atoms/EnableNotificationsButton');
var ChangeAvatar = ComponentBroker.get('molecules/ChangeAvatar');
var ChangePassword = ComponentBroker.get('molecules/ChangePassword');
var LogoutPrompt = ComponentBroker.get('organisms/LogoutPrompt');
var Loader = require("react-loader");
var Modal = require("../../../../src/Modal");
module.exports = React.createClass({
displayName: 'UserSettings',
mixins: [UserSettingsController],
editAvatar: function() {
var url = MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl);
Modal.createDialog(ChangeAvatar, {initialAvatarUrl: url});
},
addEmail: function() {
},
editDisplayName: function() {
this.refs.displayname.edit();
},
changePassword: function() {
Modal.createDialog(ChangePassword);
},
onLogoutClicked: function(ev) {
this.logoutModal = Modal.createDialog(LogoutPrompt, {onCancel: this.onLogoutPromptCancel});
},
onLogoutPromptCancel: function() {
this.logoutModal.closeDialog();
},
render: function() {
switch (this.state.phase) {
case this.Phases.Loading:
return <Loader />
case this.Phases.Display:
return (
<div className="mx_UserSettings">
<div className="mx_UserSettings_User">
<h1>User Settings</h1>
<hr/>
<div className="mx_UserSettings_User_Inner">
<div className="mx_UserSettings_Avatar">
<div className="mx_UserSettings_Avatar_Text">Profile Photo</div>
<div className="mx_UserSettings_Avatar_Edit" onClick={this.editAvatar}>Edit</div>
</div>
<div className="mx_UserSettings_DisplayName">
<EditableText ref="displayname" initialValue={this.state.displayName} label="Click to set display name." onValueChanged={this.changeDisplayname}/>
<div className="mx_UserSettings_DisplayName_Edit" onClick={this.editDisplayName}>Edit</div>
</div>
<div className="mx_UserSettings_3pids">
{this.state.threepids.map(function(val) {
return <div>{val.address}</div>;
})}
</div>
<div className="mx_UserSettings_Add3pid" onClick={this.addEmail}>Add email</div>
</div>
</div>
<div className="mx_UserSettings_Global">
<h1>Global Settings</h1>
<hr/>
<div className="mx_UserSettings_Global_Inner">
<div className="mx_UserSettings_ChangePassword" onClick={this.changePassword}>
Change Password
</div>
<div className="mx_UserSettings_ClientVersion">
Version {this.state.clientVersion}
</div>
<div className="mx_UserSettings_EnableNotifications">
<EnableNotificationsButton />
</div>
<div className="mx_UserSettings_Logout">
<button onClick={this.onLogoutClicked}>Sign Out</button>
</div>
</div>
</div>
</div>
);
}
}
});

View File

@@ -1,121 +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 LeftPanel = ComponentBroker.get('organisms/LeftPanel');
var RoomView = ComponentBroker.get('organisms/RoomView');
var RightPanel = ComponentBroker.get('organisms/RightPanel');
var Login = ComponentBroker.get('templates/Login');
var UserSettings = ComponentBroker.get('organisms/UserSettings');
var Register = ComponentBroker.get('templates/Register');
var CreateRoom = ComponentBroker.get('organisms/CreateRoom');
var RoomDirectory = ComponentBroker.get('organisms/RoomDirectory');
var MatrixToolbar = ComponentBroker.get('molecules/MatrixToolbar');
var Notifier = ComponentBroker.get('organisms/Notifier');
var MatrixChatController = require("../../../../src/controllers/pages/MatrixChat");
// should be atomised
var Loader = require("react-loader");
var classNames = require("classnames");
var dis = require("../../../../src/dispatcher");
module.exports = React.createClass({
displayName: 'MatrixChat',
mixins: [MatrixChatController],
onRoomCreated: function(room_id) {
dis.dispatch({
action: "view_room",
room_id: room_id,
});
},
render: function() {
if (this.state.logged_in && this.state.ready) {
var page_element;
var right_panel = "";
switch (this.state.page_type) {
case this.PageTypes.RoomView:
page_element = <RoomView roomId={this.state.currentRoom} key={this.state.currentRoom} />
right_panel = <RightPanel roomId={this.state.currentRoom} />
break;
case this.PageTypes.UserSettings:
page_element = <UserSettings />
right_panel = <RightPanel/>
break;
case this.PageTypes.CreateRoom:
page_element = <CreateRoom onRoomCreated={this.onRoomCreated}/>
right_panel = <RightPanel/>
break;
case this.PageTypes.RoomDirectory:
page_element = <RoomDirectory />
right_panel = <RightPanel/>
break;
}
if (Notifier.supportsDesktopNotifications() && !Notifier.isEnabled()) {
return (
<div className="mx_MatrixChat_wrapper">
<MatrixToolbar />
<div className="mx_MatrixChat mx_MatrixChat_toolbarShowing">
<LeftPanel selectedRoom={this.state.currentRoom} />
<div className="mx_MatrixChat_middlePanel">
{page_element}
</div>
{right_panel}
</div>
</div>
);
}
else {
return (
<div className="mx_MatrixChat">
<LeftPanel selectedRoom={this.state.currentRoom} />
<div className="mx_MatrixChat_middlePanel">
{page_element}
</div>
{right_panel}
</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,174 +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 MatrixClientPeg = require("../../../../src/MatrixClientPeg");
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({
DEFAULT_HS_URL: 'https://matrix.org',
DEFAULT_IS_URL: 'https://matrix.org',
displayName: 'Login',
mixins: [LoginController],
getInitialState: function() {
return {
serverConfigVisible: false
};
},
componentWillMount: function() {
this.onHSChosen();
this.customHsUrl = this.DEFAULT_HS_URL;
this.customIsUrl = this.DEFAULT_IS_URL;
},
getHsUrl: function() {
if (this.state.serverConfigVisible) {
return this.customHsUrl;
} else {
return this.DEFAULT_HS_URL;
}
},
getIsUrl: function() {
if (this.state.serverConfigVisible) {
return this.customIsUrl;
} else {
return this.DEFAULT_IS_URL;
}
},
onServerConfigVisibleChange: function(ev) {
this.setState({
serverConfigVisible: ev.target.checked
}, this.onHsUrlChanged);
},
/**
* 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
};
},
onHsUrlChanged: function() {
this.customHsUrl = this.refs.serverConfig.getHsUrl();
this.customIsUrl = this.refs.serverConfig.getIsUrl();
MatrixClientPeg.replaceUsingUrls(
this.getHsUrl(),
this.getIsUrl()
);
this.setState({
hs_url: this.getHsUrl(),
is_url: this.getIsUrl()
});
// XXX: HSes do not have to offer password auth, so we
// need to update and maybe show a different component
// when a new HS is entered.
/*if (this.updateHsTimeout) {
clearTimeout(this.updateHsTimeout);
}
var self = this;
this.updateHsTimeout = setTimeout(function() {
self.onHSChosen();
}, 500);*/
},
componentForStep: function(step) {
switch (step) {
case 'choose_hs':
var serverConfigStyle = {};
serverConfigStyle.display = this.state.serverConfigVisible ? 'block' : 'none';
return (
<div>
<input className="mx_Login_checkbox" id="advanced" type="checkbox" value={this.state.serverConfigVisible} onChange={this.onServerConfigVisibleChange} />
<label className="mx_Login_label" htmlFor="advanced">Use custom server options (advanced)</label>
<div style={serverConfigStyle}>
<ServerConfig ref="serverConfig"
defaultHsUrl={this.customHsUrl} defaultIsUrl={this.customIsUrl}
onHsUrlChanged={this.onHsUrlChanged}
/>
</div>
</div>
);
// XXX: clearly these should be separate organisms
case 'stage_m.login.password':
return (
<div>
<form onSubmit={this.onUserPassEntered}>
<input className="mx_Login_field" ref="user" type="text" value={this.state.username} onChange={this.onUsernameChanged} placeholder="Email or user name" /><br />
<input className="mx_Login_field" ref="pass" type="password" value={this.state.password} onChange={this.onPasswordChanged} placeholder="Password" /><br />
{this.componentForStep('choose_hs')}
<input className="mx_Login_submit" type="submit" value="Log in" />
</form>
</div>
);
}
},
onUsernameChanged: function(ev) {
this.setState({username: ev.target.value});
},
onPasswordChanged: function(ev) {
this.setState({password: ev.target.value});
},
loginContent: function() {
if (this.state.busy) {
return (
<Loader />
);
} else {
return (
<div>
<h2>Sign in</h2>
{this.componentForStep(this.state.step)}
<div className="mx_Login_error">{this.state.errorText}</div>
<a className="mx_Login_create" onClick={this.showRegister} href="#">Create a new account</a>
</div>
);
}
},
render: function() {
return (
<div className="mx_Login">
<div className="mx_Login_box">
<div className="mx_Login_logo">
<img src="img/logo.png" width="249" height="78" alt="vector"/>
</div>
{this.loginContent()}
</div>
</div>
);
}
});

View File

@@ -1,192 +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({
DEFAULT_HS_URL: 'https://matrix.org',
DEFAULT_IS_URL: 'https://matrix.org',
displayName: 'Register',
mixins: [RegisterController],
getInitialState: function() {
return {
serverConfigVisible: false
};
},
componentWillMount: function() {
this.customHsUrl = this.DEFAULT_HS_URL;
this.customIsUrl = this.DEFAULT_IS_URL;
},
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() {
if (this.state.serverConfigVisible) {
return this.customHsUrl;
} else {
return this.DEFAULT_HS_URL;
}
},
getIsUrl: function() {
if (this.state.serverConfigVisible) {
return this.customIsUrl;
} else {
return this.DEFAULT_IS_URL;
}
},
onServerConfigVisibleChange: function(ev) {
this.setState({
serverConfigVisible: ev.target.checked
});
},
getUserIdSuffix: function() {
return '';
var actualHsUrl = document.createElement('a');
actualHsUrl.href = this.getHsUrl();
var defaultHsUrl = document.createElement('a');
defaultHsUrl.href = this.DEFAULT_HS_URL;
if (actualHsUrl.host == defaultHsUrl.host) {
return ':matrix.org';
}
return '';
},
onServerUrlChanged: function(newUrl) {
this.customHsUrl = this.refs.serverConfig.getHsUrl();
this.customIsUrl = this.refs.serverConfig.getIsUrl();
this.forceUpdate();
},
componentForStep: function(step) {
switch (step) {
case 'initial':
var serverConfigStyle = {};
serverConfigStyle.display = this.state.serverConfigVisible ? 'block' : 'none';
return (
<div>
<form onSubmit={this.onInitialStageSubmit}>
<input className="mx_Login_field" type="text" ref="email" placeholder="Email address" defaultValue={this.savedParams.email} /><br />
<input className="mx_Login_field" type="text" ref="username" placeholder="User name" defaultValue={this.savedParams.username} />{this.getUserIdSuffix()}<br />
<input className="mx_Login_field" type="password" ref="password" placeholder="Password" defaultValue={this.savedParams.password} /><br />
<input className="mx_Login_field" type="password" ref="confirmPassword" placeholder="Confirm password" defaultValue={this.savedParams.confirmPassword} /><br />
<input className="mx_Login_checkbox" id="advanced" type="checkbox" value={this.state.serverConfigVisible} onChange={this.onServerConfigVisibleChange} />
<label htmlFor="advanced">Use custom server options (advanced)</label>
<div style={serverConfigStyle}>
<ServerConfig ref="serverConfig"
defaultHsUrl={this.customHsUrl} defaultIsUrl={this.customIsUrl}
onHsUrlChanged={this.onServerUrlChanged} onIsUrlChanged={this.onServerUrlChanged} />
</div>
<br />
<input className="mx_Login_submit" type="submit" value="Register" />
</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 are not a robot
<div id="mx_recaptcha"></div>
</div>
);
}
},
registerContent: function() {
if (this.state.busy) {
return (
<Loader />
);
} else {
return (
<div>
<h2>Create an account</h2>
{this.componentForStep(this.state.step)}
<div className="mx_Login_error">{this.state.errorText}</div>
<a className="mx_Login_create" onClick={this.showLogin} href="#">I already have an 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_Login">
<div className="mx_Login_box">
<div className="mx_Login_logo">
<img src="img/logo.png" width="249" height="78" alt="vector"/>
</div>
{this.registerContent()}
</div>
</div>
);
}
});

View File

@@ -1,276 +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';
/*
* Manages a list of all the currently active calls.
*
* This handler dispatches when voip calls are added/updated/removed from this list:
* {
* action: 'call_state'
* room_id: <room ID of the call>
* }
*
* To know the state of the call, this handler exposes a getter to
* obtain the call for a room:
* var call = CallHandler.getCall(roomId)
* var state = call.call_state; // ringing|ringback|connected|ended|busy|stop_ringback|stop_ringing
*
* This handler listens for and handles the following actions:
* {
* action: 'place_call',
* type: 'voice|video',
* room_id: <room that the place call button was pressed in>
* }
*
* {
* action: 'incoming_call'
* call: MatrixCall
* }
*
* {
* action: 'hangup'
* room_id: <room that the hangup button was pressed in>
* }
*
* {
* action: 'answer'
* room_id: <room that the answer button was pressed in>
* }
*/
var MatrixClientPeg = require("./MatrixClientPeg");
var Modal = require("./Modal");
var ComponentBroker = require('./ComponentBroker');
var ErrorDialog = ComponentBroker.get("organisms/ErrorDialog");
var Matrix = require("matrix-js-sdk");
var dis = require("./dispatcher");
var q = require("q");
var calls = {
//room_id: MatrixCall
};
function play(audioId) {
// TODO: Attach an invisible element for this instead
// which listens?
var audio = document.getElementById(audioId);
if (audio) {
audio.load();
audio.play();
}
}
function pause(audioId) {
// TODO: Attach an invisible element for this instead
// which listens?
var audio = document.getElementById(audioId);
if (audio) {
audio.pause();
}
}
function _setCallListeners(call) {
call.on("error", function(err) {
console.error("Call error: %s", err);
console.error(err.stack);
call.hangup();
_setCallState(undefined, call.roomId, "ended");
});
call.on("hangup", function() {
_setCallState(undefined, call.roomId, "ended");
});
// map web rtc states to dummy UI state
// ringing|ringback|connected|ended|busy|stop_ringback|stop_ringing
call.on("state", function(newState, oldState) {
if (newState === "ringing") {
_setCallState(call, call.roomId, "ringing");
pause("ringbackAudio");
}
else if (newState === "invite_sent") {
_setCallState(call, call.roomId, "ringback");
play("ringbackAudio");
}
else if (newState === "ended" && oldState === "connected") {
_setCallState(call, call.roomId, "ended");
pause("ringbackAudio");
play("callendAudio");
}
else if (newState === "ended" && oldState === "invite_sent" &&
(call.hangupParty === "remote" ||
(call.hangupParty === "local" && call.hangupReason === "invite_timeout")
)) {
_setCallState(call, call.roomId, "busy");
pause("ringbackAudio");
play("busyAudio");
Modal.createDialog(ErrorDialog, {
title: "Call Timeout",
description: "The remote side failed to pick up."
});
}
else if (oldState === "invite_sent") {
_setCallState(call, call.roomId, "stop_ringback");
pause("ringbackAudio");
}
else if (oldState === "ringing") {
_setCallState(call, call.roomId, "stop_ringing");
pause("ringbackAudio");
}
else if (newState === "connected") {
_setCallState(call, call.roomId, "connected");
pause("ringbackAudio");
}
});
}
function _setCallState(call, roomId, status) {
console.log(
"Call state in %s changed to %s (%s)", roomId, status, (call ? call.state : "-")
);
calls[roomId] = call;
if (call) {
call.call_state = status;
}
dis.dispatch({
action: 'call_state',
room_id: roomId
});
}
function findOrMakeVertoRoom() {
var VERTO_USERID = '@verto_1234:matrix.org';
var defer = q.defer();
var allRooms = MatrixClientPeg.get().getRooms();
for (var i = 0; i < Object.keys(allRooms).length; ++i) {
var r = allRooms[i];
var membs = r.getJoinedMembers();
if (membs.length == 2 && (membs[0].userId == VERTO_USERID || membs[0].userId == VERTO_USERID)) {
defer.resolve(r);
return defer.promise;
}
}
MatrixClientPeg.get().createRoom({
invite: [ VERTO_USERID ]
}).done(function(result) {
defer.resolve(MatrixClientPeg.get().getRoom(result.room_id));
});
return defer.promise;
}
dis.register(function(payload) {
switch (payload.action) {
case 'place_call':
if (calls[payload.room_id]) {
return; // don't allow >1 call to be placed.
}
var room = MatrixClientPeg.get().getRoom(payload.room_id);
if (!room) {
console.error("Room %s does not exist.", payload.room_id);
return;
}
var members = room.getJoinedMembers();
if (members.length > 2) {
var vertoRoom = findOrMakeVertoRoom().done(function(r) {
console.log("Place %s conference call in %s", payload.type, payload.room_id);
var call = Matrix.createNewMatrixCall(
MatrixClientPeg.get(), r.roomId
);
_setCallListeners(call);
_setCallState(call, call.roomId, "ringback");
if (payload.type === 'voice') {
call.placeVoiceCall();
}
else if (payload.type === 'video') {
call.placeVideoCall(
payload.remote_element,
payload.local_element
);
}
else {
console.error("Unknown call type: %s", payload.type);
}
});
return;
} else if (members.length !== 2) {
var text = members.length === 1 ? "yourself." : "more than 2 people.";
Modal.createDialog(ErrorDialog, {
description: "You cannot place a call with " + text
});
console.error(
"Fail: There are %s joined members in this room, not 2.",
room.getJoinedMembers().length
);
return;
}
console.log("Place %s call in %s", payload.type, payload.room_id);
var call = Matrix.createNewMatrixCall(
MatrixClientPeg.get(), payload.room_id
);
_setCallListeners(call);
_setCallState(call, call.roomId, "ringback");
if (payload.type === 'voice') {
call.placeVoiceCall();
}
else if (payload.type === 'video') {
call.placeVideoCall(
payload.remote_element,
payload.local_element
);
}
else {
console.error("Unknown call type: %s", payload.type);
}
break;
case 'incoming_call':
if (calls[payload.call.roomId]) {
payload.call.hangup("busy");
return; // don't allow >1 call to be received, hangup newer one.
}
var call = payload.call;
_setCallListeners(call);
_setCallState(call, call.roomId, "ringing");
break;
case 'hangup':
if (!calls[payload.room_id]) {
return; // no call to hangup
}
calls[payload.room_id].hangup();
_setCallState(null, payload.room_id, "ended");
break;
case 'answer':
if (!calls[payload.room_id]) {
return; // no call to answer
}
calls[payload.room_id].answer();
_setCallState(calls[payload.room_id], payload.room_id, "connected");
dis.dispatch({
action: "view_room",
room_id: payload.room_id
});
break;
}
});
module.exports = {
getCall: function(roomId) {
return calls[roomId] || null;
}
};

View File

@@ -1,117 +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/RoomAlias');
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');
require('../skins/base/views/organisms/UserSettings');
require('../skins/base/views/molecules/ChangeAvatar');
require('../skins/base/views/molecules/ChangePassword');
require('../skins/base/views/molecules/RoomSettings');
// new for vector
require('../skins/base/views/organisms/LeftPanel');
require('../skins/base/views/organisms/RightPanel');
require('../skins/base/views/organisms/LogoutPrompt');
require('../skins/base/views/organisms/RoomDirectory');
require('../skins/base/views/molecules/RoomCreate');
require('../skins/base/views/molecules/RoomDropTarget');
require('../skins/base/views/molecules/BottomLeftMenu');
require('../skins/base/views/molecules/DateSeparator');
require('../skins/base/views/atoms/voip/VideoFeed');
require('../skins/base/views/atoms/ImageView');
require('../skins/base/views/molecules/voip/VideoView');
require('../skins/base/views/molecules/voip/CallView');
require('../skins/base/views/molecules/voip/IncomingCallBox');
require('../skins/base/views/molecules/voip/MCallInviteTile');
require('../skins/base/views/molecules/voip/MCallAnswerTile');
require('../skins/base/views/molecules/voip/MCallHangupTile');
require('../skins/base/views/molecules/EventAsTextTile');
require('../skins/base/views/molecules/MemberInfo');
require('../skins/base/views/organisms/ErrorDialog');
require('../skins/base/views/organisms/QuestionDialog');
}

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
};

View File

@@ -1,101 +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 deviceId() {
var id = Math.floor(Math.random()*16777215).toString(16);
id = "W" + "000000".substring(id.length) + id;
if (localStorage) {
id = localStorage.getItem("mx_device_id") || id;
localStorage.setItem("mx_device_id", id);
}
return id;
}
function createClient(hs_url, is_url, user_id, access_token) {
var opts = {
baseUrl: hs_url,
idBaseUrl: is_url,
accessToken: access_token,
userId: user_id
};
if (localStorage) {
opts.sessionStore = new Matrix.WebStorageSessionStore(localStorage);
opts.deviceId = deviceId();
}
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;
},
unset: function() {
matrixClient = null;
},
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) {
if (localStorage) {
try {
localStorage.clear();
} catch (e) {
console.warn("Error using local storage");
}
}
createClient(hs_url, is_url, user_id, access_token);
if (localStorage) {
try {
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,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');
var q = require('q');
module.exports = {
DialogContainerId: "mx_Dialog_Container",
getOrCreateContainer: function() {
var container = document.getElementById(this.DialogContainerId);
if (!container) {
container = document.createElement("div");
container.id = this.DialogContainerId;
document.body.appendChild(container);
}
return container;
},
createDialog: function (Element, props) {
var self = this;
var closeDialog = function() {
React.unmountComponentAtNode(self.getOrCreateContainer());
if (props && props.onFinished) props.onFinished.apply(null, arguments);
};
// FIXME: If a dialog uses getDefaultProps it clobbers the onFinished
// property set here so you can't close the dialog from a button click!
var dialog = (
<div className="mx_Dialog_Wrapper">
<div className="mx_Dialog">
<Element {...props} onFinished={closeDialog}/>
</div>
<div className="mx_Dialog_Background" onClick={closeDialog}></div>
</div>
);
React.render(dialog, this.getOrCreateContainer());
return {close: closeDialog};
},
};

View File

@@ -1,107 +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");
// Time in ms after that a user is considered as unavailable/away
var UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins
var PRESENCE_STATES = ["online", "offline", "unavailable"];
// The current presence state
var state, timer;
module.exports = {
/**
* Start listening the user activity to evaluate his presence state.
* Any state change will be sent to the Home Server.
*/
start: function() {
var self = this;
this.running = true;
if (undefined === state) {
// The user is online if they move the mouse or press a key
document.onmousemove = function() { self._resetTimer(); };
document.onkeypress = function() { self._resetTimer(); };
this._resetTimer();
}
},
/**
* Stop tracking user activity
*/
stop: function() {
this.running = false;
if (timer) {
clearTimeout(timer);
timer = undefined;
}
state = undefined;
},
/**
* Get the current presence state.
* @returns {string} the presence state (see PRESENCE enum)
*/
getState: function() {
return state;
},
/**
* Set the presence state.
* If the state has changed, the Home Server will be notified.
* @param {string} newState the new presence state (see PRESENCE enum)
*/
setState: function(newState) {
if (newState === state) {
return;
}
if (PRESENCE_STATES.indexOf(newState) === -1) {
throw new Error("Bad presence state: " + newState);
}
if (!this.running) {
return;
}
state = newState;
MatrixClientPeg.get().setPresence(state).done(function() {
console.log("Presence: %s", newState);
}, function(err) {
console.error("Failed to set presence: %s", err);
});
},
/**
* Callback called when the user made no action on the page for UNAVAILABLE_TIME ms.
* @private
*/
_onUnavailableTimerFire: function() {
this.setState("unavailable");
},
/**
* Callback called when the user made an action on the page
* @private
*/
_resetTimer: function() {
var self = this;
this.setState("online");
// Re-arm the timer
clearTimeout(timer);
timer = setTimeout(function() {
self._onUnavailableTimerFire();
}, UNAVAILABLE_TIME_MS);
}
};

View File

@@ -1,253 +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");
var encryption = require("./encryption");
var reject = function(msg) {
return {
error: msg
};
};
var success = function(promise) {
return {
promise: promise
};
};
var commands = {
// Change your nickname
nick: function(room_id, args) {
if (args) {
return success(
MatrixClientPeg.get().setDisplayName(args)
);
}
return reject("Usage: /nick <display_name>");
},
encrypt: function(room_id, args) {
if (args == "on") {
var client = MatrixClientPeg.get();
var members = client.getRoom(room_id).currentState.members;
var user_ids = Object.keys(members);
return success(
encryption.enableEncryption(client, room_id, user_ids)
);
}
if (args == "off") {
var client = MatrixClientPeg.get();
return success(
encryption.disableEncryption(client, room_id)
);
}
return reject("Usage: encrypt <on/off>");
},
// Change the room topic
topic: function(room_id, args) {
if (args) {
return success(
MatrixClientPeg.get().setRoomTopic(room_id, args)
);
}
return reject("Usage: /topic <topic>");
},
// Invite a user
invite: function(room_id, args) {
if (args) {
var matches = args.match(/^(\S+)$/);
if (matches) {
return success(
MatrixClientPeg.get().invite(room_id, matches[1])
);
}
}
return reject("Usage: /invite <userId>");
},
// Join a room
join: function(room_id, args) {
if (args) {
var matches = args.match(/^(\S+)$/);
if (matches) {
var room_alias = matches[1];
// Try to find a room with this alias
var rooms = MatrixClientPeg.get().getRooms();
var roomId;
for (var i = 0; i < rooms.length; i++) {
var aliasEvents = rooms[i].currentState.getStateEvents(
"m.room.aliases"
);
for (var j = 0; j < aliasEvents.length; j++) {
var aliases = aliasEvents[j].getContent().aliases || [];
for (var k = 0; k < aliases.length; k++) {
if (aliases[k] === room_alias) {
roomId = rooms[i].roomId;
break;
}
}
if (roomId) { break; }
}
if (roomId) { break; }
}
if (roomId) { // we've already joined this room, view it.
dis.dispatch({
action: 'view_room',
room_id: roomId
});
return success();
}
else {
// attempt to join this alias.
return success(
MatrixClientPeg.get().joinRoom(room_alias).then(
function(room) {
dis.dispatch({
action: 'view_room',
room_id: room.roomId
});
})
);
}
}
}
return reject("Usage: /join <room_alias>");
},
// Kick a user from the room with an optional reason
kick: function(room_id, args) {
if (args) {
var matches = args.match(/^(\S+?)( +(.*))?$/);
if (matches) {
return success(
MatrixClientPeg.get().kick(room_id, matches[1], matches[3])
);
}
}
return reject("Usage: /kick <userId> [<reason>]");
},
// Ban a user from the room with an optional reason
ban: function(room_id, args) {
if (args) {
var matches = args.match(/^(\S+?)( +(.*))?$/);
if (matches) {
return success(
MatrixClientPeg.get().ban(room_id, matches[1], matches[3])
);
}
}
return reject("Usage: /ban <userId> [<reason>]");
},
// Unban a user from the room
unban: function(room_id, args) {
if (args) {
var matches = args.match(/^(\S+)$/);
if (matches) {
// Reset the user membership to "leave" to unban him
return success(
MatrixClientPeg.get().unban(room_id, matches[1])
);
}
}
return reject("Usage: /unban <userId>");
},
// Define the power level of a user
op: function(room_id, args) {
if (args) {
var matches = args.match(/^(\S+?)( +(\d+))?$/);
var powerLevel = 50; // default power level for op
if (matches) {
var user_id = matches[1];
if (matches.length === 4 && undefined !== matches[3]) {
powerLevel = parseInt(matches[3]);
}
if (powerLevel !== NaN) {
var room = MatrixClientPeg.get().getRoom(room_id);
if (!room) {
return reject("Bad room ID: " + room_id);
}
var powerLevelEvent = room.currentState.getStateEvents(
"m.room.power_levels", ""
);
return success(
MatrixClientPeg.get().setPowerLevel(
room_id, user_id, powerLevel, powerLevelEvent
)
);
}
}
}
return reject("Usage: /op <userId> [<power level>]");
},
// Reset the power level of a user
deop: function(room_id, args) {
if (args) {
var matches = args.match(/^(\S+)$/);
if (matches) {
var room = MatrixClientPeg.get().getRoom(room_id);
if (!room) {
return reject("Bad room ID: " + room_id);
}
var powerLevelEvent = room.currentState.getStateEvents(
"m.room.power_levels", ""
);
return success(
MatrixClientPeg.get().setPowerLevel(
room_id, args, undefined, powerLevelEvent
)
);
}
}
return reject("Usage: /deop <userId>");
}
};
module.exports = {
/**
* Process the given text for /commands and perform them.
* @param {string} roomId The room in which the command was performed.
* @param {string} input The raw text input by the user.
* @return {Object|null} An object with the property 'error' if there was an error
* processing the command, or 'promise' if a request was sent out.
* Returns null if the input didn't match a command.
*/
processInput: function(roomId, input) {
// trim any trailing whitespace, as it can confuse the parser for
// IRC-style commands
input = input.replace(/\s+$/, "");
if (input[0] === "/" && input[1] !== "/") {
var bits = input.match(/^(\S+?)( +(.*))?$/);
var cmd = bits[1].substring(1).toLowerCase();
var args = bits[3];
if (commands[cmd]) {
return commands[cmd](roomId, args);
}
}
return null; // not a command
}
};

View File

@@ -1,82 +0,0 @@
function textForMemberEvent(ev) {
// XXX: SYJS-16
var senderName = ev.sender ? ev.sender.name : ev.getSender();
var targetName = ev.target ? ev.target.name : ev.getStateKey();
var reason = ev.getContent().reason ? (
" Reason: " + ev.getContent().reason
) : "";
switch (ev.getContent().membership) {
case 'invite':
return senderName + " invited " + targetName + ".";
case 'ban':
return senderName + " banned " + targetName + "." + reason;
case 'join':
if (ev.getPrevContent() && ev.getPrevContent().membership == 'join') {
if (ev.getPrevContent().displayname && ev.getContent().displayname && ev.getPrevContent().displayname != ev.getContent().displayname) {
return ev.getSender() + " changed their display name from " +
ev.getPrevContent().displayname + " to " +
ev.getContent().displayname;
} else if (!ev.getPrevContent().displayname && ev.getContent().displayname) {
return ev.getSender() + " set their display name to " + ev.getContent().displayname;
} else if (ev.getPrevContent().displayname && !ev.getContent().displayname) {
return ev.getSender() + " removed their display name";
} else if (ev.getPrevContent().avatar_url && !ev.getContent().avatar_url) {
return ev.getSender() + " removed their profile picture";
} else if (ev.getPrevContent().avatar_url && ev.getContent().avatar_url && ev.getPrevContent().avatar_url != ev.getContent().avatar_url) {
return ev.getSender() + " changed their profile picture";
} else if (!ev.getPrevContent().avatar_url && ev.getContent().avatar_url) {
return ev.getSender() + " set a profile picture";
}
} else {
if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
return targetName + " joined the room.";
}
return '';
case 'leave':
if (ev.getSender() === ev.getStateKey()) {
return targetName + " left the room.";
}
else if (ev.getPrevContent().membership === "ban") {
return senderName + " unbanned " + targetName + ".";
}
else if (ev.getPrevContent().membership === "join") {
return senderName + " kicked " + targetName + "." + reason;
}
else {
return targetName + " left the room.";
}
}
};
function textForTopicEvent(ev) {
var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
return senderDisplayName + ' changed the topic to, "' + ev.getContent().topic + '"';
};
function textForMessageEvent(ev) {
var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
var message = senderDisplayName + ': ' + ev.getContent().body;
if (ev.getContent().msgtype === "m.emote") {
message = "* " + senderDisplayName + " " + message;
} else if (ev.getContent().msgtype === "m.image") {
message = senderDisplayName + " sent an image.";
}
return message;
};
var handlers = {
'm.room.message': textForMessageEvent,
'm.room.topic': textForTopicEvent,
'm.room.member': textForMemberEvent
};
module.exports = {
textForEvent: function(ev) {
var hdlr = handlers[ev.getType()];
if (!hdlr) return "";
return hdlr(ev);
}
}

View File

@@ -0,0 +1,134 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
"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 user ID is in fact a conference bot.
* @param {string} userId The user ID to check.
* @return {boolean} True if it is a conference bot.
*/
module.exports.isConferenceUser = function(userId) {
if (userId.indexOf("@" + USER_PREFIX) !== 0) {
return false;
}
var base64part = 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';

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