Compare commits
700 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 59fe9279d1 | |||
| 046c9ef920 | |||
| bca22f26c5 | |||
| 2b68b88b14 | |||
| 97cedfc712 | |||
| 86cb3e9376 | |||
| 42993a78ed | |||
| 2a5ca9d3df | |||
| 323bd79d0e | |||
| 60adbffacf | |||
| f827a2963e | |||
| 5e293c0f45 | |||
| cd7adfed0a | |||
| 902bf3a0a6 | |||
| f736e5243c | |||
| fb2c2ed09a | |||
| ea38968be9 | |||
| 562b047362 | |||
| 381c9009fb | |||
| c0a4574069 | |||
| de9bf4bb47 | |||
| c57bfccb9e | |||
| 52cae92dd7 | |||
| b80b08f04f | |||
| 304e5b997a | |||
| 6b4dbfbd62 | |||
| 000ca35727 | |||
| 776fe2ad70 | |||
| 602727b7ad | |||
| 56deea9f10 | |||
| 8e0be29c13 | |||
| b71b1b5535 | |||
| 5b3524f174 | |||
| f9a70a8b04 | |||
| b652ea5024 | |||
| 2a37a0cb19 | |||
| 761600f325 | |||
| 65f14c7d21 | |||
| 864ba52bc5 | |||
| fdb5020c0c | |||
| 62344b5194 | |||
| 0db12fcd22 | |||
| 455ee4f91b | |||
| 5ca391f914 | |||
| a32abae5a3 | |||
| b2dd3ecf3a | |||
| cc7017b62d | |||
| f852e8a01d | |||
| 6ff1c30a4b | |||
| 85ea45a64a | |||
| 7b258bc229 | |||
| 5ba3499f56 | |||
| f4a6a3c4b2 | |||
| 5967dc4983 | |||
| bf58c340bc | |||
| dc0b15bdfa | |||
| be6fbc2432 | |||
| 51a5542446 | |||
| 3938abc5dd | |||
| 4961a97ed4 | |||
| fb477fad1e | |||
| a070bccffb | |||
| 8e1105b12a | |||
| 93e4a04118 | |||
| 6e3313b461 | |||
| 2e77b0a3c7 | |||
| 16c22e07b8 | |||
| 99b0f9eb7c | |||
| 5248bdd974 | |||
| 157ae836c0 | |||
| 2639d10f97 | |||
| cc5c636fa5 | |||
| c4a2df75eb | |||
| 06c4cae016 | |||
| 3eed711b34 | |||
| d9c51832ab | |||
| 5011d3b158 | |||
| c10b11a22c | |||
| a5ee48d857 | |||
| 343fc1b164 | |||
| 55fde43d5d | |||
| 940eaf2b7d | |||
| 855ecbe11d | |||
| fc8f3eb0ee | |||
| df90921d6c | |||
| 0f2c41dddc | |||
| 1c76870dcf | |||
| a99c9f4db2 | |||
| 7e5373e194 | |||
| 560174b99f | |||
| d2947a637a | |||
| 8e4dcd9b41 | |||
| 9391dc6c2a | |||
| f19044fef2 | |||
| 60179aab52 | |||
| de38a32969 | |||
| 5f6cc9b37b | |||
| e2fc2b1b09 | |||
| 1d97272874 | |||
| 69da6a6dd8 | |||
| 6cb7ffcd3b | |||
| 0ab1dacb1e | |||
| af230b5fa8 | |||
| 4720da3f8e | |||
| e2b3fc3519 | |||
| ab3c1509c5 | |||
| 91dd029483 | |||
| 53fd3f52fa | |||
| d0618c4f49 | |||
| 0bce7f3102 | |||
| 3d97061d78 | |||
| 50f05db29e | |||
| 2fdec51a5b | |||
| 6d332256b5 | |||
| 2b6fbb038a | |||
| 48fb578952 | |||
| 7fc4b1cb35 | |||
| 4725fa4c2d | |||
| 5acb6b0b37 | |||
| 838608afab | |||
| a11516a984 | |||
| 196b352b9a | |||
| e8a12e7ddc | |||
| 135c22c99d | |||
| 6a13155013 | |||
| 6e2a371017 | |||
| de26d1a8ce | |||
| 7af765976b | |||
| 8f6d98886c | |||
| 72e108c4f9 | |||
| e2b695827e | |||
| 4b50a8a56e | |||
| 737d1d8843 | |||
| eea9e366b8 | |||
| 24d0b95cb2 | |||
| 77085882fa | |||
| 9375ebfb75 | |||
| e2f94c8722 | |||
| b0fd65f442 | |||
| f56a6039e8 | |||
| c44994c0ee | |||
| eeb91374cf | |||
| cd4564d3d3 | |||
| 190cd884b5 | |||
| 1741cc915e | |||
| 37fc73b1ea | |||
| c1e83da35d | |||
| 5282796d84 | |||
| 866164c4d9 | |||
| 5ceb1e641f | |||
| f3cbb9fe90 | |||
| fe4371bf45 | |||
| cde3f33db3 | |||
| 82e257b4ea | |||
| 3907da064e | |||
| f43530e1ef | |||
| f6fb1561d7 | |||
| a1e3ec1d19 | |||
| 43b87e1f82 | |||
| 2a85b2271c | |||
| cb2c2c1b36 | |||
| c5a52d89be | |||
| efa574c452 | |||
| 66ef5213b8 | |||
| 370612135f | |||
| ec05d1b9bd | |||
| 089951012b | |||
| c6a9614372 | |||
| a623430c2b | |||
| b247c8a87f | |||
| 56606c01a0 | |||
| eb2a55445c | |||
| 3fe8b503e5 | |||
| bdee2d3b28 | |||
| 15ee2578c5 | |||
| f8c9a28194 | |||
| 768f11fe58 | |||
| acdcb21830 | |||
| 1530568354 | |||
| 7b25f4e069 | |||
| cbab2c142b | |||
| 81bbc05028 | |||
| f59dbe40ec | |||
| 562c3b0e04 | |||
| f119a57952 | |||
| c6fa1e2e21 | |||
| 0bdc026b05 | |||
| 20eb28f052 | |||
| bfd3ef0e44 | |||
| abda8c77ad | |||
| 9e5d090ddb | |||
| 906be376c9 | |||
| 695930efa5 | |||
| 7f2c74e7a8 | |||
| f299572dc7 | |||
| d65b791b2b | |||
| 2bf177dbcc | |||
| 5775552bab | |||
| dd4617a7c6 | |||
| 64dedef2c7 | |||
| 89f8ff4988 | |||
| 3a8c94de5a | |||
| dd39813cc2 | |||
| e6c4273404 | |||
| e1c32536ff | |||
| 013f68519e | |||
| ab9786cc02 | |||
| 57804f4e02 | |||
| c4421f6bc7 | |||
| 965d9aaf47 | |||
| 2476f87e1d | |||
| cd36800426 | |||
| 18eb9d9330 | |||
| 7e379e9877 | |||
| f2ca249b44 | |||
| 09ce3a79ec | |||
| bfa59c6c04 | |||
| e75148e799 | |||
| 8376f0d75a | |||
| bf02a21c7d | |||
| ac365622b8 | |||
| 7cb48e0d2d | |||
| 38ac520e1e | |||
| 6182ce48c9 | |||
| 9e771ddd07 | |||
| 74aef1fdad | |||
| 8860c9c7fd | |||
| a8d7d23dd6 | |||
| f5ce053f42 | |||
| d833c7632d | |||
| 22bf6e7969 | |||
| a1f8116e3b | |||
| 1d32dd72ed | |||
| a3b77475c7 | |||
| 761552430c | |||
| cc720b9797 | |||
| 75c81b369f | |||
| 7c74b0124b | |||
| 48501d91d2 | |||
| aefef2ba56 | |||
| 31dd49ffd7 | |||
| ace0e01d86 | |||
| c0ce7663a9 | |||
| e3d5ca34c8 | |||
| 1fb53565ef | |||
| a41a8d32b8 | |||
| 835d13c696 | |||
| 6153e795bf | |||
| d12498f418 | |||
| c0eb69963d | |||
| 1f19ee88c6 | |||
| 24351537d2 | |||
| d309a7a67b | |||
| f6f68bc348 | |||
| d6a324ede7 | |||
| 7378904f00 | |||
| 059f5198e5 | |||
| 2acbad36a6 | |||
| 519dd16135 | |||
| fb103cb9e1 | |||
| 5e9a95fdfe | |||
| b8610ab466 | |||
| ee3fdbee5b | |||
| 2d827a75a6 | |||
| 50bb4edd1c | |||
| e52f5b5d08 | |||
| fd81ce126b | |||
| 7ae821e2b5 | |||
| cb98e2421e | |||
| 5417385c83 | |||
| c2d8067523 | |||
| 52bd61a2f0 | |||
| aee56a5bd1 | |||
| 7f52fa74a4 | |||
| d1dd4bd3d8 | |||
| ab9f48cd47 | |||
| c597f05e71 | |||
| 80e6cd6d7c | |||
| cb101b0a3b | |||
| bf4e3364b4 | |||
| 0494dff545 | |||
| d5865421bd | |||
| 8578203073 | |||
| e63e6e7016 | |||
| dec62ab92c | |||
| 67d38bfab8 | |||
| d2e2c726eb | |||
| 00d53e4824 | |||
| 4ce80a0837 | |||
| 9aa59fa358 | |||
| 6c8a492637 | |||
| 9709a38250 | |||
| 06ca94c1e6 | |||
| 67255e3f84 | |||
| a20962ac14 | |||
| b4cf86a362 | |||
| bf8d7050cc | |||
| 49e5fa41ad | |||
| e069d808f8 | |||
| e85674711c | |||
| 7a89328ccb | |||
| e77e6c2af0 | |||
| ad26631874 | |||
| cc75eb8b0e | |||
| 735da3c15e | |||
| 56dfdbeb6b | |||
| eaf47ea05c | |||
| 37c46cf02f | |||
| 9d72a7cb35 | |||
| a047f81b84 | |||
| a2694113d3 | |||
| 0aae88d753 | |||
| c7eba0f292 | |||
| 1bc1fc7e55 | |||
| b91a0dd7a5 | |||
| 45a813b795 | |||
| 7b7a77bad0 | |||
| ff3ad47be7 | |||
| f2e8607433 | |||
| b96ab58eb3 | |||
| 5f233d75f2 | |||
| eb88245fe7 | |||
| 45c013f2f2 | |||
| 05f8b49eec | |||
| ef8f9ecbf3 | |||
| 93fff53e29 | |||
| 4ae424f37a | |||
| 36a608952d | |||
| 900b4b4cf8 | |||
| b782e7b9ad | |||
| 8d4268754e | |||
| 9b8e127e23 | |||
| 88dba1bf6c | |||
| 8d7daf61b9 | |||
| ee1fae8ced | |||
| 13983900c0 | |||
| 881739b478 | |||
| e06caa9ca1 | |||
| efc5462131 | |||
| 2199fe5cbf | |||
| 30f774cf9c | |||
| be9aa44ca8 | |||
| dc4459083f | |||
| 2f375e4f67 | |||
| 879c325b83 | |||
| 7ad3f4a577 | |||
| 5b9d3b119f | |||
| 5467fd89d8 | |||
| d2937c2aed | |||
| a0236a9b76 | |||
| c6d4eb7fd3 | |||
| 4cb1f8a226 | |||
| abca5faf78 | |||
| 21ffe22375 | |||
| 64bbebb135 | |||
| ebad3da6dd | |||
| 4633d16a6b | |||
| df026aede2 | |||
| d495a5b747 | |||
| 042a6b58c4 | |||
| d87cf6c02b | |||
| 0c99c5563f | |||
| 3934e37f77 | |||
| 2ee4fa484e | |||
| bc7948d75f | |||
| 5348b8a980 | |||
| f2936dc15c | |||
| 864f9747f0 | |||
| 3ea62eb73a | |||
| 2fae966884 | |||
| f888ec6e81 | |||
| d2e8201d79 | |||
| 65d7d01dfa | |||
| 2cf2df20f6 | |||
| 1d1f89e0de | |||
| ee73bc3aa4 | |||
| d3fa680373 | |||
| ef9d6d45b6 | |||
| a980864886 | |||
| ca4d506391 | |||
| 554c33a883 | |||
| 56813eb11e | |||
| 4d5e3bc22b | |||
| ff55a951c9 | |||
| 895172d498 | |||
| 71f73d8df2 | |||
| 97daca4b31 | |||
| e9eafc3380 | |||
| 600a1cae79 | |||
| 0b1fc1b925 | |||
| bdaa9faea0 | |||
| dbadb07adf | |||
| 4a2c899d05 | |||
| 85084f5fd7 | |||
| 78692c83a6 | |||
| 173e6011e8 | |||
| 9e542ba232 | |||
| 5005675561 | |||
| 29759ca71e | |||
| be28a96d8d | |||
| 9b5e5c9acb | |||
| fbbbd44dc3 | |||
| 0bb3eaaf67 | |||
| e48d68a449 | |||
| 67175c5a72 | |||
| 6b0aeefc66 | |||
| 9a7f5388d9 | |||
| d1649771cc | |||
| 08e5f61b10 | |||
| 012f085f33 | |||
| 9f570152e5 | |||
| 3099ef68a9 | |||
| f0bac3a3b0 | |||
| cd0ed879e3 | |||
| 95418089f3 | |||
| 650a0f1c1f | |||
| 757e885abc | |||
| 2c8e7782c5 | |||
| d3eccc1d6f | |||
| 40aee5b03d | |||
| 4c9ade5ecb | |||
| 1d435890af | |||
| 8a2b2daad7 | |||
| 21334cab28 | |||
| a17df609f3 | |||
| 0afdf5d8e4 | |||
| 17733a66f9 | |||
| 3a819a29b7 | |||
| 9d77fab18f | |||
| 3650c3f08b | |||
| 5512fd4220 | |||
| 678393e2bd | |||
| 25d8a7999f | |||
| 014f7ade86 | |||
| 2b671fcafc | |||
| df5b243e75 | |||
| 5e43f2752a | |||
| 0cb14ba5ec | |||
| d65477891e | |||
| bb1854814c | |||
| 9e15bda803 | |||
| e7ac66ad04 | |||
| 4a0a911f3b | |||
| 7286aeb013 | |||
| 244265d52b | |||
| ab93e96a1f | |||
| 5a17d8b450 | |||
| 43e3662e60 | |||
| 19d5063814 | |||
| da7a556629 | |||
| c2cb4dff4c | |||
| dd6868c255 | |||
| b411a2e489 | |||
| 28343aaa33 | |||
| 3f615c6664 | |||
| 804b17fbf1 | |||
| 9798e14733 | |||
| b742342062 | |||
| f8fa19ed47 | |||
| fe4bb3e413 | |||
| ff13782ab5 | |||
| b1dd7efed8 | |||
| 699a58e0b3 | |||
| 6a19655886 | |||
| afc889ff4d | |||
| b06c9f037e | |||
| 1c812b340d | |||
| bd9f5d3e06 | |||
| cf8164bcc3 | |||
| 33612b7076 | |||
| 5a97786cc6 | |||
| ee2329d236 | |||
| 66f80b2239 | |||
| 62ebeb9fd8 | |||
| 72ba708bfe | |||
| d0d7f2d2d2 | |||
| b3459be707 | |||
| d1e22d50f0 | |||
| bf46c3cfab | |||
| 7880734d77 | |||
| 5ce1aba493 | |||
| c929076a83 | |||
| 99625067fe | |||
| c9ab977d73 | |||
| b99e7598f9 | |||
| b9e06bcf66 | |||
| eb108c7866 | |||
| a190862ed3 | |||
| 34a31a71fd | |||
| 7774756ed1 | |||
| ee9f78d156 | |||
| 70754db27a | |||
| 16f8143f3e | |||
| be1f014294 | |||
| f53f9af1c5 | |||
| 58b1d62976 | |||
| 8e0f7f18a0 | |||
| 75ea62f351 | |||
| ee8572559f | |||
| f640be90ad | |||
| 472acd4792 | |||
| 8087e99808 | |||
| 51b74251f9 | |||
| 8c7aede0cc | |||
| 2829d95705 | |||
| 28057fd086 | |||
| 2e3ad3206c | |||
| 4f94cf5dfb | |||
| 51e8c28ab6 | |||
| 0f73228d55 | |||
| d21e4fb86a | |||
| 645db7fa2f | |||
| 0d4f35bed1 | |||
| 2123fec8ed | |||
| 3860488bb5 | |||
| ef5ea46830 | |||
| d4faacf462 | |||
| 4a7d2901ac | |||
| f382946138 | |||
| bb93a59cfb | |||
| 0ad84fd7b0 | |||
| 87bddcd8ce | |||
| 18701a2dae | |||
| 2f65064688 | |||
| 2f08f2441f | |||
| 6c4c0bf57a | |||
| 55a10ee275 | |||
| 49545ce0c2 | |||
| b87058508e | |||
| fd53f10fbd | |||
| 6329e274ab | |||
| b5fdaac947 | |||
| 22bf74dc65 | |||
| d376df478a | |||
| 53f4da1d30 | |||
| e34db7b8c6 | |||
| 074bbc7149 | |||
| 4b33164ab6 | |||
| dab707a893 | |||
| 5cf164fcc1 | |||
| 37a7ce809a | |||
| 15f9f5dbe8 | |||
| 187818aaa0 | |||
| 30b1e7078f | |||
| 791980cd1f | |||
| 6c19504c8b | |||
| 497ebce88a | |||
| 2768cd2010 | |||
| 204e42494a | |||
| 72b4a86eed | |||
| ce5311191f | |||
| 7eff6d968e | |||
| d01e2506f5 | |||
| 53fe372a0c | |||
| 4cb04d1e40 | |||
| 24e021b91f | |||
| e988f5ca3b | |||
| 633a3f4867 | |||
| df163d8cb7 | |||
| 73bb317925 | |||
| ad74d264a3 | |||
| e9db975d7d | |||
| 0958a6bb62 | |||
| f3586a79c2 | |||
| 882d09bf85 | |||
| 25eb2e2daf | |||
| d8d9912f2d | |||
| 8a28da1986 | |||
| 384425582a | |||
| b87b356722 | |||
| 6ae0dda9d3 | |||
| 6c680ff424 | |||
| c6b455f470 | |||
| f6d7052928 | |||
| 2ee1a9c440 | |||
| 8fd12d530d | |||
| 3f7bd48c0a | |||
| 28108476bd | |||
| 722cedc92e | |||
| f182e32e3d | |||
| 3cfcc13387 | |||
| 953bb64e0b | |||
| 54f4443428 | |||
| a039450d10 | |||
| 1e963a6c3a | |||
| 80ad45df06 | |||
| 348f133e77 | |||
| cd865bbe8f | |||
| e668d7685d | |||
| 6607bee91a | |||
| 3a89a5af0b | |||
| 35e3621ae7 | |||
| 040ef73886 | |||
| 74c9ac0872 | |||
| adbad509f4 | |||
| 15a97a653f | |||
| 9fb97a6b10 | |||
| 579f210cfc | |||
| 2fb1e156ed | |||
| 707ddc61bf | |||
| 09e861637f | |||
| 1f43f904d5 | |||
| 446f74b3dd | |||
| d2391f999e | |||
| e1779ca8bc | |||
| 65371c9a39 | |||
| a4dc844338 | |||
| 0a4af647c8 | |||
| 503bf541c7 | |||
| 1fbc249de5 | |||
| 959dcd0c49 | |||
| ef4f2f10d9 | |||
| 19dbd85d44 | |||
| ef4b604caf | |||
| 74f459f8a4 | |||
| fef81748bb | |||
| 3e53879adc | |||
| 145e61b00f | |||
| 49dd93ffab | |||
| 7174879ac9 | |||
| 486adb717b | |||
| 773f592c3f | |||
| 2ca9d87b95 | |||
| 4bc4292ceb | |||
| cbb72c2f29 | |||
| 5f477b313b | |||
| d45e44d01c | |||
| c12839dc7b | |||
| c35c9f7c3a | |||
| ff5c7072d7 | |||
| eca453ee5a | |||
| ad2541299f | |||
| dc840fdf48 | |||
| 510bb5785e | |||
| 9556795611 | |||
| 4c6fa740f3 | |||
| f4a3e9a39b | |||
| bb820bebd1 | |||
| 664f809362 | |||
| 034c045b37 | |||
| 4dfb0e9a90 | |||
| 654429dbdb | |||
| c7d0214aaa | |||
| 607923b58f | |||
| 895fb63d5d | |||
| b172018d08 | |||
| 95a0bc92d6 | |||
| a90492e393 | |||
| ec7067e7bd | |||
| 42b7410a5d | |||
| 4cfcdfa040 | |||
| 795986f146 | |||
| d38c338f89 | |||
| a373849b5b | |||
| 8cd4637316 | |||
| 0635a6f562 | |||
| a8cee87c08 | |||
| a7598ea815 | |||
| 22cef7a6a0 | |||
| e507339324 | |||
| b643d8ff6a | |||
| 3547bd8d00 | |||
| ab1f37b0bb | |||
| eb37032d8a | |||
| f6ed21559a | |||
| a5986ade51 | |||
| d7504aeda5 | |||
| b2459b2dc6 | |||
| 819e06e2cd | |||
| b7f1a3db57 | |||
| a030e46c69 | |||
| f61cfbc542 | |||
| c4b7571c45 | |||
| 4dd477e064 | |||
| f595f6f141 | |||
| 24602119c5 | |||
| 3040d0a474 | |||
| e4ea00ca23 | |||
| 4fc311da90 | |||
| 7894e52529 | |||
| 7999a70cab | |||
| f6aa9a7ea4 | |||
| b3ae9cc9d4 | |||
| 5f29729e82 | |||
| e24851456a | |||
| 1e40fd750f | |||
| ed1554f4af | |||
| c6cf5febd5 | |||
| f9aaf7d903 | |||
| a2e73cceee | |||
| c672919d1e | |||
| 7ab2449ac1 | |||
| e68a2b5e1d | |||
| ddc4ac187c | |||
| 7e563b89c7 | |||
| 6a6118e136 | |||
| a288c5b85d | |||
| c4d408d095 | |||
| ac24d6707f | |||
| e5835d2731 |
+4
-1
@@ -1,5 +1,4 @@
|
||||
/cert.pem
|
||||
/.DS_Store
|
||||
/karma-reports
|
||||
/key.pem
|
||||
/lib
|
||||
@@ -7,3 +6,7 @@
|
||||
/packages/
|
||||
/vector/bundle.*
|
||||
/vector/components.css
|
||||
/vector/emojione/
|
||||
/vector/config.json
|
||||
/vector/olm.js
|
||||
.DS_Store
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 6 # node v6, to match jenkins
|
||||
install:
|
||||
- npm install
|
||||
- (cd node_modules/matrix-react-sdk && npm run build)
|
||||
+283
@@ -1,3 +1,286 @@
|
||||
Changes in [0.8.3](https://github.com/vector-im/vector-web/releases/tag/v0.8.3) (2016-10-12)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.2...v0.8.3)
|
||||
|
||||
* Centre images in dialog buttons
|
||||
[\#2453](https://github.com/vector-im/vector-web/pull/2453)
|
||||
* Only show quote option if RTE is enabled
|
||||
[\#2448](https://github.com/vector-im/vector-web/pull/2448)
|
||||
* Fix join button for 'matrix' networks
|
||||
[\#2443](https://github.com/vector-im/vector-web/pull/2443)
|
||||
* Don't stop paginating if no rooms match
|
||||
[\#2422](https://github.com/vector-im/vector-web/pull/2422)
|
||||
|
||||
Changes in [0.8.2](https://github.com/vector-im/vector-web/releases/tag/v0.8.2) (2016-10-05)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.1...v0.8.2)
|
||||
|
||||
* Add native joining of 3p networks to room dir
|
||||
[\#2379](https://github.com/vector-im/vector-web/pull/2379)
|
||||
* Update to linkify 2.1.3
|
||||
[\#2406](https://github.com/vector-im/vector-web/pull/2406)
|
||||
* Use 'Sign In' / 'Sign Out' universally
|
||||
[\#2383](https://github.com/vector-im/vector-web/pull/2383)
|
||||
* Prevent network dropdown resizing slightly
|
||||
[\#2382](https://github.com/vector-im/vector-web/pull/2382)
|
||||
* Room directory: indicate when there are no results
|
||||
[\#2380](https://github.com/vector-im/vector-web/pull/2380)
|
||||
* Room dir: New filtering & 3rd party networks
|
||||
[\#2362](https://github.com/vector-im/vector-web/pull/2362)
|
||||
* Update linkify version
|
||||
[\#2359](https://github.com/vector-im/vector-web/pull/2359)
|
||||
* Directory search join button
|
||||
[\#2339](https://github.com/vector-im/vector-web/pull/2339)
|
||||
|
||||
Changes in [0.8.1](https://github.com/vector-im/vector-web/releases/tag/v0.8.1) (2016-09-21)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.0...v0.8.1)
|
||||
|
||||
|
||||
Changes in [0.8.0](https://github.com/vector-im/vector-web/releases/tag/v0.8.0) (2016-09-21)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.5-r3...v0.8.0)
|
||||
|
||||
* Dbkr/rebrand
|
||||
[\#2285](https://github.com/vector-im/vector-web/pull/2285)
|
||||
* Listen for close_scalar and close the dialog box when received
|
||||
[\#2282](https://github.com/vector-im/vector-web/pull/2282)
|
||||
* Revert "improve lipstick and support scalar logout"
|
||||
[\#2281](https://github.com/vector-im/vector-web/pull/2281)
|
||||
* improve lipstick and support scalar logout
|
||||
[\#2280](https://github.com/vector-im/vector-web/pull/2280)
|
||||
* Fix changelog links
|
||||
[\#2071](https://github.com/vector-im/vector-web/pull/2071)
|
||||
* Paginate Room Directory
|
||||
[\#2241](https://github.com/vector-im/vector-web/pull/2241)
|
||||
* Make redeploy script symlink config
|
||||
[\#2240](https://github.com/vector-im/vector-web/pull/2240)
|
||||
* Update the version of olm to 1.3.0
|
||||
[\#2210](https://github.com/vector-im/vector-web/pull/2210)
|
||||
* Directory network selector
|
||||
[\#2219](https://github.com/vector-im/vector-web/pull/2219)
|
||||
* Wmwragg/two state sublist headers
|
||||
[\#2235](https://github.com/vector-im/vector-web/pull/2235)
|
||||
* Wmwragg/correct incoming call positioning
|
||||
[\#2222](https://github.com/vector-im/vector-web/pull/2222)
|
||||
* Wmwragg/remove old filter
|
||||
[\#2211](https://github.com/vector-im/vector-web/pull/2211)
|
||||
* Wmwragg/multi invite bugfix
|
||||
[\#2198](https://github.com/vector-im/vector-web/pull/2198)
|
||||
* Wmwragg/chat multi invite
|
||||
[\#2181](https://github.com/vector-im/vector-web/pull/2181)
|
||||
* shuffle bottomleftmenu around a bit
|
||||
[\#2182](https://github.com/vector-im/vector-web/pull/2182)
|
||||
* Improve autocomplete behaviour (styling)
|
||||
[\#2175](https://github.com/vector-im/vector-web/pull/2175)
|
||||
* First wave of E2E visuals
|
||||
[\#2163](https://github.com/vector-im/vector-web/pull/2163)
|
||||
* FilePanel and NotificationPanel support
|
||||
[\#2113](https://github.com/vector-im/vector-web/pull/2113)
|
||||
* Cursor: pointer on member info create room button
|
||||
[\#2151](https://github.com/vector-im/vector-web/pull/2151)
|
||||
* Support for adding DM rooms to the MemberInfo Panel
|
||||
[\#2147](https://github.com/vector-im/vector-web/pull/2147)
|
||||
* Wmwragg/one to one indicators
|
||||
[\#2139](https://github.com/vector-im/vector-web/pull/2139)
|
||||
* Added back the Directory listing button, with new tootlip
|
||||
[\#2136](https://github.com/vector-im/vector-web/pull/2136)
|
||||
* wmwragg/chat invite dialog fix
|
||||
[\#2134](https://github.com/vector-im/vector-web/pull/2134)
|
||||
* Wmwragg/one to one chat
|
||||
[\#2110](https://github.com/vector-im/vector-web/pull/2110)
|
||||
* Support toggling DM status of rooms
|
||||
[\#2111](https://github.com/vector-im/vector-web/pull/2111)
|
||||
* Formatting toolbar for RTE message composer.
|
||||
[\#2082](https://github.com/vector-im/vector-web/pull/2082)
|
||||
* jenkins.sh: install olm from jenkins artifacts
|
||||
[\#2092](https://github.com/vector-im/vector-web/pull/2092)
|
||||
* e2e device CSS
|
||||
[\#2085](https://github.com/vector-im/vector-web/pull/2085)
|
||||
* Bump to olm 1.1.0
|
||||
[\#2069](https://github.com/vector-im/vector-web/pull/2069)
|
||||
* Improve readability of the changelog dialog
|
||||
[\#2056](https://github.com/vector-im/vector-web/pull/2056)
|
||||
* Turn react consistency checks back on in develop builds
|
||||
[\#2009](https://github.com/vector-im/vector-web/pull/2009)
|
||||
* Wmwragg/direct chat sublist
|
||||
[\#2028](https://github.com/vector-im/vector-web/pull/2028)
|
||||
|
||||
Changes in [0.7.5-r3](https://github.com/vector-im/vector-web/releases/tag/v0.7.5-r3) (2016-09-02)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.5-r2...v0.7.5-r3)
|
||||
|
||||
* Bump to matrix-react-sdk 0.6.5-r3 in order to fix bug #2020 (tightloop when flooded with join events)
|
||||
|
||||
|
||||
Changes in [0.7.5-r2](https://github.com/vector-im/vector-web/releases/tag/v0.7.5-r2) (2016-09-01)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.5-r1...v0.7.5-r2)
|
||||
|
||||
* Bump to matrix-react-sdk 0.6.5-r1 in order to fix guest access
|
||||
|
||||
Changes in [0.7.5-r1](https://github.com/vector-im/vector-web/releases/tag/v0.7.5-r1) (2016-08-28)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.5...v0.7.5-r1)
|
||||
|
||||
* Correctly pin deps :(
|
||||
|
||||
Changes in [0.7.5](https://github.com/vector-im/vector-web/releases/tag/v0.7.5) (2016-08-28)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.4-r1...v0.7.5)
|
||||
|
||||
* re-add leave button in RoomSettings
|
||||
* add /user URLs
|
||||
* recognise matrix.to links and other vector links
|
||||
* fix linkify dependency
|
||||
* fix avatar clicking in MemberInfo
|
||||
* fix RoomTagContextMenu so it works on historical rooms
|
||||
* warn people to put their Matrix HS on a separate domain to Vector
|
||||
* fix zalgos again
|
||||
* Add .travis.yml
|
||||
[\#2007](https://github.com/vector-im/vector-web/pull/2007)
|
||||
* add fancy changelog dialog
|
||||
[\#1972](https://github.com/vector-im/vector-web/pull/1972)
|
||||
* Update autocomplete design
|
||||
[\#1978](https://github.com/vector-im/vector-web/pull/1978)
|
||||
* Update encryption info in README
|
||||
[\#2001](https://github.com/vector-im/vector-web/pull/2001)
|
||||
* Added event/info message avatars back in
|
||||
[\#2000](https://github.com/vector-im/vector-web/pull/2000)
|
||||
* Wmwragg/chat message presentation
|
||||
[\#1987](https://github.com/vector-im/vector-web/pull/1987)
|
||||
* Make the notification slider work
|
||||
[\#1982](https://github.com/vector-im/vector-web/pull/1982)
|
||||
* Use cpx to copy olm.js, and add watcher
|
||||
[\#1966](https://github.com/vector-im/vector-web/pull/1966)
|
||||
* Make up a device display name
|
||||
[\#1959](https://github.com/vector-im/vector-web/pull/1959)
|
||||
|
||||
Changes in [0.7.4-r1](https://github.com/vector-im/vector-web/releases/tag/v0.7.4-r1) (2016-08-12)
|
||||
==================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.4...v0.7.4-r1)
|
||||
* Update to matrix-react-sdk 0.6.4-r1 to fix inviting multiple people
|
||||
|
||||
|
||||
Changes in [0.7.4](https://github.com/vector-im/vector-web/releases/tag/v0.7.4) (2016-08-11)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.3...v0.7.4)
|
||||
|
||||
* Don't show border on composer when not in RTE mode
|
||||
[\#1954](https://github.com/vector-im/vector-web/pull/1954)
|
||||
* Wmwragg/room tag menu
|
||||
[\#1941](https://github.com/vector-im/vector-web/pull/1941)
|
||||
* Don't redirect to mobile app if verifying 3pid
|
||||
[\#1951](https://github.com/vector-im/vector-web/pull/1951)
|
||||
* Make sure that we clear localstorage before *all* tests
|
||||
[\#1950](https://github.com/vector-im/vector-web/pull/1950)
|
||||
* Basic CSS for multi-invite dialog
|
||||
[\#1942](https://github.com/vector-im/vector-web/pull/1942)
|
||||
* More tests for the loading process:
|
||||
[\#1947](https://github.com/vector-im/vector-web/pull/1947)
|
||||
* Support for refactored login token handling
|
||||
[\#1946](https://github.com/vector-im/vector-web/pull/1946)
|
||||
* Various fixes and improvements to emojification.
|
||||
[\#1935](https://github.com/vector-im/vector-web/pull/1935)
|
||||
* More app-loading tests
|
||||
[\#1938](https://github.com/vector-im/vector-web/pull/1938)
|
||||
* Some tests of the application load process
|
||||
[\#1936](https://github.com/vector-im/vector-web/pull/1936)
|
||||
* Add 'enable labs' setting to sample config
|
||||
[\#1930](https://github.com/vector-im/vector-web/pull/1930)
|
||||
* Matthew/scalar
|
||||
[\#1928](https://github.com/vector-im/vector-web/pull/1928)
|
||||
* Fix unit tests
|
||||
[\#1929](https://github.com/vector-im/vector-web/pull/1929)
|
||||
* Wmwragg/mute mention state fix
|
||||
[\#1926](https://github.com/vector-im/vector-web/pull/1926)
|
||||
* CSS for deactivate account dialog
|
||||
[\#1919](https://github.com/vector-im/vector-web/pull/1919)
|
||||
* Wmwragg/mention state menu
|
||||
[\#1900](https://github.com/vector-im/vector-web/pull/1900)
|
||||
* Fix UnknownBody styling for #1901
|
||||
[\#1913](https://github.com/vector-im/vector-web/pull/1913)
|
||||
* Exclude olm from the webpack
|
||||
[\#1914](https://github.com/vector-im/vector-web/pull/1914)
|
||||
* Wmwragg/button updates
|
||||
[\#1912](https://github.com/vector-im/vector-web/pull/1912)
|
||||
* Wmwragg/button updates
|
||||
[\#1828](https://github.com/vector-im/vector-web/pull/1828)
|
||||
* CSS for device management UI
|
||||
[\#1909](https://github.com/vector-im/vector-web/pull/1909)
|
||||
* Fix a warning from RoomSubList
|
||||
[\#1908](https://github.com/vector-im/vector-web/pull/1908)
|
||||
* Fix notifications warning layout
|
||||
[\#1907](https://github.com/vector-im/vector-web/pull/1907)
|
||||
* Remove relayoutOnUpdate prop on gemini-scrollbar
|
||||
[\#1883](https://github.com/vector-im/vector-web/pull/1883)
|
||||
* Bump dependency versions
|
||||
[\#1842](https://github.com/vector-im/vector-web/pull/1842)
|
||||
* Wmwragg/mention state indicator round 2
|
||||
[\#1835](https://github.com/vector-im/vector-web/pull/1835)
|
||||
* Wmwragg/spinner fix
|
||||
[\#1822](https://github.com/vector-im/vector-web/pull/1822)
|
||||
* Wmwragg/mention state indicator
|
||||
[\#1823](https://github.com/vector-im/vector-web/pull/1823)
|
||||
* Revert "Presentation for inline link"
|
||||
[\#1809](https://github.com/vector-im/vector-web/pull/1809)
|
||||
* Wmwragg/modal restyle
|
||||
[\#1806](https://github.com/vector-im/vector-web/pull/1806)
|
||||
* Presentation for inline link
|
||||
[\#1799](https://github.com/vector-im/vector-web/pull/1799)
|
||||
* CSS for offline user colours
|
||||
[\#1798](https://github.com/vector-im/vector-web/pull/1798)
|
||||
* Wmwragg/typography updates
|
||||
[\#1776](https://github.com/vector-im/vector-web/pull/1776)
|
||||
* webpack: always use the olm from vector-web
|
||||
[\#1766](https://github.com/vector-im/vector-web/pull/1766)
|
||||
* feat: large emoji support
|
||||
[\#1718](https://github.com/vector-im/vector-web/pull/1718)
|
||||
* Autocomplete
|
||||
[\#1717](https://github.com/vector-im/vector-web/pull/1717)
|
||||
* #1664 Set a maximum height for codeblocks
|
||||
[\#1670](https://github.com/vector-im/vector-web/pull/1670)
|
||||
* CSS for device blocking
|
||||
[\#1688](https://github.com/vector-im/vector-web/pull/1688)
|
||||
* Fix joining rooms by typing the alias
|
||||
[\#1685](https://github.com/vector-im/vector-web/pull/1685)
|
||||
* Add ability to delete an alias from room directory
|
||||
[\#1680](https://github.com/vector-im/vector-web/pull/1680)
|
||||
* package.json: add olm as optionalDependency
|
||||
[\#1678](https://github.com/vector-im/vector-web/pull/1678)
|
||||
* Another go at enabling olm on vector.im/develop
|
||||
[\#1675](https://github.com/vector-im/vector-web/pull/1675)
|
||||
* CSS for unverify button
|
||||
[\#1661](https://github.com/vector-im/vector-web/pull/1661)
|
||||
* CSS fix for rooms with crypto enabled
|
||||
[\#1660](https://github.com/vector-im/vector-web/pull/1660)
|
||||
* Karma: fix warning by ignoring olm
|
||||
[\#1652](https://github.com/vector-im/vector-web/pull/1652)
|
||||
* Update for react-sdk dbkr/fix_peeking branch
|
||||
[\#1639](https://github.com/vector-im/vector-web/pull/1639)
|
||||
* Update README.md
|
||||
[\#1641](https://github.com/vector-im/vector-web/pull/1641)
|
||||
* Fix karma tests
|
||||
[\#1643](https://github.com/vector-im/vector-web/pull/1643)
|
||||
* Rich Text Editor
|
||||
[\#1553](https://github.com/vector-im/vector-web/pull/1553)
|
||||
* Fix RoomDirectory to join by alias whenever possible.
|
||||
[\#1615](https://github.com/vector-im/vector-web/pull/1615)
|
||||
* Make the config optional
|
||||
[\#1612](https://github.com/vector-im/vector-web/pull/1612)
|
||||
* CSS support for device verification
|
||||
[\#1610](https://github.com/vector-im/vector-web/pull/1610)
|
||||
* Don't use SdkConfig
|
||||
[\#1609](https://github.com/vector-im/vector-web/pull/1609)
|
||||
* serve config.json statically instead of bundling it
|
||||
[\#1516](https://github.com/vector-im/vector-web/pull/1516)
|
||||
|
||||
Changes in [0.7.3](https://github.com/vector-im/vector-web/releases/tag/v0.7.3) (2016-06-03)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.2...v0.7.3)
|
||||
|
||||
* Update to react-sdk 0.6.3
|
||||
|
||||
Changes in [0.7.2](https://github.com/vector-im/vector-web/releases/tag/v0.7.2) (2016-06-02)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.7.1...v0.7.2)
|
||||
|
||||
@@ -3,63 +3,162 @@ Vector/Web
|
||||
|
||||
Vector is a Matrix web client built using the Matrix React SDK (https://github.com/matrix-org/matrix-react-sdk).
|
||||
|
||||
Getting started
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
The easiest way to test Vector is to just use the hosted copy at https://vector.im/beta.
|
||||
The develop branch is continuously deployed by Jenkins at https://vector.im/develop for
|
||||
those who like living dangerously.
|
||||
|
||||
To host your own copy of Vector, the quickest bet is to use a pre-built released version
|
||||
of Vector:
|
||||
|
||||
1. Download the latest version from https://vector.im/packages/
|
||||
1. Untar the tarball on your web server
|
||||
1. Move (or symlink) the vector-x.x.x directory to an appropriate name
|
||||
1. If desired, copy `config.sample.json` to `config.json` and edit it
|
||||
as desired. See below for details.
|
||||
1. Enter the URL into your browser and log into vector!
|
||||
|
||||
Important Security Note
|
||||
=======================
|
||||
|
||||
We do not recommend running Vector from the same domain name as your Matrix
|
||||
homeserver. The reason is the risk of XSS (cross-site-scripting) vulnerabilities
|
||||
that could occur if someone caused Vector to load and render malicious user generated
|
||||
content from a Matrix API which then had trusted access to Vector (or other apps) due
|
||||
to sharing the same domain.
|
||||
|
||||
We have put some coarse mitigations into place to try to protect against this situation,
|
||||
but it's still not good practice to do it in the first place.
|
||||
See https://github.com/vector-im/vector-web/issues/1977 for more details.
|
||||
|
||||
Building From Source
|
||||
====================
|
||||
|
||||
Vector is a modular webapp built with modern ES6 and requires a npm build system to build.
|
||||
|
||||
1. Install or update `node.js` so that your `npm` is at least at version `2.0.0`
|
||||
1. Clone the repo: `git clone https://github.com/vector-im/vector-web.git`
|
||||
1. Clone the repo: `git clone https://github.com/vector-im/vector-web.git`
|
||||
1. Switch to the vector directory: `cd vector-web`
|
||||
1. Install the prerequisites: `npm install`
|
||||
1. If you are using the `develop` branch of vector, you will probably need to
|
||||
rebuild one of the dependencies, due to https://github.com/npm/npm/issues/3055:
|
||||
`(cd node_modules/matrix-react-sdk && npm install)`
|
||||
1. Start the development builder and a testing server: `npm start`
|
||||
1. Wait a few seconds for the initial build to finish (the command won't
|
||||
terminate: it's running a web server for you).
|
||||
1. Open http://127.0.0.1:8080/ in your browser to see your newly built Vector.
|
||||
1. Configure the app by copying `config.sample.json` to `config.json` and modifying
|
||||
it (see below for details)
|
||||
1. `npm run package` to build a tarball to deploy. Untaring this file will give
|
||||
a version-specific directory containing all the files that need to go on your
|
||||
web server.
|
||||
|
||||
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.
|
||||
Note that `npm run package` is not supported on Windows, so Windows users can run `npm
|
||||
run build`, which will build all the necessary files into the `vector`
|
||||
directory. The version of Vector will not appear in Settings without
|
||||
using the package script. You can then mount the vector directory on your
|
||||
webserver to actually serve up the app, which is entirely static content.
|
||||
|
||||
Configuring
|
||||
config.json
|
||||
===========
|
||||
|
||||
Configure the app by modifying the `config.json` file:
|
||||
You can configure the app by copying `vector/config.sample.json` to
|
||||
`vector/config.json` and customising it:
|
||||
|
||||
1. `default_hs_url` is the default home server url.
|
||||
1. `default_is_url` is the default identity server url (this is the server used
|
||||
for verifying third party identifiers like email addresses). If this is blank,
|
||||
registering with an email address or adding an email address to your account
|
||||
will not work.
|
||||
registering with an email address, adding an email address to your account,
|
||||
or inviting users via email address will not work. Matrix identity servers are
|
||||
very simple web services which map third party identifiers (currently only email
|
||||
addresses) to matrix IDs: see http://matrix.org/docs/spec/identity_service/unstable.html
|
||||
for more details. Currently the only public matrix identity servers are https://matrix.org
|
||||
and https://vector.im. In future identity servers will be decentralised.
|
||||
1. `roomDirectory`: config for the public room directory. This section encodes behaviour
|
||||
on the room directory screen for filtering the list by server / network type and joining
|
||||
third party networks. This config section will disappear once APIs are available to
|
||||
get this information for home servers. This section is optional.
|
||||
1. `roomDirectory.servers`: List of other Home Servers' directories to include in the drop
|
||||
down list. Optional.
|
||||
1. `roomDirectory.serverConfig`: Config for each server in `roomDirectory.servers`. Optional.
|
||||
1. `roomDirectory.serverConfig.<server_name>.networks`: List of networks (named
|
||||
in `roomDirectory.networks`) to include for this server. Optional.
|
||||
1. `roomDirectory.networks`: config for each network type. Optional.
|
||||
1. `roomDirectory.<network_type>.name`: Human-readable name for the network. Required.
|
||||
1. `roomDirectory.<network_type>.protocol`: Protocol as given by the server in
|
||||
`/_matrix/client/unstable/thirdparty/protocols` response. Required to be able to join
|
||||
this type of third party network.
|
||||
1. `roomDirectory.<network_type>.domain`: Domain as given by the server in
|
||||
`/_matrix/client/unstable/thirdparty/protocols` response, if present. Required to be
|
||||
able to join this type of third party network, if present in `thirdparty/protocols`.
|
||||
1. `roomDirectory.<network_type>.portalRoomPattern`: Regular expression matching aliases
|
||||
for portal rooms to locations on this network. Required.
|
||||
1. `roomDirectory.<network_type>.icon`: URL to an icon to be displayed for this network. Required.
|
||||
1. `roomDirectory.<network_type>.example`: Textual example of a location on this network,
|
||||
eg. '#channel' for an IRC network. Optional.
|
||||
1. `roomDirectory.<network_type>.nativePattern`: Regular expression that matches a
|
||||
valid location on this network. This is used as a hint to the user to indicate
|
||||
when a valid location has been entered so it's not necessary for this to be
|
||||
exactly correct. Optional.
|
||||
|
||||
You will need to re-run `npm run build` after editing `config.json`.
|
||||
Running as a Desktop app
|
||||
========================
|
||||
|
||||
Deployment
|
||||
==========
|
||||
In future we'll do an official distribution of Vector as an desktop app. Meanwhile,
|
||||
there are a few options:
|
||||
|
||||
On a Unix-based OS, run `npm run package` to build a tarball package. Untaring
|
||||
this file will give a version-specific directory containing all the files that
|
||||
need to go on your web server.
|
||||
@asdf:matrix.org points out that you can use nativefier and it just works(tm):
|
||||
|
||||
```
|
||||
sudo npm install nativefier -g
|
||||
nativefier https://vector.im/beta/
|
||||
```
|
||||
|
||||
krisa has a dedicated electron project at https://github.com/krisak/vector-electron-desktop
|
||||
(although you should swap out the 'vector' folder for the latest vector tarball you want to run.
|
||||
Get a tarball from https://vector.im/packages or build your own - see Building From Source
|
||||
above).
|
||||
|
||||
There's also a (much) older electron distribution at https://github.com/stevenhammerton/vector-desktop
|
||||
|
||||
The package script is not supported on Windows, so Windows users can run `npm
|
||||
run build`, which will build all the necessary files into the `vector`
|
||||
directory. Note that the version of Vector will not appear in Settings without
|
||||
using the package script. You can then mount the vector directory on your
|
||||
webserver to actually serve up the app, which is entirely static content.
|
||||
|
||||
Development
|
||||
===========
|
||||
|
||||
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.
|
||||
Before attempting to develop on Vector you **must** read the developer guide
|
||||
for `matrix-react-sdk` at https://github.com/matrix-org/matrix-react-sdk, which
|
||||
also defines the design, architecture and style for Vector too.
|
||||
|
||||
However, much of the functionality in Vector is actually in the
|
||||
`matrix-react-sdk` and `matrix-js-sdk` modules. It is possible to set these up
|
||||
in a way that makes it easy to track the `develop` branches in git and to make
|
||||
local changes without having to manually rebuild each time.
|
||||
The idea of Vector is to be a relatively lightweight "skin" of customisations on
|
||||
top of the underlying `matrix-react-sdk`. `matrix-react-sdk` provides both the
|
||||
higher and lower level React components useful for building Matrix communication
|
||||
apps using React.
|
||||
|
||||
[Be aware that there may be problems with this process under npm version 3.]
|
||||
After creating a new component you must run `npm run reskindex` to regenerate
|
||||
the `component-index.js` for the app (used in future for skinning)
|
||||
|
||||
**However, as of July 2016 this layering abstraction is broken due to rapid
|
||||
development on Vector forcing `matrix-react-sdk` to move fast at the expense of
|
||||
maintaining a clear abstraction between the two.** Hacking on Vector inevitably
|
||||
means hacking equally on `matrix-react-sdk`, and there are bits of
|
||||
`matrix-react-sdk` behaviour incorrectly residing in the `vector-web` project
|
||||
(e.g. matrix-react-sdk specific CSS), and a bunch of Vector specific behaviour
|
||||
in the `matrix-react-sdk` (grep for Vector). This separation problem will be
|
||||
solved asap once development on Vector (and thus matrix-react-sdk) has
|
||||
stabilised. Until then, the two projects should basically be considered as a
|
||||
single unit. In particular, `matrix-react-sdk` issues are currently filed
|
||||
against `vector-web` in github.
|
||||
|
||||
Please note that Vector is intended to run correctly without access to the public
|
||||
internet. So please don't depend on resources (JS libs, CSS, images, fonts)
|
||||
hosted by external CDNs or servers but instead please package all dependencies
|
||||
into Vector itself.
|
||||
|
||||
Setting up a dev environment
|
||||
============================
|
||||
|
||||
Much of the functionality in Vector is actually in the `matrix-react-sdk` and
|
||||
`matrix-js-sdk` modules. It is possible to set these up in a way that makes it
|
||||
easy to track the `develop` branches in git and to make local changes without
|
||||
having to manually rebuild each time.
|
||||
|
||||
First clone and build `matrix-js-sdk`:
|
||||
|
||||
@@ -102,17 +201,53 @@ Finally, build and start vector itself:
|
||||
+ 1013 hidden modules
|
||||
```
|
||||
Remember, the command will not terminate since it runs the web server
|
||||
and rebuilds source files when they change.
|
||||
and rebuilds source files when they change. This development server also
|
||||
disables caching, so do NOT use it in production.
|
||||
1. Open http://127.0.0.1:8080/ in your browser to see your newly built Vector.
|
||||
|
||||
When you make changes to `matrix-js-sdk` or `matrix-react-sdk`, you will need
|
||||
to run `npm run build` in the relevant directory. You can do this automatically
|
||||
by instead running `npm start` in each directory, to start a development
|
||||
builder which will watch for changes to the files and rebuild automatically.
|
||||
When you make changes to `matrix-react-sdk`, you will need to run `npm run
|
||||
build` in the relevant directory. You can do this automatically by instead
|
||||
running `npm start` in the directory, to start a development builder which
|
||||
will watch for changes to the files and rebuild automatically.
|
||||
|
||||
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`.
|
||||
|
||||
If any of these steps error with, `file table overflow`, you are probably on a mac
|
||||
which has a very low limit on max open files. Run `ulimit -Sn 1024` and try again.
|
||||
You'll need to do this in each new terminal you open before building vector.
|
||||
|
||||
Filing issues
|
||||
=============
|
||||
|
||||
All issues for Vector-web and Matrix-react-sdk should be filed at
|
||||
https://github.com/matrix-org/matrix-react-sdk/issues
|
||||
|
||||
Triaging issues
|
||||
===============
|
||||
|
||||
Issues will be triaged by the core team using the following primary set of tags:
|
||||
|
||||
priority:
|
||||
P1: top priority; typically blocks releases.
|
||||
P2: one below that
|
||||
P3: non-urgent
|
||||
P4/P5: bluesky some day, who knows.
|
||||
|
||||
bug or feature:
|
||||
bug severity:
|
||||
* cosmetic - feature works functionally but UI/UX is broken.
|
||||
* critical - whole app doesn't work
|
||||
* major - entire feature doesn't work
|
||||
* minor - partially broken feature (but still usable)
|
||||
|
||||
* release blocker
|
||||
|
||||
* ui/ux (think of this as cosmetic)
|
||||
|
||||
* network (specific to network conditions)
|
||||
* platform (platform specific)
|
||||
|
||||
Enabling encryption
|
||||
===================
|
||||
|
||||
@@ -121,23 +256,14 @@ 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.
|
||||
|
||||
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.
|
||||
|
||||
To enable encryption for a room, type
|
||||
|
||||
```
|
||||
/encrypt on
|
||||
```
|
||||
|
||||
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`.)
|
||||
To enable the (very experimental) support, check the 'End-to-End Encryption'
|
||||
box in the 'Labs' section of the user settings (note that the labs are disabled
|
||||
on http://vector.im/beta: you will need to use http://vector.im/develop or your
|
||||
own deployment of vector). The Room Settings dialog will then show an
|
||||
'Encryption' setting; rooms for which you are an administrator will offer you
|
||||
the option of enabling encryption. Any messages sent in that room will then be
|
||||
encrypted.
|
||||
|
||||
Note that historical encrypted messages cannot currently be decoded - history
|
||||
is therefore lost when the page is reloaded.
|
||||
|
||||
There is currently no visual indication of whether encryption is enabled for a
|
||||
room, or whether a particular message was encrypted.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"default_hs_url": "https://matrix.org",
|
||||
"default_is_url": "https://vector.im",
|
||||
"brand": "Vector",
|
||||
"integrations_ui_url": "http://localhost:8081/",
|
||||
"integrations_rest_url": "http://localhost:5050"
|
||||
}
|
||||
+14
-4
@@ -5,8 +5,8 @@ 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
|
||||
arg_jenkins_url, arg_extract_path, arg_should_clean, arg_symlink, arg_config_location = (
|
||||
None, None, None, None, None
|
||||
)
|
||||
|
||||
def download_file(url):
|
||||
@@ -122,6 +122,9 @@ def on_receive_jenkins_poke():
|
||||
|
||||
create_symlink(source=os.path.join(untar_location, "vector"), linkname=arg_symlink)
|
||||
|
||||
if arg_config_location:
|
||||
create_symlink(source=arg_config_location, linkname=os.path.join(untar_location, "vector", 'config.json'))
|
||||
|
||||
return jsonify({})
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -154,6 +157,12 @@ if __name__ == "__main__":
|
||||
to the /vector directory INSIDE the tarball."
|
||||
)
|
||||
)
|
||||
parser.add_argument(
|
||||
"--config", dest="config", help=(
|
||||
"Write a symlink to config.json in the extracted tarball. \
|
||||
To this location."
|
||||
)
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if args.jenkins.endswith("/"): # important for urljoin
|
||||
arg_jenkins_url = args.jenkins
|
||||
@@ -162,9 +171,10 @@ if __name__ == "__main__":
|
||||
arg_extract_path = args.extract
|
||||
arg_should_clean = args.clean
|
||||
arg_symlink = args.symlink
|
||||
arg_config_location = args.config
|
||||
print(
|
||||
"Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s" %
|
||||
"Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Config location: %s" %
|
||||
(args.port, arg_extract_path,
|
||||
" (clean after)" if arg_should_clean else "", arg_symlink, arg_jenkins_url)
|
||||
" (clean after)" if arg_should_clean else "", arg_symlink, arg_jenkins_url, arg_config_location)
|
||||
)
|
||||
app.run(host="0.0.0.0", port=args.port, debug=True)
|
||||
|
||||
+10
-1
@@ -4,12 +4,21 @@ set -e
|
||||
|
||||
export NVM_DIR="/home/jenkins/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
||||
nvm use 4
|
||||
nvm use 6
|
||||
|
||||
set -x
|
||||
|
||||
npm install
|
||||
|
||||
# apparently npm 3.10.3 on node 6.4.0 doesn't upgrade #develop target with npm install unless explicitly asked.
|
||||
npm install matrix-react-sdk matrix-js-sdk
|
||||
|
||||
# install olm. A naive 'npm i ./olm/olm-*.tgz' fails because it uses the url
|
||||
# from our package.json (or even matrix-js-sdk's) in preference.
|
||||
tar -C olm -xz < olm/olm-*.tgz
|
||||
rm -r node_modules/olm
|
||||
cp -r olm/package node_modules/olm
|
||||
|
||||
# we may be using a dev branch of react-sdk, in which case we need to build it
|
||||
(cd node_modules/matrix-react-sdk && npm run build)
|
||||
|
||||
|
||||
+8
-2
@@ -27,6 +27,7 @@ module.exports = function (config) {
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'node_modules/babel-polyfill/browser.js',
|
||||
testFile,
|
||||
{pattern: 'vector/img/*', watched: false, included: false, served: true, nocache: false},
|
||||
],
|
||||
@@ -35,7 +36,7 @@ module.exports = function (config) {
|
||||
proxies: {
|
||||
"/img/": "/base/vector/img/",
|
||||
},
|
||||
|
||||
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors:
|
||||
// https://npmjs.org/browse/keyword/karma-preprocessor
|
||||
@@ -122,7 +123,7 @@ module.exports = function (config) {
|
||||
|
||||
// same goes for js-sdk
|
||||
"matrix-js-sdk": path.resolve('./node_modules/matrix-js-sdk'),
|
||||
|
||||
|
||||
sinon: 'sinon/pkg/sinon.js',
|
||||
},
|
||||
root: [
|
||||
@@ -130,6 +131,11 @@ module.exports = function (config) {
|
||||
path.resolve('./test'),
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// olm may not be installed, so avoid webpack warnings by
|
||||
// ignoring it.
|
||||
new webpack.IgnorePlugin(/^olm$/),
|
||||
],
|
||||
devtool: 'inline-source-map',
|
||||
},
|
||||
});
|
||||
|
||||
+30
-16
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vector-web",
|
||||
"version": "0.7.2",
|
||||
"version": "0.8.3",
|
||||
"description": "Vector webapp",
|
||||
"author": "matrix.org",
|
||||
"repository": {
|
||||
@@ -12,53 +12,64 @@
|
||||
"matrix-react-parent": "matrix-react-sdk",
|
||||
"scripts": {
|
||||
"reskindex": "reskindex -h src/header",
|
||||
"build:emojione": "cpx \"node_modules/emojione/assets/svg/*\" vector/emojione/svg/",
|
||||
"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:bundle:dev": "NODE_ENV=production webpack --optimize-occurence-order lib/vector/index.js vector/bundle.js",
|
||||
"build": "npm run build:css && npm run build:compile && npm run build:bundle",
|
||||
"build:dev": "npm run build:css && npm run build:compile && npm run build:bundle:dev",
|
||||
"build:bundle:dev": "webpack --optimize-occurence-order lib/vector/index.js vector/bundle.js",
|
||||
"build:staticfiles": "cpx -v node_modules/olm/olm.js vector/",
|
||||
"build": "npm run build:staticfiles && npm run build:emojione && npm run build:css && npm run build:compile && npm run build:bundle",
|
||||
"build:dev": "npm run build:staticfiles && npm run build:emojione && npm run build:css && npm run build:compile && npm run build:bundle:dev",
|
||||
"package": "scripts/package.sh",
|
||||
"start:emojione": "cpx \"node_modules/emojione/assets/svg/*\" vector/emojione/svg/ -w",
|
||||
"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",
|
||||
"start:staticfiles": "cpx -Lwv node_modules/olm/olm.js vector/",
|
||||
"//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*",
|
||||
"start": "parallelshell \"npm run start:staticfiles\" \"npm run start:emojione\" \"npm run start:js\" \"npm run start:skins:css\" \"http-server -c 1 vector\"",
|
||||
"start:prod": "parallelshell \"npm run start:staticfiles\" \"npm run start:emojione\" \"npm run start:js:prod\" \"npm run start:skins:css\" \"http-server -c 1 vector\"",
|
||||
"clean": "rimraf lib vector/olm.js vector/bundle.css vector/bundle.js vector/bundle.js.map vector/webpack.css* vector/emojione",
|
||||
"prepublish": "npm run build:css && npm run build:compile",
|
||||
"test": "karma start --single-run=true --autoWatch=false --browsers PhantomJS --colors=false",
|
||||
"test:multi": "karma start"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.5.0",
|
||||
"browser-request": "^0.3.3",
|
||||
"classnames": "^2.1.2",
|
||||
"draft-js": "^0.8.1",
|
||||
"extract-text-webpack-plugin": "^0.9.1",
|
||||
"filesize": "^3.1.2",
|
||||
"flux": "~2.0.3",
|
||||
"gemini-scrollbar": "matrix-org/gemini-scrollbar#87ebaa7",
|
||||
"gemini-scrollbar": "matrix-org/gemini-scrollbar#b302279",
|
||||
"gfm.css": "^1.1.1",
|
||||
"highlight.js": "^9.0.0",
|
||||
"linkifyjs": "^2.0.0-beta.4",
|
||||
"matrix-js-sdk": "^0.5.4",
|
||||
"matrix-react-sdk": "^0.6.2",
|
||||
"linkifyjs": "^2.1.3",
|
||||
"matrix-js-sdk": "0.6.3",
|
||||
"matrix-react-sdk": "0.7.4",
|
||||
"modernizr": "^3.1.0",
|
||||
"q": "^1.4.1",
|
||||
"react": "^15.0.1",
|
||||
"react": "^15.2.1",
|
||||
"react-dnd": "^2.1.4",
|
||||
"react-dnd-html5-backend": "^2.1.2",
|
||||
"react-dom": "^15.0.1",
|
||||
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#c3d942e",
|
||||
"sanitize-html": "^1.11.1"
|
||||
"react-dom": "^15.2.1",
|
||||
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
|
||||
"sanitize-html": "^1.11.1",
|
||||
"ua-parser-js": "^0.7.10",
|
||||
"url": "^0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^5.8.23",
|
||||
"babel-core": "^5.8.25",
|
||||
"babel-loader": "^5.3.2",
|
||||
"catw": "^1.0.1",
|
||||
"cpx": "^1.3.2",
|
||||
"css-raw-loader": "^0.1.1",
|
||||
"emojione": "^2.2.3",
|
||||
"expect": "^1.16.0",
|
||||
"fs-extra": "^0.30.0",
|
||||
"http-server": "^0.8.4",
|
||||
"json-loader": "^0.5.3",
|
||||
"karma": "^0.13.22",
|
||||
@@ -72,10 +83,13 @@
|
||||
"mocha": "^2.4.5",
|
||||
"parallelshell": "^1.2.0",
|
||||
"phantomjs-prebuilt": "^2.1.7",
|
||||
"react-addons-test-utils": "^15.0.1",
|
||||
"react-addons-perf": "^15.0",
|
||||
"react-addons-test-utils": "^15.0.1",
|
||||
"rimraf": "^2.4.3",
|
||||
"source-map-loader": "^0.1.5",
|
||||
"webpack": "^1.12.14"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"olm": "https://matrix.org/packages/npm/olm/olm-1.3.0.tgz"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,11 @@ module.exports.components['structures.RoomDirectory'] = require('./components/st
|
||||
module.exports.components['structures.RoomSubList'] = require('./components/structures/RoomSubList');
|
||||
module.exports.components['structures.SearchBox'] = require('./components/structures/SearchBox');
|
||||
module.exports.components['structures.ViewSource'] = require('./components/structures/ViewSource');
|
||||
module.exports.components['views.context_menus.MessageContextMenu'] = require('./components/views/context_menus/MessageContextMenu');
|
||||
module.exports.components['views.context_menus.NotificationStateContextMenu'] = require('./components/views/context_menus/NotificationStateContextMenu');
|
||||
module.exports.components['views.context_menus.RoomTagContextMenu'] = require('./components/views/context_menus/RoomTagContextMenu');
|
||||
module.exports.components['views.dialogs.ChangelogDialog'] = require('./components/views/dialogs/ChangelogDialog');
|
||||
module.exports.components['views.directory.NetworkDropdown'] = require('./components/views/directory/NetworkDropdown');
|
||||
module.exports.components['views.elements.ImageView'] = require('./components/views/elements/ImageView');
|
||||
module.exports.components['views.elements.Spinner'] = require('./components/views/elements/Spinner');
|
||||
module.exports.components['views.globals.GuestWarningBar'] = require('./components/views/globals/GuestWarningBar');
|
||||
@@ -44,11 +49,9 @@ module.exports.components['views.login.VectorLoginFooter'] = require('./componen
|
||||
module.exports.components['views.login.VectorLoginHeader'] = require('./components/views/login/VectorLoginHeader');
|
||||
module.exports.components['views.messages.DateSeparator'] = require('./components/views/messages/DateSeparator');
|
||||
module.exports.components['views.messages.MessageTimestamp'] = require('./components/views/messages/MessageTimestamp');
|
||||
module.exports.components['views.messages.SenderProfile'] = require('./components/views/messages/SenderProfile');
|
||||
module.exports.components['views.rooms.BottomLeftMenuTile'] = require('./components/views/rooms/BottomLeftMenuTile');
|
||||
module.exports.components['views.rooms.MessageContextMenu'] = require('./components/views/rooms/MessageContextMenu');
|
||||
module.exports.components['views.rooms.RoomDNDView'] = require('./components/views/rooms/RoomDNDView');
|
||||
module.exports.components['views.rooms.DNDRoomTile'] = require('./components/views/rooms/DNDRoomTile');
|
||||
module.exports.components['views.rooms.RoomDropTarget'] = require('./components/views/rooms/RoomDropTarget');
|
||||
module.exports.components['views.rooms.RoomTooltip'] = require('./components/views/rooms/RoomTooltip');
|
||||
module.exports.components['views.rooms.SearchBar'] = require('./components/views/rooms/SearchBar');
|
||||
module.exports.components['views.settings.IntegrationsManager'] = require('./components/views/settings/IntegrationsManager');
|
||||
module.exports.components['views.settings.Notifications'] = require('./components/views/settings/Notifications');
|
||||
|
||||
@@ -17,48 +17,105 @@ limitations under the License.
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactDOM = require('react-dom');
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'BottomLeftMenu',
|
||||
|
||||
propTypes: {
|
||||
collapsed: React.PropTypes.bool.isRequired,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return({
|
||||
directoryHover : false,
|
||||
roomsHover : false,
|
||||
peopleHover : false,
|
||||
settingsHover : false,
|
||||
});
|
||||
},
|
||||
|
||||
// Room events
|
||||
onDirectoryClick: function() {
|
||||
dis.dispatch({ action: 'view_room_directory' });
|
||||
},
|
||||
|
||||
onDirectoryMouseEnter: function() {
|
||||
this.setState({ directoryHover: true });
|
||||
},
|
||||
|
||||
onDirectoryMouseLeave: function() {
|
||||
this.setState({ directoryHover: false });
|
||||
},
|
||||
|
||||
onRoomsClick: function() {
|
||||
dis.dispatch({ action: 'view_create_room' });
|
||||
},
|
||||
|
||||
onRoomsMouseEnter: function() {
|
||||
this.setState({ roomsHover: true });
|
||||
},
|
||||
|
||||
onRoomsMouseLeave: function() {
|
||||
this.setState({ roomsHover: false });
|
||||
},
|
||||
|
||||
// People events
|
||||
onPeopleClick: function() {
|
||||
dis.dispatch({ action: 'view_create_chat' });
|
||||
},
|
||||
|
||||
onPeopleMouseEnter: function() {
|
||||
this.setState({ peopleHover: true });
|
||||
},
|
||||
|
||||
onPeopleMouseLeave: function() {
|
||||
this.setState({ peopleHover: false });
|
||||
},
|
||||
|
||||
// Settings events
|
||||
onSettingsClick: function() {
|
||||
dis.dispatch({action: 'view_user_settings'});
|
||||
dis.dispatch({ action: 'view_user_settings' });
|
||||
},
|
||||
|
||||
onRoomDirectoryClick: function() {
|
||||
dis.dispatch({action: 'view_room_directory'});
|
||||
onSettingsMouseEnter: function() {
|
||||
this.setState({ settingsHover: true });
|
||||
},
|
||||
|
||||
onCreateRoomClick: function() {
|
||||
dis.dispatch({action: 'view_create_room'});
|
||||
onSettingsMouseLeave: function() {
|
||||
this.setState({ settingsHover: false });
|
||||
},
|
||||
|
||||
getLabel: function(name) {
|
||||
if (!this.props.collapsed) {
|
||||
return <div className="mx_RoomTile_name">{name}</div>
|
||||
}
|
||||
else if (this.state.hover) {
|
||||
// Get the label/tooltip to show
|
||||
getLabel: function(label, show) {
|
||||
if (show) {
|
||||
var RoomTooltip = sdk.getComponent("rooms.RoomTooltip");
|
||||
return <RoomTooltip name={name}/>;
|
||||
return <RoomTooltip className="mx_BottomLeftMenu_tooltip" label={label} />;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var BottomLeftMenuTile = sdk.getComponent('rooms.BottomLeftMenuTile');
|
||||
var TintableSvg = sdk.getComponent('elements.TintableSvg');
|
||||
return (
|
||||
<div className="mx_BottomLeftMenu">
|
||||
<div className="mx_BottomLeftMenu_options">
|
||||
<div className="mx_BottomLeftMenu_createRoom" title="Start chat" onClick={ this.onCreateRoomClick }>
|
||||
<TintableSvg src="img/icons-create-room.svg" width="24" height="24"/>
|
||||
<div className="mx_BottomLeftMenu_people" onClick={ this.onPeopleClick } onMouseEnter={ this.onPeopleMouseEnter } onMouseLeave={ this.onPeopleMouseLeave } >
|
||||
<TintableSvg src="img/icons-people.svg" width="25" height="25" />
|
||||
{ this.getLabel("Start chat", this.state.peopleHover) }
|
||||
</div>
|
||||
<div className="mx_BottomLeftMenu_directory" title="Room directory" onClick={ this.onRoomDirectoryClick }>
|
||||
<TintableSvg src="img/icons-directory.svg" width="24" height="24"/>
|
||||
<div className="mx_BottomLeftMenu_directory" onClick={ this.onDirectoryClick } onMouseEnter={ this.onDirectoryMouseEnter } onMouseLeave={ this.onDirectoryMouseLeave } >
|
||||
<TintableSvg src="img/icons-directory.svg" width="25" height="25"/>
|
||||
{ this.getLabel("Room directory", this.state.directoryHover) }
|
||||
</div>
|
||||
<div className="mx_BottomLeftMenu_settings" title="Settings" onClick={ this.onSettingsClick }>
|
||||
<TintableSvg src="img/icons-settings.svg" width="24" height="24"/>
|
||||
<div className="mx_BottomLeftMenu_createRoom" onClick={ this.onRoomsClick } onMouseEnter={ this.onRoomsMouseEnter } onMouseLeave={ this.onRoomsMouseLeave } >
|
||||
<TintableSvg src="img/icons-create-room.svg" width="25" height="25" />
|
||||
{ this.getLabel("Create new room", this.state.roomsHover) }
|
||||
</div>
|
||||
<div className="mx_BottomLeftMenu_settings" onClick={ this.onSettingsClick } onMouseEnter={ this.onSettingsMouseEnter } onMouseLeave={ this.onSettingsMouseLeave } >
|
||||
<TintableSvg src="img/icons-settings.svg" width="25" height="25" />
|
||||
{ this.getLabel("Settings", this.state.settingsHover) }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,14 +39,14 @@ module.exports = React.createClass({
|
||||
return (
|
||||
<div className="mx_CompatibilityPage">
|
||||
<div className="mx_CompatibilityPage_box">
|
||||
<p>Sorry, your browser is <b>not</b> able to run Vector.</p>
|
||||
<p>Sorry, your browser is <b>not</b> able to run Riot.</p>
|
||||
<p>
|
||||
Vector uses many advanced browser features, some of which are not
|
||||
Riot uses many advanced browser features, some of which are not
|
||||
available or experimental in your current browser.
|
||||
</p>
|
||||
<p>
|
||||
Please install <a href="https://www.google.com/chrome">Chrome</a> for
|
||||
the best experience. <a href="https://getfirefox.com">Firefox</a>,
|
||||
Please install <a href="https://www.google.com/chrome">Chrome</a> or
|
||||
<a href="https://getfirefox.com">Firefox</a> for the best experience.
|
||||
<a href="http://apple.com/safari">Safari</a> and
|
||||
<a href="http://opera.com">Opera</a> work too.
|
||||
</p>
|
||||
|
||||
@@ -109,7 +109,7 @@ var LeftPanel = React.createClass({
|
||||
var CallView = sdk.getComponent('voip.CallView');
|
||||
callPreview = (
|
||||
<CallView
|
||||
className="mx_LeftPanel_callView" onClick={this.onCallViewClick}
|
||||
className="mx_LeftPanel_callView" showVoice={true} onClick={this.onCallViewClick}
|
||||
ConferenceHandler={VectorConferenceHandler} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,17 +17,26 @@ limitations under the License.
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var sdk = require('matrix-react-sdk');
|
||||
var Matrix = require("matrix-js-sdk");
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
|
||||
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');
|
||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RightPanel',
|
||||
|
||||
propTypes: {
|
||||
userId: React.PropTypes.string, // if showing an orphaned MemberInfo page, this is set
|
||||
roomId: React.PropTypes.string, // if showing panels for a given room, this is set
|
||||
collapsed: React.PropTypes.bool, // currently unused property to request for a minimized view of the panel
|
||||
},
|
||||
|
||||
Phase : {
|
||||
MemberList: 'MemberList',
|
||||
FileList: 'FileList',
|
||||
FilePanel: 'FilePanel',
|
||||
NotificationPanel: 'NotificationPanel',
|
||||
MemberInfo: 'MemberInfo',
|
||||
},
|
||||
|
||||
@@ -45,13 +54,22 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
phase : this.Phase.MemberList
|
||||
if (this.props.userId) {
|
||||
var member = new Matrix.RoomMember(null, this.props.userId);
|
||||
return {
|
||||
phase: this.Phase.MemberInfo,
|
||||
member: member,
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
phase: this.Phase.MemberList
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onMemberListButtonClick: function() {
|
||||
if (this.props.collapsed) {
|
||||
if (this.props.collapsed || this.state.phase !== this.Phase.MemberList) {
|
||||
this.setState({ phase: this.Phase.MemberList });
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
@@ -64,6 +82,51 @@ module.exports = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
onFileListButtonClick: function() {
|
||||
if (this.props.collapsed || this.state.phase !== this.Phase.FilePanel) {
|
||||
this.setState({ phase: this.Phase.FilePanel });
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
}
|
||||
else {
|
||||
dis.dispatch({
|
||||
action: 'hide_right_panel',
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onNotificationListButtonClick: function() {
|
||||
if (this.props.collapsed || this.state.phase !== this.Phase.NotificationPanel) {
|
||||
this.setState({ phase: this.Phase.NotificationPanel });
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
}
|
||||
else {
|
||||
dis.dispatch({
|
||||
action: 'hide_right_panel',
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onInviteButtonClick: function() {
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
|
||||
Modal.createDialog(NeedToRegisterDialog, {
|
||||
title: "Please Register",
|
||||
description: "Guest users can't invite users. Please register to invite."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// call ChatInviteDialog
|
||||
dis.dispatch({
|
||||
action: 'view_invite',
|
||||
roomId: this.props.roomId,
|
||||
});
|
||||
},
|
||||
|
||||
onRoomStateMember: function(ev, state, member) {
|
||||
// redraw the badge on the membership list
|
||||
if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) {
|
||||
@@ -97,7 +160,7 @@ module.exports = React.createClass({
|
||||
});
|
||||
}
|
||||
}
|
||||
if (payload.action === "view_room") {
|
||||
else if (payload.action === "view_room") {
|
||||
if (this.state.phase === this.Phase.MemberInfo) {
|
||||
this.setState({
|
||||
phase: this.Phase.MemberList
|
||||
@@ -108,52 +171,86 @@ module.exports = React.createClass({
|
||||
|
||||
render: function() {
|
||||
var MemberList = sdk.getComponent('rooms.MemberList');
|
||||
var NotificationPanel = sdk.getComponent('structures.NotificationPanel');
|
||||
var FilePanel = sdk.getComponent('structures.FilePanel');
|
||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||
var buttonGroup;
|
||||
var inviteGroup;
|
||||
var panel;
|
||||
|
||||
var filesHighlight;
|
||||
var membersHighlight;
|
||||
var notificationsHighlight;
|
||||
if (!this.props.collapsed) {
|
||||
if (this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) {
|
||||
membersHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
|
||||
}
|
||||
else if (this.state.phase == this.Phase.FileList) {
|
||||
else if (this.state.phase == this.Phase.FilePanel) {
|
||||
filesHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
|
||||
}
|
||||
else if (this.state.phase == this.Phase.NotificationPanel) {
|
||||
notificationsHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
|
||||
}
|
||||
}
|
||||
|
||||
var membersBadge;
|
||||
if ((this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) && this.props.roomId) {
|
||||
var cli = MatrixClientPeg.get();
|
||||
var room = cli.getRoom(this.props.roomId);
|
||||
var user_is_in_room;
|
||||
if (room) {
|
||||
membersBadge = <div className="mx_RightPanel_headerButton_badge">{ room.getJoinedMembers().length }</div>;
|
||||
membersBadge = room.getJoinedMembers().length;
|
||||
user_is_in_room = room.hasMembershipState(
|
||||
MatrixClientPeg.get().credentials.userId, 'join'
|
||||
);
|
||||
}
|
||||
|
||||
if (user_is_in_room) {
|
||||
inviteGroup =
|
||||
<div className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } >
|
||||
<div className="mx_RightPanel_icon" >
|
||||
<TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />
|
||||
</div>
|
||||
<div className="mx_RightPanel_message">Invite to this room</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.props.roomId) {
|
||||
buttonGroup =
|
||||
<div className="mx_RightPanel_headerButtonGroup">
|
||||
<div className="mx_RightPanel_headerButton" title="Members" onClick={ this.onMemberListButtonClick }>
|
||||
<TintableSvg src="img/members.svg" width="17" height="22"/>
|
||||
{ membersBadge }
|
||||
<div className="mx_RightPanel_headerButton_badge">{ membersBadge ? membersBadge : <span> </span>}</div>
|
||||
<TintableSvg src="img/icons-people.svg" width="25" height="25"/>
|
||||
{ membersHighlight }
|
||||
</div>
|
||||
<div className="mx_RightPanel_headerButton mx_RightPanel_filebutton" title="Files">
|
||||
<TintableSvg src="img/files.svg" width="17" height="22"/>
|
||||
<div className="mx_RightPanel_headerButton mx_RightPanel_filebutton" title="Files" onClick={ this.onFileListButtonClick }>
|
||||
<div className="mx_RightPanel_headerButton_badge"> </div>
|
||||
<TintableSvg src="img/icons-files.svg" width="25" height="25"/>
|
||||
{ filesHighlight }
|
||||
</div>
|
||||
<div className="mx_RightPanel_headerButton mx_RightPanel_notificationbutton" title="Notifications" onClick={ this.onNotificationListButtonClick }>
|
||||
<div className="mx_RightPanel_headerButton_badge"> </div>
|
||||
<TintableSvg src="img/icons-notifications.svg" width="25" height="25"/>
|
||||
{ notificationsHighlight }
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
if (!this.props.collapsed) {
|
||||
if(this.state.phase == this.Phase.MemberList) {
|
||||
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
||||
}
|
||||
else if(this.state.phase == this.Phase.MemberInfo) {
|
||||
var MemberInfo = sdk.getComponent('rooms.MemberInfo');
|
||||
panel = <MemberInfo roomId={this.props.roomId} member={this.state.member} key={this.props.roomId} />
|
||||
}
|
||||
if (!this.props.collapsed) {
|
||||
if(this.props.roomId && this.state.phase == this.Phase.MemberList) {
|
||||
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
||||
}
|
||||
else if(this.state.phase == this.Phase.MemberInfo) {
|
||||
var MemberInfo = sdk.getComponent('rooms.MemberInfo');
|
||||
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.props.userId} />
|
||||
}
|
||||
else if (this.state.phase == this.Phase.NotificationPanel) {
|
||||
panel = <NotificationPanel />
|
||||
}
|
||||
else if (this.state.phase == this.Phase.FilePanel) {
|
||||
panel = <FilePanel roomId={this.props.roomId} />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +270,7 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
{ panel }
|
||||
<div className="mx_RightPanel_footer">
|
||||
{ inviteGroup }
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ var React = require('react');
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var ContentRepo = require("matrix-js-sdk").ContentRepo;
|
||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var sdk = require('matrix-react-sdk');
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
var GeminiScrollbar = require('react-gemini-scrollbar');
|
||||
|
||||
@@ -29,21 +29,72 @@ var linkify = require('linkifyjs');
|
||||
var linkifyString = require('linkifyjs/string');
|
||||
var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix');
|
||||
var sanitizeHtml = require('sanitize-html');
|
||||
var q = require('q');
|
||||
|
||||
linkifyMatrix(linkify);
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomDirectory',
|
||||
|
||||
propTypes: {
|
||||
config: React.PropTypes.object,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
config: {
|
||||
networks: [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
publicRooms: [],
|
||||
roomAlias: '',
|
||||
loading: true,
|
||||
network: null,
|
||||
roomServer: null,
|
||||
filterString: null,
|
||||
}
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
// precompile Regexps
|
||||
this.portalRoomPatterns = {};
|
||||
this.nativePatterns = {};
|
||||
if (this.props.config.networks) {
|
||||
for (const network of Object.keys(this.props.config.networks)) {
|
||||
const network_info = this.props.config.networks[network];
|
||||
if (network_info.portalRoomPattern) {
|
||||
this.portalRoomPatterns[network] = new RegExp(network_info.portalRoomPattern);
|
||||
}
|
||||
if (network_info.nativePattern) {
|
||||
this.nativePatterns[network] = new RegExp(network_info.nativePattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.nextBatch = null;
|
||||
this.filterTimeout = null;
|
||||
this.scrollPanel = null;
|
||||
this.protocols = null;
|
||||
|
||||
MatrixClientPeg.get().getThirdpartyProtocols().done((response) => {
|
||||
this.protocols = response;
|
||||
}, (err) => {
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
// Guests currently aren't allowed to use this API, so
|
||||
// ignore this as otherwise this error is literally the
|
||||
// thing you see when loading the client!
|
||||
return;
|
||||
}
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to get protocol list from Home Server",
|
||||
description: "The Home Server may be too old to support third party networks",
|
||||
});
|
||||
});
|
||||
|
||||
// dis.dispatch({
|
||||
// action: 'ui_opacity',
|
||||
// sideOpacity: 0.3,
|
||||
@@ -51,28 +102,6 @@ module.exports = React.createClass({
|
||||
// });
|
||||
},
|
||||
|
||||
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));
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to get public room list",
|
||||
description: err.message
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.setState({
|
||||
publicRooms: data.chunk,
|
||||
loading: false,
|
||||
});
|
||||
self.forceUpdate();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
// dis.dispatch({
|
||||
// action: 'ui_opacity',
|
||||
@@ -81,20 +110,229 @@ module.exports = React.createClass({
|
||||
// });
|
||||
},
|
||||
|
||||
showRoom: function(roomId) {
|
||||
// extract the metadata from the publicRooms structure to pass
|
||||
// as out-of-band data to view_room, because we get information
|
||||
// here that we can't get other than by joining the room in some
|
||||
// cases.
|
||||
var room;
|
||||
for (var i = 0; i < this.state.publicRooms.length; ++i) {
|
||||
if (this.state.publicRooms[i].room_id == roomId) {
|
||||
room = this.state.publicRooms[i];
|
||||
break;
|
||||
}
|
||||
refreshRoomList: function() {
|
||||
this.nextBatch = null;
|
||||
this.setState({
|
||||
publicRooms: [],
|
||||
loading: true,
|
||||
});
|
||||
this.getMoreRooms().done();
|
||||
},
|
||||
|
||||
getMoreRooms: function() {
|
||||
if (!MatrixClientPeg.get()) return q();
|
||||
|
||||
const my_filter_string = this.state.filterString;
|
||||
const my_server = this.state.roomServer;
|
||||
// remember the next batch token when we sent the request
|
||||
// too. If it's changed, appending to the list will corrupt it.
|
||||
const my_next_batch = this.nextBatch;
|
||||
const opts = {limit: 20};
|
||||
if (my_server != MatrixClientPeg.getHomeServerName()) {
|
||||
opts.server = my_server;
|
||||
}
|
||||
var oob_data = {};
|
||||
if (this.nextBatch) opts.since = this.nextBatch;
|
||||
if (my_filter_string) opts.filter = { generic_search_term: my_filter_string } ;
|
||||
return MatrixClientPeg.get().publicRooms(opts).then((data) => {
|
||||
if (
|
||||
my_filter_string != this.state.filterString ||
|
||||
my_server != this.state.roomServer ||
|
||||
my_next_batch != this.nextBatch)
|
||||
{
|
||||
// if the filter or server has changed since this request was sent,
|
||||
// throw away the result (don't even clear the busy flag
|
||||
// since we must still have a request in flight)
|
||||
return;
|
||||
}
|
||||
|
||||
this.nextBatch = data.next_batch;
|
||||
this.setState((s) => {
|
||||
s.publicRooms.push(...data.chunk);
|
||||
s.loading = false;
|
||||
return s;
|
||||
});
|
||||
return Boolean(data.next_batch);
|
||||
}, (err) => {
|
||||
if (
|
||||
my_filter_string != this.state.filterString ||
|
||||
my_server != this.state.roomServer ||
|
||||
my_next_batch != this.nextBatch)
|
||||
{
|
||||
// as above: we don't care about errors for old
|
||||
// requests either
|
||||
return;
|
||||
}
|
||||
this.setState({ loading: false });
|
||||
console.error("Failed to get publicRooms: %s", JSON.stringify(err));
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to get public room list",
|
||||
description: err.message
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* A limited interface for removing rooms from the directory.
|
||||
* Will set the room to not be publicly visible and delete the
|
||||
* default alias. In the long term, it would be better to allow
|
||||
* HS admins to do this through the RoomSettings interface, but
|
||||
* this needs SPEC-417.
|
||||
*/
|
||||
removeFromDirectory: function(room) {
|
||||
var alias = get_display_alias_for_room(room);
|
||||
var name = room.name || alias || "Unnamed room";
|
||||
|
||||
var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
|
||||
var desc;
|
||||
if (alias) {
|
||||
desc = `Delete the room alias '${alias}' and remove '${name}' from the directory?`;
|
||||
} else {
|
||||
desc = `Remove '${name}' from the directory?`;
|
||||
}
|
||||
|
||||
Modal.createDialog(QuestionDialog, {
|
||||
title: "Remove from Directory",
|
||||
description: desc,
|
||||
onFinished: (should_delete) => {
|
||||
if (!should_delete) return;
|
||||
|
||||
var Loader = sdk.getComponent("elements.Spinner");
|
||||
var modal = Modal.createDialog(Loader);
|
||||
var step = `remove '${name}' from the directory.`;
|
||||
|
||||
MatrixClientPeg.get().setRoomDirectoryVisibility(room.room_id, 'private').then(() => {
|
||||
if (!alias) return;
|
||||
step = 'delete the alias.';
|
||||
return MatrixClientPeg.get().deleteAlias(alias);
|
||||
}).done(() => {
|
||||
modal.close();
|
||||
this.refreshRoomList();
|
||||
}, function(err) {
|
||||
modal.close();
|
||||
this.refreshRoomList();
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to "+step,
|
||||
description: err.toString()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onRoomClicked: function(room, ev) {
|
||||
if (ev.shiftKey) {
|
||||
ev.preventDefault();
|
||||
this.removeFromDirectory(room);
|
||||
} else {
|
||||
this.showRoom(room);
|
||||
}
|
||||
},
|
||||
|
||||
onOptionChange: function(server, network) {
|
||||
// clear next batch so we don't try to load more rooms
|
||||
this.nextBatch = null;
|
||||
this.setState({
|
||||
// Clear the public rooms out here otherwise we needlessly
|
||||
// spend time filtering lots of rooms when we're about to
|
||||
// to clear the list anyway.
|
||||
publicRooms: [],
|
||||
roomServer: server,
|
||||
network: network,
|
||||
}, this.refreshRoomList);
|
||||
// We also refresh the room list each time even though this
|
||||
// filtering is client-side. It hopefully won't be client side
|
||||
// for very long, and we may have fetched a thousand rooms to
|
||||
// find the five gitter ones, at which point we do not want
|
||||
// to render all those rooms when switching back to 'all networks'.
|
||||
// Easiest to just blow away the state & re-fetch.
|
||||
},
|
||||
|
||||
onFillRequest: function(backwards) {
|
||||
if (backwards || !this.nextBatch) return q(false);
|
||||
|
||||
return this.getMoreRooms();
|
||||
},
|
||||
|
||||
onFilterChange: function(alias) {
|
||||
this.setState({
|
||||
filterString: alias || null,
|
||||
});
|
||||
|
||||
// don't send the request for a little bit,
|
||||
// no point hammering the server with a
|
||||
// request for every keystroke, let the
|
||||
// user finish typing.
|
||||
if (this.filterTimeout) {
|
||||
clearTimeout(this.filterTimeout);
|
||||
}
|
||||
this.filterTimeout = setTimeout(() => {
|
||||
this.filterTimeout = null;
|
||||
this.refreshRoomList();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
onFilterClear: function() {
|
||||
// update immediately
|
||||
this.setState({
|
||||
filterString: null,
|
||||
}, this.refreshRoomList);
|
||||
|
||||
if (this.filterTimeout) {
|
||||
clearTimeout(this.filterTimeout);
|
||||
}
|
||||
},
|
||||
|
||||
onJoinClick: function(alias) {
|
||||
// If we're on the 'Matrix' network (or all networks),
|
||||
// just show that rooms alias
|
||||
if (this.state.network == null || this.state.network == '_matrix') {
|
||||
this.showRoomAlias(alias);
|
||||
} else {
|
||||
// This is a 3rd party protocol. Let's see if we
|
||||
// can join it
|
||||
const fields = this._getFieldsForThirdPartyLocation(alias, this.state.network);
|
||||
if (!fields) {
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Unable to join network",
|
||||
description: "Riot does not know how to join a room on this network",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const protocol = this._protocolForThirdPartyNetwork(this.state.network);
|
||||
MatrixClientPeg.get().getThirdpartyLocation(protocol, fields).done((resp) => {
|
||||
if (resp.length > 0 && resp[0].alias) {
|
||||
this.showRoomAlias(resp[0].alias);
|
||||
} else {
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Room not found",
|
||||
description: "Couldn't find a matching Matrix room",
|
||||
});
|
||||
}
|
||||
}, (e) => {
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Fetching third party location failed",
|
||||
description: "Unable to look up room ID from server",
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
showRoomAlias: function(alias) {
|
||||
this.showRoom(null, alias);
|
||||
},
|
||||
|
||||
showRoom: function(room, room_alias) {
|
||||
var payload = {action: 'view_room'};
|
||||
if (room) {
|
||||
// Don't let the user view a room they won't be able to either
|
||||
// peek or join: fail earlier so they don't have to click back
|
||||
// to the directory.
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
if (!room.world_readable && !room.guest_can_join) {
|
||||
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
|
||||
@@ -106,41 +344,46 @@ module.exports = React.createClass({
|
||||
}
|
||||
}
|
||||
|
||||
oob_data = {
|
||||
if (!room_alias) {
|
||||
room_alias = get_display_alias_for_room(room);
|
||||
}
|
||||
|
||||
payload.oob_data = {
|
||||
avatarUrl: room.avatar_url,
|
||||
// XXX: This logic is duplicated from the JS SDK which
|
||||
// would normally decide what the name is.
|
||||
name: room.name || room.canonical_alias || (room.aliases ? room.aliases[0] : "Unnamed room"),
|
||||
name: room.name || room_alias || "Unnamed room",
|
||||
};
|
||||
}
|
||||
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: roomId,
|
||||
oob_data: oob_data,
|
||||
});
|
||||
// It's not really possible to join Matrix rooms by ID because the HS has no way to know
|
||||
// which servers to start querying. However, there's no other way to join rooms in
|
||||
// this list without aliases at present, so if roomAlias isn't set here we have no
|
||||
// choice but to supply the ID.
|
||||
if (room_alias) {
|
||||
payload.room_alias = room_alias;
|
||||
} else {
|
||||
payload.room_id = room.room_id;
|
||||
}
|
||||
dis.dispatch(payload);
|
||||
},
|
||||
|
||||
getRows: function(filter) {
|
||||
getRows: function() {
|
||||
var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||
|
||||
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.name && a.name.toLowerCase().search(filter.toLowerCase()) >= 0) ||
|
||||
(a.aliases && a.aliases[0].toLowerCase().search(filter.toLowerCase()) >= 0)) &&
|
||||
a.num_joined_members > 0);
|
||||
}).sort(function(a,b) {
|
||||
return a.num_joined_members - b.num_joined_members;
|
||||
var rooms = this.state.publicRooms.filter((a) => {
|
||||
if (this.state.network) {
|
||||
if (!this._isRoomInNetwork(a, this.state.roomServer, this.state.network)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
var rows = [];
|
||||
var self = this;
|
||||
var guestRead, guestJoin, perms;
|
||||
for (var i = 0; i < rooms.length; i++) {
|
||||
var alias = rooms[i].canonical_alias || (rooms[i].aliases ? rooms[i].aliases[0] : "");
|
||||
var name = rooms[i].name || alias || "Unnamed room";
|
||||
var name = rooms[i].name || get_display_alias_for_room(rooms[i]) || "Unnamed room";
|
||||
guestRead = null;
|
||||
guestJoin = null;
|
||||
|
||||
@@ -163,8 +406,12 @@ module.exports = React.createClass({
|
||||
var topic = rooms[i].topic || '';
|
||||
topic = linkifyString(sanitizeHtml(topic));
|
||||
|
||||
rows.unshift(
|
||||
<tr key={ rooms[i].room_id } onClick={self.showRoom.bind(null, rooms[i].room_id)}>
|
||||
rows.push(
|
||||
<tr key={ rooms[i].room_id }
|
||||
onClick={self.onRoomClicked.bind(self, rooms[i])}
|
||||
// cancel onMouseDown otherwise shift-clicking highlights text
|
||||
onMouseDown={(ev) => {ev.preventDefault();}}
|
||||
>
|
||||
<td className="mx_RoomDirectory_roomAvatar">
|
||||
<BaseAvatar width={24} height={24} resizeMethod='crop'
|
||||
name={ name } idName={ name }
|
||||
@@ -178,7 +425,7 @@ module.exports = React.createClass({
|
||||
<div className="mx_RoomDirectory_topic"
|
||||
onClick={ function(e) { e.stopPropagation() } }
|
||||
dangerouslySetInnerHTML={{ __html: topic }}/>
|
||||
<div className="mx_RoomDirectory_alias">{ alias }</div>
|
||||
<div className="mx_RoomDirectory_alias">{ get_display_alias_for_room(rooms[i]) }</div>
|
||||
</td>
|
||||
<td className="mx_RoomDirectory_roomMemberCount">
|
||||
{ rooms[i].num_joined_members }
|
||||
@@ -189,40 +436,196 @@ module.exports = React.createClass({
|
||||
return rows;
|
||||
},
|
||||
|
||||
onKeyUp: function(ev) {
|
||||
this.forceUpdate();
|
||||
this.setState({ roomAlias : this.refs.roomAlias.value })
|
||||
if (ev.key == "Enter") {
|
||||
this.showRoom(this.refs.roomAlias.value);
|
||||
collectScrollPanel: function(element) {
|
||||
this.scrollPanel = element;
|
||||
},
|
||||
|
||||
/**
|
||||
* Terrible temporary function that guess what network a public room
|
||||
* entry is in, until synapse is able to tell us
|
||||
*/
|
||||
_isRoomInNetwork: function(room, server, network) {
|
||||
// We carve rooms into two categories here. 'portal' rooms are
|
||||
// rooms created by a user joining a bridge 'portal' alias to
|
||||
// participate in that room or a foreign network. A room is a
|
||||
// portal room if it has exactly one alias and that alias matches
|
||||
// a pattern defined in the config. Its network is the key
|
||||
// of the pattern that it matches.
|
||||
// All other rooms are considered 'native matrix' rooms, and
|
||||
// go into the special '_matrix' network.
|
||||
|
||||
let roomNetwork = '_matrix';
|
||||
if (room.aliases && room.aliases.length == 1) {
|
||||
if (this.props.config.serverConfig && this.props.config.serverConfig[server] && this.props.config.serverConfig[server].networks) {
|
||||
for (const n of this.props.config.serverConfig[server].networks) {
|
||||
const pat = this.portalRoomPatterns[n];
|
||||
if (pat && pat.test(room.aliases[0])) {
|
||||
roomNetwork = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return roomNetwork == network;
|
||||
},
|
||||
|
||||
_stringLooksLikeId: function(s, network) {
|
||||
let pat = /^#[^\s]+:[^\s]/;
|
||||
if (
|
||||
network && network != '_matrix' &&
|
||||
this.nativePatterns[network]
|
||||
) {
|
||||
pat = this.nativePatterns[network];
|
||||
}
|
||||
|
||||
return pat.test(s);
|
||||
},
|
||||
|
||||
_protocolForThirdPartyNetwork: function(network) {
|
||||
if (
|
||||
this.props.config.networks &&
|
||||
this.props.config.networks[network] &&
|
||||
this.props.config.networks[network].protocol
|
||||
) {
|
||||
return this.props.config.networks[network].protocol;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.loading) {
|
||||
var Loader = sdk.getComponent("elements.Spinner");
|
||||
return (
|
||||
<div className="mx_RoomDirectory">
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
_getFieldsForThirdPartyLocation: function(user_input, network) {
|
||||
if (!this.props.config.networks || !this.props.config.networks[network]) return null;
|
||||
|
||||
const network_info = this.props.config.networks[network];
|
||||
if (!network_info.protocol) return null;
|
||||
|
||||
if (!this.protocols) return null;
|
||||
|
||||
let matched_instance;
|
||||
// Try to find which instance in the 'protocols' response
|
||||
// matches this network. We look for a matching protocol
|
||||
// and the existence of a 'domain' field and if present,
|
||||
// its value.
|
||||
if (
|
||||
this.protocols[network_info.protocol] &&
|
||||
this.protocols[network_info.protocol].instances &&
|
||||
this.protocols[network_info.protocol].instances.length == 1
|
||||
) {
|
||||
const the_instance = this.protocols[network_info.protocol].instances[0];
|
||||
// If there's only one instance in this protocol, use it
|
||||
// as long as it has no domain (which we assume to mean it's
|
||||
// there is only one possible instance).
|
||||
if (
|
||||
(
|
||||
the_instance.fields.domain === undefined &&
|
||||
network_info.domain === undefined
|
||||
) ||
|
||||
(
|
||||
the_instance.fields.domain !== undefined &&
|
||||
the_instance.fields.domain == network_info.domain
|
||||
)
|
||||
) {
|
||||
matched_instance = the_instance;
|
||||
}
|
||||
} else if (network_info.domain) {
|
||||
// otherwise, we look for one with a matching domain.
|
||||
for (const this_instance of this.protocols[network_info.protocol].instances) {
|
||||
if (this_instance.fields.domain == network_info.domain) {
|
||||
matched_instance = this_instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
||||
if (matched_instance === undefined) return null;
|
||||
|
||||
// now make an object with the fields specified by that protocol. We
|
||||
// require that the values of all but the last field come from the
|
||||
// instance. The last is the user input.
|
||||
const required_fields = this.protocols[network_info.protocol].location_fields;
|
||||
const fields = {};
|
||||
for (let i = 0; i < required_fields.length - 1; ++i) {
|
||||
const this_field = required_fields[i];
|
||||
if (matched_instance.fields[this_field] === undefined) return null;
|
||||
fields[this_field] = matched_instance.fields[this_field];
|
||||
}
|
||||
fields[required_fields[required_fields.length - 1]] = user_input;
|
||||
return fields;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
let content;
|
||||
if (this.state.loading) {
|
||||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
content = <div className="mx_RoomDirectory">
|
||||
<Loader />
|
||||
</div>;
|
||||
} else {
|
||||
const rows = this.getRows();
|
||||
// we still show the scrollpanel, at least for now, because
|
||||
// otherwise we don't fetch more because we don't get a fill
|
||||
// request from the scrollpanel because there isn't one
|
||||
let scrollpanel_content;
|
||||
if (rows.length == 0) {
|
||||
scrollpanel_content = <i>No rooms to show</i>;
|
||||
} else {
|
||||
scrollpanel_content = <table ref="directory_table" className="mx_RoomDirectory_table">
|
||||
<tbody>
|
||||
{ this.getRows() }
|
||||
</tbody>
|
||||
</table>;
|
||||
}
|
||||
const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
|
||||
content = <ScrollPanel ref={this.collectScrollPanel}
|
||||
className="mx_RoomDirectory_tableWrapper"
|
||||
onFillRequest={ this.onFillRequest }
|
||||
stickyBottom={false}
|
||||
startAtBottom={false}
|
||||
onResize={function(){}}
|
||||
>
|
||||
{ scrollpanel_content }
|
||||
</ScrollPanel>;
|
||||
}
|
||||
|
||||
let placeholder = 'Search for a room';
|
||||
if (this.state.network === null || this.state.network === '_matrix') {
|
||||
placeholder = '#example:' + this.state.roomServer;
|
||||
} else if (
|
||||
this.props.config.networks &&
|
||||
this.props.config.networks[this.state.network] &&
|
||||
this.props.config.networks[this.state.network].example &&
|
||||
this._getFieldsForThirdPartyLocation(this.state.filterString, this.state.network)
|
||||
) {
|
||||
placeholder = this.props.config.networks[this.state.network].example;
|
||||
}
|
||||
|
||||
let showJoinButton = this._stringLooksLikeId(this.state.filterString, this.state.network);
|
||||
if (this.state.network && this.state.network != '_matrix') {
|
||||
if (this._getFieldsForThirdPartyLocation(this.state.filterString, this.state.network) === null) {
|
||||
showJoinButton = false;
|
||||
}
|
||||
}
|
||||
|
||||
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
||||
const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown');
|
||||
const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
|
||||
return (
|
||||
<div className="mx_RoomDirectory">
|
||||
<SimpleRoomHeader title="Directory" />
|
||||
<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 }/>
|
||||
<GeminiScrollbar className="mx_RoomDirectory_tableWrapper"
|
||||
relayoutOnUpdate={false} >
|
||||
<table ref="directory_table" className="mx_RoomDirectory_table">
|
||||
<tbody>
|
||||
{ this.getRows(this.state.roomAlias) }
|
||||
</tbody>
|
||||
</table>
|
||||
</GeminiScrollbar>
|
||||
<div className="mx_RoomDirectory_listheader">
|
||||
<DirectorySearchBox
|
||||
className="mx_RoomDirectory_searchbox"
|
||||
onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
|
||||
placeholder={placeholder} showJoinButton={showJoinButton}
|
||||
/>
|
||||
<NetworkDropdown config={this.props.config} onOptionChange={this.onOptionChange} />
|
||||
</div>
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Similar to matrix-react-sdk's MatrixTools.getDisplayAliasForRoom
|
||||
// but works with the objects we get from the public room list
|
||||
function get_display_alias_for_room(room) {
|
||||
return room.canonical_alias || (room.aliases ? room.aliases[0] : "");
|
||||
}
|
||||
|
||||
@@ -17,15 +17,21 @@ limitations under the License.
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactDOM = require('react-dom');
|
||||
var classNames = require('classnames');
|
||||
var DropTarget = require('react-dnd').DropTarget;
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
var Unread = require('matrix-react-sdk/lib/Unread');
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
|
||||
var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
|
||||
|
||||
// turn this on for drop & drag console debugging galore
|
||||
var debug = false;
|
||||
|
||||
const TRUNCATE_AT = 10;
|
||||
|
||||
var roomListTarget = {
|
||||
canDrop: function() {
|
||||
return true;
|
||||
@@ -61,8 +67,12 @@ var RoomSubList = React.createClass({
|
||||
label: React.PropTypes.string.isRequired,
|
||||
tagName: React.PropTypes.string,
|
||||
editable: React.PropTypes.bool,
|
||||
|
||||
order: React.PropTypes.string.isRequired,
|
||||
selectedRoom: React.PropTypes.string.isRequired,
|
||||
|
||||
// undefined if no room is selected (eg we are showing settings)
|
||||
selectedRoom: React.PropTypes.string,
|
||||
|
||||
startAsHidden: React.PropTypes.bool,
|
||||
showSpinner: React.PropTypes.bool, // true to show a spinner if 0 elements when expanded
|
||||
collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed?
|
||||
@@ -76,7 +86,7 @@ var RoomSubList = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
hidden: this.props.startAsHidden || false,
|
||||
truncateAt: 20,
|
||||
truncateAt: TRUNCATE_AT,
|
||||
sortedList: [],
|
||||
};
|
||||
},
|
||||
@@ -105,17 +115,34 @@ var RoomSubList = React.createClass({
|
||||
});
|
||||
},
|
||||
|
||||
onClick: function(ev) {
|
||||
var isHidden = !this.state.hidden;
|
||||
this.setState({ hidden : isHidden });
|
||||
|
||||
if (isHidden) {
|
||||
// as good a way as any to reset the truncate state
|
||||
this.setState({ truncateAt : 20 });
|
||||
this.props.onShowMoreRooms();
|
||||
// The header is collapsable if it is hidden or not stuck
|
||||
// The dataset elements are added in the RoomList _initAndPositionStickyHeaders method
|
||||
isCollapsableOnClick: function() {
|
||||
var stuck = this.refs.header.dataset.stuck;
|
||||
if (this.state.hidden || stuck === undefined || stuck === "none") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
this.props.onHeaderClick(isHidden);
|
||||
onClick: function(ev) {
|
||||
if (this.isCollapsableOnClick()) {
|
||||
// The header isCollapsable, so the click is to be interpreted as collapse and truncation logic
|
||||
var isHidden = !this.state.hidden;
|
||||
this.setState({ hidden : isHidden });
|
||||
|
||||
if (isHidden) {
|
||||
// as good a way as any to reset the truncate state
|
||||
this.setState({ truncateAt : TRUNCATE_AT });
|
||||
}
|
||||
|
||||
this.props.onShowMoreRooms();
|
||||
this.props.onHeaderClick(isHidden);
|
||||
} else {
|
||||
// The header is stuck, so the click is to be interpreted as a scroll to the header
|
||||
this.props.onHeaderClick(this.state.hidden, this.refs.header.dataset.originalPosition);
|
||||
}
|
||||
},
|
||||
|
||||
tsOfNewestEvent: function(room) {
|
||||
@@ -145,11 +172,26 @@ var RoomSubList = React.createClass({
|
||||
return this.tsOfNewestEvent(roomB) - this.tsOfNewestEvent(roomA);
|
||||
},
|
||||
|
||||
lexicographicalComparator: function(roomA, roomB) {
|
||||
return roomA.name > roomB.name ? 1 : -1;
|
||||
},
|
||||
|
||||
// Generates the manual comparator using the given list
|
||||
manualComparator: function(roomA, roomB) {
|
||||
if (!roomA.tags[this.props.tagName] || !roomB.tags[this.props.tagName]) return 0;
|
||||
|
||||
// Make sure the room tag has an order element, if not set it to be the bottom
|
||||
var a = roomA.tags[this.props.tagName].order;
|
||||
var b = roomB.tags[this.props.tagName].order;
|
||||
return a == b ? this.recentsComparator(roomA, roomB) : ( a > b ? 1 : -1);
|
||||
|
||||
// Order undefined room tag orders to the bottom
|
||||
if (a === undefined && b !== undefined) {
|
||||
return 1;
|
||||
} else if (a !== undefined && b === undefined) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return a == b ? this.lexicographicalComparator(roomA, roomB) : ( a > b ? 1 : -1);
|
||||
},
|
||||
|
||||
sortList: function(list, order) {
|
||||
@@ -160,10 +202,59 @@ var RoomSubList = React.createClass({
|
||||
if (order === "manual") comparator = this.manualComparator;
|
||||
if (order === "recent") comparator = this.recentsComparator;
|
||||
|
||||
// Fix undefined orders here, and make sure the backend gets updated as well
|
||||
this._fixUndefinedOrder(list);
|
||||
|
||||
//if (debug) console.log("sorting list for sublist " + this.props.label + " with length " + list.length + ", this.props.list = " + this.props.list);
|
||||
this.setState({ sortedList: list.sort(comparator) });
|
||||
},
|
||||
|
||||
_shouldShowNotifBadge: function(roomNotifState) {
|
||||
const showBadgeInStates = [RoomNotifs.ALL_MESSAGES, RoomNotifs.ALL_MESSAGES_LOUD];
|
||||
return showBadgeInStates.indexOf(roomNotifState) > -1;
|
||||
},
|
||||
|
||||
_shouldShowMentionBadge: function(roomNotifState) {
|
||||
return roomNotifState != RoomNotifs.MUTE;
|
||||
},
|
||||
|
||||
/**
|
||||
* Total up all the notification counts from the rooms
|
||||
*
|
||||
* @param {Number} If supplied will only total notifications for rooms outside the truncation number
|
||||
* @returns {Array} The array takes the form [total, highlight] where highlight is a bool
|
||||
*/
|
||||
roomNotificationCount: function(truncateAt) {
|
||||
var self = this;
|
||||
|
||||
return this.props.list.reduce(function(result, room, index) {
|
||||
if (truncateAt === undefined || index >= truncateAt) {
|
||||
var roomNotifState = RoomNotifs.getRoomNotifsState(room.roomId);
|
||||
var highlight = room.getUnreadNotificationCount('highlight') > 0 || self.props.label === 'Invites';
|
||||
var notificationCount = room.getUnreadNotificationCount();
|
||||
|
||||
const notifBadges = notificationCount > 0 && self._shouldShowNotifBadge(roomNotifState);
|
||||
const mentionBadges = highlight && self._shouldShowMentionBadge(roomNotifState);
|
||||
const badges = notifBadges || mentionBadges;
|
||||
|
||||
if (badges) {
|
||||
result[0] += notificationCount;
|
||||
if (highlight) {
|
||||
result[1] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}, [0, false]);
|
||||
},
|
||||
|
||||
_updateSubListCount: function() {
|
||||
// Force an update by setting the state to the current state
|
||||
// Doing it this way rather than using forceUpdate(), so that the shouldComponentUpdate()
|
||||
// method is honoured
|
||||
this.setState(this.state);
|
||||
},
|
||||
|
||||
moveRoomTile: function(room, atIndex) {
|
||||
if (debug) console.log("moveRoomTile: id " + room.roomId + ", atIndex " + atIndex);
|
||||
//console.log("moveRoomTile before: " + JSON.stringify(this.state.rooms));
|
||||
@@ -257,12 +348,12 @@ var RoomSubList = React.createClass({
|
||||
|
||||
makeRoomTiles: function() {
|
||||
var self = this;
|
||||
var RoomTile = sdk.getComponent("rooms.RoomTile");
|
||||
var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile");
|
||||
return this.state.sortedList.map(function(room) {
|
||||
var selected = room.roomId == self.props.selectedRoom;
|
||||
// XXX: is it evil to pass in self as a prop to RoomTile?
|
||||
return (
|
||||
<RoomTile
|
||||
<DNDRoomTile
|
||||
room={ room }
|
||||
roomSubList={ self }
|
||||
key={ room.roomId }
|
||||
@@ -271,32 +362,95 @@ var RoomSubList = React.createClass({
|
||||
unread={ Unread.doesRoomHaveUnreadMessages(room) }
|
||||
highlight={ room.getUnreadNotificationCount('highlight') > 0 || self.props.label === 'Invites' }
|
||||
isInvite={ self.props.label === 'Invites' }
|
||||
incomingCall={ self.props.incomingCall && (self.props.incomingCall.roomId === room.roomId) ? self.props.incomingCall : null } />
|
||||
refreshSubList={ self._updateSubListCount }
|
||||
incomingCall={ null } />
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
_getHeaderJsx: function() {
|
||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||
|
||||
var subListNotifications = this.roomNotificationCount();
|
||||
var subListNotifCount = subListNotifications[0];
|
||||
var subListNotifHighlight = subListNotifications[1];
|
||||
|
||||
var roomCount = this.props.list.length > 0 ? this.props.list.length : '';
|
||||
|
||||
var chevronClasses = classNames({
|
||||
'mx_RoomSubList_chevron': true,
|
||||
'mx_RoomSubList_chevronRight': this.state.hidden,
|
||||
'mx_RoomSubList_chevronDown': !this.state.hidden,
|
||||
});
|
||||
|
||||
var badgeClasses = classNames({
|
||||
'mx_RoomSubList_badge': true,
|
||||
'mx_RoomSubList_badgeHighlight': subListNotifHighlight,
|
||||
});
|
||||
|
||||
var badge;
|
||||
if (subListNotifCount > 0) {
|
||||
badge = <div className={badgeClasses}>{ FormattingUtils.formatCount(subListNotifCount) }</div>;
|
||||
}
|
||||
|
||||
// When collapsed, allow a long hover on the header to show user
|
||||
// the full tag name and room count
|
||||
var title;
|
||||
if (this.props.collapsed) {
|
||||
title = this.props.label;
|
||||
if (roomCount !== '') {
|
||||
title += " [" + roomCount + "]";
|
||||
}
|
||||
}
|
||||
|
||||
var incomingCall;
|
||||
if (this.props.incomingCall) {
|
||||
var self = this;
|
||||
// Check if the incoming call is for this section
|
||||
var incomingCallRoom = this.state.sortedList.filter(function(room) {
|
||||
return self.props.incomingCall.roomId === room.roomId;
|
||||
});
|
||||
|
||||
if (incomingCallRoom.length === 1) {
|
||||
var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
|
||||
incomingCall = <IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={ this.props.incomingCall }/>;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<h2 onClick={ this.onClick } className="mx_RoomSubList_label">
|
||||
{ this.props.collapsed ? '' : this.props.label }
|
||||
<img className="mx_RoomSubList_chevron"
|
||||
src={ this.state.hidden ? "img/list-close.svg" : "img/list-open.svg" }
|
||||
width="10" height="10" />
|
||||
</h2>
|
||||
<div className="mx_RoomSubList_labelContainer" title={ title } ref="header">
|
||||
<div onClick={ this.onClick } className="mx_RoomSubList_label">
|
||||
{ this.props.collapsed ? '' : this.props.label }
|
||||
<div className="mx_RoomSubList_roomCount">{ roomCount }</div>
|
||||
<div className={chevronClasses}></div>
|
||||
{ badge }
|
||||
{ incomingCall }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
_createOverflowTile: function(overflowCount, totalCount) {
|
||||
var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||
// XXX: this is duplicated from RoomTile - factor it out
|
||||
var content = <div className="mx_RoomSubList_chevronDown"></div>;
|
||||
|
||||
var overflowNotifications = this.roomNotificationCount(TRUNCATE_AT);
|
||||
var overflowNotifCount = overflowNotifications[0];
|
||||
var overflowNotifHighlight = overflowNotifications[1];
|
||||
if (overflowNotifCount && !this.props.collapsed) {
|
||||
content = FormattingUtils.formatCount(overflowNotifCount);
|
||||
}
|
||||
|
||||
var badgeClasses = classNames({
|
||||
'mx_RoomSubList_moreBadge': true,
|
||||
'mx_RoomSubList_moreBadgeNotify': overflowNotifCount && !this.props.collapsed,
|
||||
'mx_RoomSubList_moreBadgeHighlight': overflowNotifHighlight && !this.props.collapsed,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mx_RoomTile mx_RoomTile_ellipsis" onClick={this._showFullMemberList}>
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<BaseAvatar url="img/ellipsis.svg" name="..." width={24} height={24} />
|
||||
</div>
|
||||
<div className="mx_RoomTile_name">and { overflowCount } others...</div>
|
||||
<div className="mx_RoomSubList_ellipsis" onClick={this._showFullMemberList}>
|
||||
<div className="mx_RoomSubList_line"></div>
|
||||
<div className="mx_RoomSubList_more">more</div>
|
||||
<div className={ badgeClasses }>{ content }</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -305,7 +459,49 @@ var RoomSubList = React.createClass({
|
||||
this.setState({
|
||||
truncateAt: -1
|
||||
});
|
||||
|
||||
this.props.onShowMoreRooms();
|
||||
this.props.onHeaderClick(false);
|
||||
},
|
||||
|
||||
// Fix any undefined order elements of a room in a manual ordered list
|
||||
// room.tag[tagname].order
|
||||
_fixUndefinedOrder: function(list) {
|
||||
if (this.props.order === "manual") {
|
||||
var order = 0.0;
|
||||
var self = this;
|
||||
|
||||
// Find the highest (lowest position) order of a room in a manual ordered list
|
||||
list.forEach(function(room) {
|
||||
if (room.tags.hasOwnProperty(self.props.tagName)) {
|
||||
if (order < room.tags[self.props.tagName].order) {
|
||||
order = room.tags[self.props.tagName].order;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Fix any undefined order elements of a room in a manual ordered list
|
||||
// Do this one at a time, as each time a rooms tag data is updated the RoomList
|
||||
// gets triggered and another list is passed in. Doing it one at a time means that
|
||||
// we always correctly calculate the highest order for the list - stops multiple
|
||||
// rooms getting the same order. This is only really relevant for the first time this
|
||||
// is run with historical room tag data, after that there should only be undefined
|
||||
// in the list at a time anyway.
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (list[i].tags[self.props.tagName] && list[i].tags[self.props.tagName].order === undefined) {
|
||||
MatrixClientPeg.get().setRoomTag(list[i].roomId, self.props.tagName, {order: (order + 1.0) / 2.0}).finally(function() {
|
||||
// Do any final stuff here
|
||||
}).fail(function(err) {
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to add tag " + self.props.tagName + " to room",
|
||||
description: err.toString()
|
||||
});
|
||||
});
|
||||
break;
|
||||
};
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
@@ -94,7 +94,7 @@ module.exports = React.createClass({
|
||||
<TintableSvg
|
||||
key="button"
|
||||
className="mx_SearchBox_searchButton"
|
||||
src="img/right_search.svg" width="24" height="24"
|
||||
src="img/icons-search-copy.svg" width="13" height="13"
|
||||
/>,
|
||||
<input
|
||||
key="searchfield"
|
||||
@@ -103,7 +103,7 @@ module.exports = React.createClass({
|
||||
className="mx_SearchBox_search"
|
||||
value={ this.state.searchTerm }
|
||||
onChange={ this.onChange }
|
||||
placeholder="Search room names"
|
||||
placeholder="Filter room names"
|
||||
/>
|
||||
];
|
||||
}
|
||||
|
||||
+26
-11
@@ -20,9 +20,10 @@ var React = require('react');
|
||||
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var sdk = require('matrix-react-sdk');
|
||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
||||
var Resend = require("matrix-react-sdk/lib/Resend");
|
||||
import * as UserSettingsStore from 'matrix-react-sdk/lib/UserSettingsStore';
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MessageContextMenu',
|
||||
@@ -47,7 +48,7 @@ module.exports = React.createClass({
|
||||
var ViewSource = sdk.getComponent('structures.ViewSource');
|
||||
Modal.createDialog(ViewSource, {
|
||||
mxEvent: this.props.mxEvent
|
||||
});
|
||||
}, 'mx_Dialog_viewsource');
|
||||
if (this.props.onFinished) this.props.onFinished();
|
||||
},
|
||||
|
||||
@@ -84,6 +85,14 @@ module.exports = React.createClass({
|
||||
if (this.props.onFinished) this.props.onFinished();
|
||||
},
|
||||
|
||||
onQuoteClick: function () {
|
||||
console.log(this.props.mxEvent);
|
||||
dis.dispatch({
|
||||
action: 'quote',
|
||||
event: this.props.mxEvent,
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var eventStatus = this.props.mxEvent.status;
|
||||
var resendButton;
|
||||
@@ -95,7 +104,7 @@ module.exports = React.createClass({
|
||||
|
||||
if (eventStatus === 'not_sent') {
|
||||
resendButton = (
|
||||
<div className="mx_ContextualMenu_field" onClick={this.onResendClick}>
|
||||
<div className="mx_MessageContextMenu_field" onClick={this.onResendClick}>
|
||||
Resend
|
||||
</div>
|
||||
);
|
||||
@@ -103,7 +112,7 @@ module.exports = React.createClass({
|
||||
|
||||
if (!eventStatus) { // sent
|
||||
redactButton = (
|
||||
<div className="mx_ContextualMenu_field" onClick={this.onRedactClick}>
|
||||
<div className="mx_MessageContextMenu_field" onClick={this.onRedactClick}>
|
||||
Redact
|
||||
</div>
|
||||
);
|
||||
@@ -111,14 +120,14 @@ module.exports = React.createClass({
|
||||
|
||||
if (eventStatus === "queued" || eventStatus === "not_sent") {
|
||||
cancelButton = (
|
||||
<div className="mx_ContextualMenu_field" onClick={this.onCancelSendClick}>
|
||||
<div className="mx_MessageContextMenu_field" onClick={this.onCancelSendClick}>
|
||||
Cancel Sending
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
viewSourceButton = (
|
||||
<div className="mx_ContextualMenu_field" onClick={this.onViewSourceClick}>
|
||||
<div className="mx_MessageContextMenu_field" onClick={this.onViewSourceClick}>
|
||||
View Source
|
||||
</div>
|
||||
);
|
||||
@@ -126,19 +135,24 @@ module.exports = React.createClass({
|
||||
if (this.props.eventTileOps) {
|
||||
if (this.props.eventTileOps.isWidgetHidden()) {
|
||||
unhidePreviewButton = (
|
||||
<div className="mx_ContextualMenu_field" onClick={this.onUnhidePreviewClick}>
|
||||
<div className="mx_MessageContextMenu_field" onClick={this.onUnhidePreviewClick}>
|
||||
Unhide Preview
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: this should be https://matrix.to.
|
||||
// XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID)
|
||||
permalinkButton = (
|
||||
<div className="mx_ContextualMenu_field">
|
||||
<a href={ "#/room/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId() }
|
||||
onClick={ this.onPermalinkClick }>Permalink</a>
|
||||
<div className="mx_MessageContextMenu_field">
|
||||
<a href={ "https://matrix.to/#/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId() }
|
||||
target="_blank" onClick={ this.onPermalinkClick }>Permalink</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
const quoteButton = (
|
||||
<div className="mx_MessageContextMenu_field" onClick={this.onQuoteClick}>
|
||||
Quote
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -150,6 +164,7 @@ module.exports = React.createClass({
|
||||
{viewSourceButton}
|
||||
{unhidePreviewButton}
|
||||
{permalinkButton}
|
||||
{UserSettingsStore.isFeatureEnabled('rich_text_editor') ? quoteButton : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
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 React = require('react');
|
||||
var classNames = require('classnames');
|
||||
var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'NotificationStateContextMenu',
|
||||
|
||||
propTypes: {
|
||||
room: React.PropTypes.object.isRequired,
|
||||
/* callback called when the menu is dismissed */
|
||||
onFinished: React.PropTypes.func,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
roomNotifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
|
||||
}
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this._unmounted = false;
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this._unmounted = true;
|
||||
},
|
||||
|
||||
_save: function(newState) {
|
||||
const oldState = this.state.roomNotifState;
|
||||
const roomId = this.props.room.roomId;
|
||||
var cli = MatrixClientPeg.get();
|
||||
|
||||
if (cli.isGuest()) return;
|
||||
|
||||
this.setState({
|
||||
roomNotifState: newState,
|
||||
});
|
||||
RoomNotifs.setRoomNotifsState(this.props.room.roomId, newState).done(() => {
|
||||
// delay slightly so that the user can see their state change
|
||||
// before closing the menu
|
||||
return q.delay(500).then(() => {
|
||||
if (this._unmounted) return;
|
||||
// Close the context menu
|
||||
if (this.props.onFinished) {
|
||||
this.props.onFinished();
|
||||
};
|
||||
});
|
||||
}, (error) => {
|
||||
// TODO: some form of error notification to the user
|
||||
// to inform them that their state change failed.
|
||||
// For now we at least set the state back
|
||||
if (this._unmounted) return;
|
||||
this.setState({
|
||||
roomNotifState: oldState,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_onClickAlertMe: function() {
|
||||
this._save(RoomNotifs.ALL_MESSAGES_LOUD);
|
||||
},
|
||||
|
||||
_onClickAllNotifs: function() {
|
||||
this._save(RoomNotifs.ALL_MESSAGES);
|
||||
},
|
||||
|
||||
_onClickMentions: function() {
|
||||
this._save(RoomNotifs.MENTIONS_ONLY);
|
||||
},
|
||||
|
||||
_onClickMute: function() {
|
||||
this._save(RoomNotifs.MUTE);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var alertMeClasses = classNames({
|
||||
'mx_NotificationStateContextMenu_field': true,
|
||||
'mx_NotificationStateContextMenu_fieldSet': this.state.roomNotifState == RoomNotifs.ALL_MESSAGES_LOUD,
|
||||
});
|
||||
|
||||
var allNotifsClasses = classNames({
|
||||
'mx_NotificationStateContextMenu_field': true,
|
||||
'mx_NotificationStateContextMenu_fieldSet': this.state.roomNotifState == RoomNotifs.ALL_MESSAGES,
|
||||
});
|
||||
|
||||
var mentionsClasses = classNames({
|
||||
'mx_NotificationStateContextMenu_field': true,
|
||||
'mx_NotificationStateContextMenu_fieldSet': this.state.roomNotifState == RoomNotifs.MENTIONS_ONLY,
|
||||
});
|
||||
|
||||
var muteNotifsClasses = classNames({
|
||||
'mx_NotificationStateContextMenu_field': true,
|
||||
'mx_NotificationStateContextMenu_fieldSet': this.state.roomNotifState == RoomNotifs.MUTE,
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mx_NotificationStateContextMenu_picker" >
|
||||
<img src="img/notif-slider.svg" width="20" height="107" />
|
||||
</div>
|
||||
<div className={ alertMeClasses } onClick={this._onClickAlertMe} >
|
||||
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
||||
<img className="mx_NotificationStateContextMenu_icon" src="img/icon-context-mute-off-copy.svg" width="16" height="12" />
|
||||
All messages (loud)
|
||||
</div>
|
||||
<div className={ allNotifsClasses } onClick={this._onClickAllNotifs} >
|
||||
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
||||
<img className="mx_NotificationStateContextMenu_icon" src="img/icon-context-mute-off.svg" width="16" height="12" />
|
||||
All messages
|
||||
</div>
|
||||
<div className={ mentionsClasses } onClick={this._onClickMentions} >
|
||||
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
||||
<img className="mx_NotificationStateContextMenu_icon" src="img/icon-context-mute-mentions.svg" width="16" height="12" />
|
||||
Mentions only
|
||||
</div>
|
||||
<div className={ muteNotifsClasses } onClick={this._onClickMute} >
|
||||
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
||||
<img className="mx_NotificationStateContextMenu_icon" src="img/icon-context-mute.svg" width="16" height="12" />
|
||||
Mute
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
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 React = require('react');
|
||||
var classNames = require('classnames');
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
var DMRoomMap = require('matrix-react-sdk/lib/utils/DMRoomMap');
|
||||
var Rooms = require('matrix-react-sdk/lib/Rooms');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomTagContextMenu',
|
||||
|
||||
propTypes: {
|
||||
room: React.PropTypes.object.isRequired,
|
||||
/* callback called when the menu is dismissed */
|
||||
onFinished: React.PropTypes.func,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
const dmRoomMap = new DMRoomMap(MatrixClientPeg.get());
|
||||
return {
|
||||
isFavourite: this.props.room.tags.hasOwnProperty("m.favourite"),
|
||||
isLowPriority: this.props.room.tags.hasOwnProperty("m.lowpriority"),
|
||||
isDirectMessage: Boolean(dmRoomMap.getUserIdForRoomId(this.props.room.roomId)),
|
||||
};
|
||||
},
|
||||
|
||||
_toggleTag: function(tagNameOn, tagNameOff) {
|
||||
var self = this;
|
||||
const roomId = this.props.room.roomId;
|
||||
var cli = MatrixClientPeg.get();
|
||||
if (!cli.isGuest()) {
|
||||
q.delay(500).then(function() {
|
||||
if (tagNameOff !== null && tagNameOff !== undefined) {
|
||||
cli.deleteRoomTag(roomId, tagNameOff).finally(function() {
|
||||
// Close the context menu
|
||||
if (self.props.onFinished) {
|
||||
self.props.onFinished();
|
||||
};
|
||||
}).fail(function(err) {
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to remove tag " + tagNameOff + " from room",
|
||||
description: err.toString()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (tagNameOn !== null && tagNameOn !== undefined) {
|
||||
// If the tag ordering meta data is required, it is added by
|
||||
// the RoomSubList when it sorts its rooms
|
||||
cli.setRoomTag(roomId, tagNameOn, {}).finally(function() {
|
||||
// Close the context menu
|
||||
if (self.props.onFinished) {
|
||||
self.props.onFinished();
|
||||
};
|
||||
}).fail(function(err) {
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to add tag " + tagNameOn + " to room",
|
||||
description: err.toString()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_onClickFavourite: function() {
|
||||
// Tag room as 'Favourite'
|
||||
if (!this.state.isFavourite && this.state.isLowPriority) {
|
||||
this.setState({
|
||||
isFavourite: true,
|
||||
isLowPriority: false,
|
||||
});
|
||||
this._toggleTag("m.favourite", "m.lowpriority");
|
||||
} else if (this.state.isFavourite) {
|
||||
this.setState({isFavourite: false});
|
||||
this._toggleTag(null, "m.favourite");
|
||||
} else if (!this.state.isFavourite) {
|
||||
this.setState({isFavourite: true});
|
||||
this._toggleTag("m.favourite");
|
||||
}
|
||||
},
|
||||
|
||||
_onClickLowPriority: function() {
|
||||
// Tag room as 'Low Priority'
|
||||
if (!this.state.isLowPriority && this.state.isFavourite) {
|
||||
this.setState({
|
||||
isFavourite: false,
|
||||
isLowPriority: true,
|
||||
});
|
||||
this._toggleTag("m.lowpriority", "m.favourite");
|
||||
} else if (this.state.isLowPriority) {
|
||||
this.setState({isLowPriority: false});
|
||||
this._toggleTag(null, "m.lowpriority");
|
||||
} else if (!this.state.isLowPriority) {
|
||||
this.setState({isLowPriority: true});
|
||||
this._toggleTag("m.lowpriority");
|
||||
}
|
||||
},
|
||||
|
||||
_onClickDM: function() {
|
||||
const newIsDirectMessage = !this.state.isDirectMessage;
|
||||
this.setState({
|
||||
isDirectMessage: newIsDirectMessage,
|
||||
});
|
||||
|
||||
if (MatrixClientPeg.get().isGuest()) return;
|
||||
|
||||
let newTarget;
|
||||
if (newIsDirectMessage) {
|
||||
const guessedTarget = Rooms.guessDMRoomTarget(
|
||||
this.props.room,
|
||||
this.props.room.getMember(MatrixClientPeg.get().credentials.userId),
|
||||
);
|
||||
newTarget = guessedTarget.userId;
|
||||
} else {
|
||||
newTarget = null;
|
||||
}
|
||||
|
||||
// give some time for the user to see the icon change first, since
|
||||
// this will hide the context menu once it completes
|
||||
q.delay(500).done(() => {
|
||||
return Rooms.setDMRoom(this.props.room.roomId, newTarget).finally(() => {
|
||||
// Close the context menu
|
||||
if (this.props.onFinished) {
|
||||
this.props.onFinished();
|
||||
};
|
||||
}, (err) => {
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to set Direct Message status of room",
|
||||
description: err.toString()
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_onClickLeave: function() {
|
||||
// Leave room
|
||||
dis.dispatch({
|
||||
action: 'leave_room',
|
||||
room_id: this.props.room.roomId,
|
||||
});
|
||||
|
||||
// Close the context menu
|
||||
if (this.props.onFinished) {
|
||||
this.props.onFinished();
|
||||
};
|
||||
},
|
||||
|
||||
_onClickForget: function() {
|
||||
// FIXME: duplicated with RoomSettings (and dead code in RoomView)
|
||||
MatrixClientPeg.get().forget(this.props.room.roomId).done(function() {
|
||||
dis.dispatch({ action: 'view_next_room' });
|
||||
}, function(err) {
|
||||
var errCode = err.errcode || "unknown error code";
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Error",
|
||||
description: `Failed to forget room (${errCode})`
|
||||
});
|
||||
});
|
||||
|
||||
// Close the context menu
|
||||
if (this.props.onFinished) {
|
||||
this.props.onFinished();
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const myUserId = MatrixClientPeg.get().credentials.userId;
|
||||
const myMember = this.props.room.getMember(myUserId);
|
||||
|
||||
const favouriteClasses = classNames({
|
||||
'mx_RoomTagContextMenu_field': true,
|
||||
'mx_RoomTagContextMenu_fieldSet': this.state.isFavourite,
|
||||
'mx_RoomTagContextMenu_fieldDisabled': false,
|
||||
});
|
||||
|
||||
const lowPriorityClasses = classNames({
|
||||
'mx_RoomTagContextMenu_field': true,
|
||||
'mx_RoomTagContextMenu_fieldSet': this.state.isLowPriority,
|
||||
'mx_RoomTagContextMenu_fieldDisabled': false,
|
||||
});
|
||||
|
||||
const leaveClasses = classNames({
|
||||
'mx_RoomTagContextMenu_field': true,
|
||||
'mx_RoomTagContextMenu_fieldSet': false,
|
||||
'mx_RoomTagContextMenu_fieldDisabled': false,
|
||||
});
|
||||
|
||||
const dmClasses = classNames({
|
||||
'mx_RoomTagContextMenu_field': true,
|
||||
'mx_RoomTagContextMenu_fieldSet': this.state.isDirectMessage,
|
||||
'mx_RoomTagContextMenu_fieldDisabled': false,
|
||||
});
|
||||
|
||||
if (myMember && myMember.membership === "leave") {
|
||||
return (
|
||||
<div>
|
||||
<div className={ leaveClasses } onClick={ this._onClickForget } >
|
||||
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_delete.svg" width="15" height="15" />
|
||||
Forget
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={ favouriteClasses } onClick={this._onClickFavourite} >
|
||||
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_fave.svg" width="15" height="15" />
|
||||
<img className="mx_RoomTagContextMenu_icon_set" src="img/icon_context_fave_on.svg" width="15" height="15" />
|
||||
Favourite
|
||||
</div>
|
||||
<div className={ lowPriorityClasses } onClick={this._onClickLowPriority} >
|
||||
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_low.svg" width="15" height="15" />
|
||||
<img className="mx_RoomTagContextMenu_icon_set" src="img/icon_context_low_on.svg" width="15" height="15" />
|
||||
Low Priority
|
||||
</div>
|
||||
<div className={ dmClasses } onClick={this._onClickDM} >
|
||||
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_person.svg" width="15" height="15" />
|
||||
<img className="mx_RoomTagContextMenu_icon_set" src="img/icon_context_person_on.svg" width="15" height="15" />
|
||||
Direct Chat
|
||||
</div>
|
||||
<hr className="mx_RoomTagContextMenu_separator" />
|
||||
<div className={ leaveClasses } onClick={(myMember && myMember.membership === "join") ? this._onClickLeave : null} >
|
||||
<img className="mx_RoomTagContextMenu_icon" src="img/icon_context_delete.svg" width="15" height="15" />
|
||||
Leave
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright 2016 Aviral Dasgupta
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import sdk from 'matrix-react-sdk';
|
||||
import request from 'browser-request';
|
||||
|
||||
const REPOS = ['vector-im/vector-web', 'matrix-org/matrix-react-sdk', 'matrix-org/matrix-js-sdk'];
|
||||
|
||||
export default class ChangelogDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const version = this.props.newVersion.split('-');
|
||||
const version2 = this.props.version.split('-');
|
||||
if(version == null || version2 == null) return;
|
||||
for(let i=0; i<REPOS.length; i++) {
|
||||
const oldVersion = version2[2*i+1];
|
||||
const newVersion = version[2*i+1];
|
||||
request(`https://api.github.com/repos/${REPOS[i]}/compare/${oldVersion}...${newVersion}`, (a, b, body) => {
|
||||
if(body == null) return;
|
||||
this.setState({[REPOS[i]]: JSON.parse(body).commits});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_elementsForCommit(commit) {
|
||||
return (
|
||||
<li key={commit.sha} className="mx_ChangelogDialog_li">
|
||||
<a href={commit.html_url} target="_blank" ref="noopener">
|
||||
{commit.commit.message}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const Spinner = sdk.getComponent('views.elements.Spinner');
|
||||
const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog');
|
||||
|
||||
const logs = REPOS.map(repo => {
|
||||
if (this.state[repo] == null) return <Spinner key={repo} />;
|
||||
return (
|
||||
<div key={repo}>
|
||||
<h2>{repo}</h2>
|
||||
<ul>
|
||||
{this.state[repo].map(this._elementsForCommit)}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
|
||||
const content = (
|
||||
<div className="mx_ChangelogDialog_content">
|
||||
{this.props.version == null || this.props.newVersion == null ? <h2>Unavailable</h2> : logs}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<QuestionDialog
|
||||
title="Changelog"
|
||||
description={content}
|
||||
button="Update"
|
||||
onFinished={this.props.onFinished}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ChangelogDialog.propTypes = {
|
||||
version: React.PropTypes.string.isRequired,
|
||||
newVersion: React.PropTypes.string.isRequired,
|
||||
onFinished: React.PropTypes.func.isRequired,
|
||||
};
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
||||
|
||||
export default class NetworkDropdown extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.dropdownRootElement = null;
|
||||
this.ignoreEvent = null;
|
||||
|
||||
this.onInputClick = this.onInputClick.bind(this);
|
||||
this.onRootClick = this.onRootClick.bind(this);
|
||||
this.onDocumentClick = this.onDocumentClick.bind(this);
|
||||
this.onMenuOptionClick = this.onMenuOptionClick.bind(this);
|
||||
this.onInputKeyUp = this.onInputKeyUp.bind(this);
|
||||
this.collectRoot = this.collectRoot.bind(this);
|
||||
this.collectInputTextBox = this.collectInputTextBox.bind(this);
|
||||
|
||||
this.inputTextBox = null;
|
||||
|
||||
const server = MatrixClientPeg.getHomeServerName();
|
||||
let defaultNetwork = null;
|
||||
if (
|
||||
this.props.config.serverConfig &&
|
||||
this.props.config.serverConfig[server] &&
|
||||
this.props.config.serverConfig[server].networks &&
|
||||
this.props.config.serverConfig[server].networks.indexOf('_matrix') > -1
|
||||
) {
|
||||
defaultNetwork = '_matrix';
|
||||
}
|
||||
|
||||
this.state = {
|
||||
expanded: false,
|
||||
selectedServer: server,
|
||||
selectedNetwork: defaultNetwork,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
// Listen for all clicks on the document so we can close the
|
||||
// menu when the user clicks somewhere else
|
||||
document.addEventListener('click', this.onDocumentClick, false);
|
||||
|
||||
// fire this now so the defaults can be set up
|
||||
this.props.onOptionChange(this.state.selectedServer, this.state.selectedNetwork);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('click', this.onDocumentClick, false);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.expanded && this.inputTextBox) {
|
||||
this.inputTextBox.focus();
|
||||
}
|
||||
}
|
||||
|
||||
onDocumentClick(ev) {
|
||||
// Close the dropdown if the user clicks anywhere that isn't
|
||||
// within our root element
|
||||
if (ev !== this.ignoreEvent) {
|
||||
this.setState({
|
||||
expanded: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onRootClick(ev) {
|
||||
// This captures any clicks that happen within our elements,
|
||||
// such that we can then ignore them when they're seen by the
|
||||
// click listener on the document handler, ie. not close the
|
||||
// dropdown immediately after opening it.
|
||||
// NB. We can't just stopPropagation() because then the event
|
||||
// doesn't reach the React onClick().
|
||||
this.ignoreEvent = ev;
|
||||
}
|
||||
|
||||
onInputClick(ev) {
|
||||
this.setState({
|
||||
expanded: !this.state.expanded,
|
||||
});
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
onMenuOptionClick(server, network, ev) {
|
||||
this.setState({
|
||||
expanded: false,
|
||||
selectedServer: server,
|
||||
selectedNetwork: network,
|
||||
});
|
||||
this.props.onOptionChange(server, network);
|
||||
}
|
||||
|
||||
onInputKeyUp(e) {
|
||||
if (e.key == 'Enter') {
|
||||
this.setState({
|
||||
expanded: false,
|
||||
selectedServer: e.target.value,
|
||||
selectedNetwork: null,
|
||||
});
|
||||
this.props.onOptionChange(e.target.value, null);
|
||||
}
|
||||
}
|
||||
|
||||
collectRoot(e) {
|
||||
if (this.dropdownRootElement) {
|
||||
this.dropdownRootElement.removeEventListener('click', this.onRootClick, false);
|
||||
}
|
||||
if (e) {
|
||||
e.addEventListener('click', this.onRootClick, false);
|
||||
}
|
||||
this.dropdownRootElement = e;
|
||||
}
|
||||
|
||||
collectInputTextBox(e) {
|
||||
this.inputTextBox = e;
|
||||
}
|
||||
|
||||
_getMenuOptions() {
|
||||
const options = [];
|
||||
|
||||
let servers = [];
|
||||
if (this.props.config.servers) {
|
||||
servers = servers.concat(this.props.config.servers);
|
||||
}
|
||||
|
||||
if (servers.indexOf(MatrixClientPeg.getHomeServerName()) == -1) {
|
||||
servers.unshift(MatrixClientPeg.getHomeServerName());
|
||||
}
|
||||
|
||||
for (const server of servers) {
|
||||
options.push(this._makeMenuOption(server, null));
|
||||
if (this.props.config.serverConfig && this.props.config.serverConfig[server] && this.props.config.serverConfig[server].networks) {
|
||||
for (const network of this.props.config.serverConfig[server].networks) {
|
||||
options.push(this._makeMenuOption(server, network));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
_makeMenuOption(server, network, wire_onclick) {
|
||||
if (wire_onclick === undefined) wire_onclick = true;
|
||||
let icon;
|
||||
let name;
|
||||
let span_class;
|
||||
|
||||
if (network === null) {
|
||||
name = server;
|
||||
span_class = 'mx_NetworkDropdown_menu_all';
|
||||
} else if (network == '_matrix') {
|
||||
name = 'Matrix';
|
||||
icon = <img src="img/network-matrix.svg" width="16" height="16" />;
|
||||
span_class = 'mx_NetworkDropdown_menu_network';
|
||||
} else {
|
||||
if (this.props.config.networks[network] === undefined) {
|
||||
throw new Error(network + ' network missing from config');
|
||||
}
|
||||
if (this.props.config.networks[network].name) {
|
||||
name = this.props.config.networks[network].name;
|
||||
} else {
|
||||
name = network;
|
||||
}
|
||||
if (this.props.config.networks[network].icon) {
|
||||
// omit height here so if people define a non-square logo in the config, it
|
||||
// will keep the aspect when it scales
|
||||
icon = <img src={this.props.config.networks[network].icon} width="16" />;
|
||||
} else {
|
||||
icon = <img src={iconPath} width="16" height="16" />;
|
||||
}
|
||||
|
||||
span_class = 'mx_NetworkDropdown_menu_network';
|
||||
}
|
||||
|
||||
const click_handler = wire_onclick ? this.onMenuOptionClick.bind(this, server, network) : null;
|
||||
|
||||
let key = server;
|
||||
if (network !== null) {
|
||||
key += '_' + network;
|
||||
}
|
||||
|
||||
return <div key={key} className="mx_NetworkDropdown_networkoption" onClick={click_handler}>
|
||||
{icon}
|
||||
<span className={span_class}>{name}</span>
|
||||
</div>;
|
||||
}
|
||||
|
||||
render() {
|
||||
let current_value;
|
||||
|
||||
let menu;
|
||||
if (this.state.expanded) {
|
||||
const menu_options = this._getMenuOptions();
|
||||
menu = <div className="mx_NetworkDropdown_menu">
|
||||
{menu_options}
|
||||
</div>;
|
||||
current_value = <input type="text" className="mx_NetworkDropdown_networkoption"
|
||||
ref={this.collectInputTextBox} onKeyUp={this.onInputKeyUp}
|
||||
placeholder="matrix.org" // 'matrix.org' as an example of an HS name
|
||||
/>
|
||||
} else {
|
||||
current_value = this._makeMenuOption(
|
||||
this.state.selectedServer, this.state.selectedNetwork, false
|
||||
);
|
||||
}
|
||||
|
||||
return <div className="mx_NetworkDropdown" ref={this.collectRoot}>
|
||||
<div className="mx_NetworkDropdown_input" onClick={this.onInputClick}>
|
||||
{current_value}
|
||||
<span className="mx_NetworkDropdown_arrow"></span>
|
||||
{menu}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkDropdown.propTypes = {
|
||||
onOptionChange: React.PropTypes.func.isRequired,
|
||||
config: React.PropTypes.object,
|
||||
};
|
||||
|
||||
NetworkDropdown.defaultProps = {
|
||||
config: {
|
||||
networks: [],
|
||||
}
|
||||
};
|
||||
|
||||
@@ -80,7 +80,7 @@ module.exports = React.createClass({
|
||||
getName: function () {
|
||||
var name = this.props.name;
|
||||
if (name && this.props.link) {
|
||||
name = <a href={ this.props.link } target="_blank">{ name }</a>;
|
||||
name = <a href={ this.props.link } target="_blank" rel="noopener">{ name }</a>;
|
||||
}
|
||||
return name;
|
||||
},
|
||||
@@ -169,7 +169,7 @@ module.exports = React.createClass({
|
||||
{ this.getName() }
|
||||
</div>
|
||||
{ eventMeta }
|
||||
<a className="mx_ImageView_link" href={ this.props.src } target="_blank">
|
||||
<a className="mx_ImageView_link" href={ this.props.src } target="_blank" rel="noopener">
|
||||
<div className="mx_ImageView_download">
|
||||
Download this file<br/>
|
||||
<span className="mx_ImageView_size">{ size_res }</span>
|
||||
|
||||
@@ -34,7 +34,7 @@ module.exports = React.createClass({
|
||||
<div className="mx_GuestWarningBar">
|
||||
<img className="mx_GuestWarningBar_warning" src="img/warning.svg" width="24" height="23" alt="/!\"/>
|
||||
<div>
|
||||
You are using Vector as a guest. <a onClick={this.onRegisterClicked}>Register</a> or <a onClick={this.onLoginClicked}>log in</a> to access more rooms and features.
|
||||
You are Rioting as a guest. <a onClick={this.onRegisterClicked}>Register</a> or <a onClick={this.onLoginClicked}>sign in</a> to access more rooms and features.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -35,7 +35,7 @@ module.exports = React.createClass({
|
||||
return (
|
||||
<div className="mx_MatrixToolbar">
|
||||
<img className="mx_MatrixToolbar_warning" src="img/warning.svg" width="24" height="23" alt="/!\"/>
|
||||
<div>
|
||||
<div className="mx_MatrixToolbar_content">
|
||||
You are not receiving desktop notifications. <a className="mx_MatrixToolbar_link" onClick={ this.onClick }>Enable them now</a>
|
||||
</div>
|
||||
<div className="mx_MatrixToolbar_close"><img src="img/cancel.svg" width="18" height="18" onClick={ this.hideToolbar } /></div>
|
||||
@@ -43,4 +43,3 @@ module.exports = React.createClass({
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -17,20 +17,49 @@ limitations under the License.
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var sdk = require('matrix-react-sdk');
|
||||
import Modal from 'matrix-react-sdk/lib/Modal';
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'NewVersionBar',
|
||||
/**
|
||||
* Check a version string is compatible with the Changelog
|
||||
* dialog
|
||||
*/
|
||||
function checkVersion(ver) {
|
||||
const parts = ver.split('-');
|
||||
return parts[0] == 'vector' && parts[2] == 'react' && parts[4] == 'js';
|
||||
}
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_MatrixToolbar">
|
||||
<img className="mx_MatrixToolbar_warning" src="img/warning.svg" width="24" height="23" alt="/!\"/>
|
||||
<div>
|
||||
A new version of Vector is available. Refresh your browser.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
export default function NewVersionBar(props) {
|
||||
const onChangelogClicked = () => {
|
||||
const ChangelogDialog = sdk.getComponent('dialogs.ChangelogDialog');
|
||||
|
||||
Modal.createDialog(ChangelogDialog, {
|
||||
version: props.version,
|
||||
newVersion: props.newVersion,
|
||||
onFinished: (update) => {
|
||||
if(update) {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let changelog_button;
|
||||
if (checkVersion(props.version) && checkVersion(props.newVersion)) {
|
||||
changelog_button = <button className="mx_MatrixToolbar_action" onClick={onChangelogClicked}>Changelog</button>;
|
||||
}
|
||||
});
|
||||
return (
|
||||
<div className="mx_MatrixToolbar">
|
||||
<img className="mx_MatrixToolbar_warning" src="img/warning.svg" width="24" height="23" alt="/!\"/>
|
||||
<div className="mx_MatrixToolbar_content">
|
||||
A new version of Riot is available. Refresh your browser.
|
||||
</div>
|
||||
{changelog_button}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
NewVersionBar.propTypes = {
|
||||
version: React.PropTypes.string.isRequired,
|
||||
newVersion: React.PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
@@ -30,10 +30,10 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
<div className="mx_Dialog_content">
|
||||
<span>
|
||||
You can use the custom server options to log into other Matrix
|
||||
You can use the custom server options to sign into other Matrix
|
||||
servers by specifying a different Home server URL.
|
||||
<br/>
|
||||
This allows you to use Vector with an existing Matrix account on
|
||||
This allows you to use Riot with an existing Matrix account on
|
||||
a different home server.
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
@@ -27,8 +27,8 @@ module.exports = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_Login_links">
|
||||
<a href="https://medium.com/@Vector">blog</a> ·
|
||||
<a href="https://twitter.com/@VectorCo">twitter</a> ·
|
||||
<a href="https://medium.com/@RiotChat">blog</a> ·
|
||||
<a href="https://twitter.com/@RiotChat">twitter</a> ·
|
||||
<a href="https://github.com/vector-im/vector-web">github</a> ·
|
||||
<a href="https://matrix.org">powered by Matrix</a>
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,7 @@ module.exports = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_Login_logo">
|
||||
<img src="img/logo.png" width="249" height="78" alt="vector"/>
|
||||
<img src="img/logo.png" width="195" height="195" alt="Riot"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ module.exports = React.createClass({
|
||||
var date = new Date(this.props.ts);
|
||||
return (
|
||||
<span className="mx_MessageTimestamp">
|
||||
{ DateUtils.formatDate(date) }
|
||||
{ DateUtils.formatTime(date) }
|
||||
</span>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
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 React = require('react');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'SenderProfile',
|
||||
|
||||
propTypes: {
|
||||
mxEvent: React.PropTypes.object.isRequired, // event whose sender we're showing
|
||||
aux: React.PropTypes.string, // stuff to go after the sender name, if anything
|
||||
onClick: React.PropTypes.func,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var mxEvent = this.props.mxEvent;
|
||||
var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
||||
|
||||
var msgtype = mxEvent.getContent().msgtype;
|
||||
if (msgtype && msgtype == 'm.emote') {
|
||||
return <span/>; // emote message must include the name so don't duplicate it
|
||||
}
|
||||
return (
|
||||
<span className="mx_SenderProfile" onClick={this.props.onClick}>
|
||||
{name} { this.props.aux }
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
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 React = require('react');
|
||||
|
||||
var sdk = require('matrix-react-sdk')
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'BottomLeftMenuTile',
|
||||
|
||||
getInitialState: function() {
|
||||
return( { hover : false });
|
||||
},
|
||||
|
||||
onMouseEnter: function() {
|
||||
this.setState( { hover : true });
|
||||
},
|
||||
|
||||
onMouseLeave: function() {
|
||||
this.setState( { hover : false });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var label;
|
||||
if (!this.props.collapsed) {
|
||||
label = <div className="mx_RoomTile_name">{ this.props.label }</div>;
|
||||
}
|
||||
else if (this.state.hover) {
|
||||
var RoomTooltip = sdk.getComponent("rooms.RoomTooltip");
|
||||
label = <RoomTooltip bottom={ true } label={ this.props.label }/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomTile" onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onClick={this.props.onClick}>
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<img src={ this.props.img } width="26" height="26"/>
|
||||
</div>
|
||||
{ label }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
+7
-1
@@ -25,6 +25,13 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var sdk = require('matrix-react-sdk');
|
||||
var RoomTile = require('matrix-react-sdk/lib/components/views/rooms/RoomTile');
|
||||
|
||||
/**
|
||||
* Defines a new Component, DNDRoomTile that wraps RoomTile, making it draggable.
|
||||
* Requires extra props:
|
||||
* roomSubList: React.PropTypes.object.isRequired,
|
||||
* refreshSubList: React.PropTypes.func.isRequired,
|
||||
*/
|
||||
|
||||
/**
|
||||
* Specifies the drag source contract.
|
||||
* Only `beginDrag` function is required.
|
||||
@@ -202,4 +209,3 @@ DragSource('RoomTile', roomTileSource, function(connect, monitor) {
|
||||
};
|
||||
})(RoomTile));
|
||||
|
||||
module.exports.replaces = 'RoomTile';
|
||||
@@ -18,42 +18,79 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
var ReactDOM = require('react-dom');
|
||||
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomTooltip',
|
||||
|
||||
componentDidMount: function() {
|
||||
var tooltip = ReactDOM.findDOMNode(this);
|
||||
if (!this.props.bottom) {
|
||||
// tell the roomlist about us so it can position us
|
||||
dis.dispatch({
|
||||
action: 'view_tooltip',
|
||||
tooltip: tooltip,
|
||||
});
|
||||
}
|
||||
else {
|
||||
tooltip.style.top = (70 + tooltip.parentElement.getBoundingClientRect().top) + "px";
|
||||
tooltip.style.display = "block";
|
||||
}
|
||||
propTypes: {
|
||||
// Alllow the tooltip to be styled by the parent element
|
||||
className: React.PropTypes.string.isRequired,
|
||||
// The tooltip is derived from either the room name or a label
|
||||
room: React.PropTypes.object,
|
||||
label: React.PropTypes.string,
|
||||
},
|
||||
|
||||
// Create a wrapper for the tooltip outside the parent and attach it to the body element
|
||||
componentDidMount: function() {
|
||||
this.tooltipContainer = document.createElement("div");
|
||||
this.tooltipContainer.className = "mx_RoomTileTooltip_wrapper";
|
||||
document.body.appendChild(this.tooltipContainer);
|
||||
|
||||
this._renderTooltip();
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
this._renderTooltip();
|
||||
},
|
||||
|
||||
// Remove the wrapper element, as the tooltip has finished using it
|
||||
componentWillUnmount: function() {
|
||||
if (!this.props.bottom) {
|
||||
dis.dispatch({
|
||||
action: 'view_tooltip',
|
||||
tooltip: null,
|
||||
});
|
||||
}
|
||||
dis.dispatch({
|
||||
action: 'view_tooltip',
|
||||
tooltip: null,
|
||||
parent: null,
|
||||
});
|
||||
|
||||
ReactDOM.unmountComponentAtNode(this.tooltipContainer);
|
||||
document.body.removeChild(this.tooltipContainer);
|
||||
},
|
||||
|
||||
_renderTooltip: function() {
|
||||
var label = this.props.room ? this.props.room.name : this.props.label;
|
||||
|
||||
// Add the parent's position to the tooltips, so it's correctly
|
||||
// positioned, also taking into account any window zoom
|
||||
// NOTE: The additional 6 pixels for the left position, is to take account of the
|
||||
// tooltips chevron
|
||||
var parent = ReactDOM.findDOMNode(this);
|
||||
var style = {};
|
||||
style.top = parent.getBoundingClientRect().top + window.pageYOffset;
|
||||
style.left = 6 + parent.getBoundingClientRect().right + window.pageXOffset;
|
||||
style.display = "block";
|
||||
|
||||
var tooltip = (
|
||||
<div className="mx_RoomTooltip" style={style} >
|
||||
<div className="mx_RoomTooltip_chevron"></div>
|
||||
{ label }
|
||||
</div>
|
||||
);
|
||||
|
||||
// Render the tooltip manually, as we wish it not to be rendered within the parent
|
||||
this.tooltip = ReactDOM.render(tooltip, this.tooltipContainer);
|
||||
|
||||
// Tell the roomlist about us so it can manipulate us if it wishes
|
||||
dis.dispatch({
|
||||
action: 'view_tooltip',
|
||||
tooltip: this.tooltip,
|
||||
parent: parent,
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var label = this.props.room ? this.props.room.name : this.props.label;
|
||||
// Render a placeholder
|
||||
return (
|
||||
<div className="mx_RoomTooltip">
|
||||
<img className="mx_RoomTooltip_chevron" src="img/chevron-left.png" width="9" height="16"/>
|
||||
{ label }
|
||||
<div className={ this.props.className } >
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
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 React = require('react');
|
||||
var sdk = require('matrix-react-sdk');
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'IntegrationsManager',
|
||||
|
||||
propTypes: {
|
||||
src: React.PropTypes.string.isRequired, // the source of the integration manager being embedded
|
||||
onFinished: React.PropTypes.func.isRequired, // callback when the lightbox is dismissed
|
||||
},
|
||||
|
||||
// XXX: keyboard shortcuts for managing dialogs should be done by the modal
|
||||
// dialog base class somehow, surely...
|
||||
componentDidMount: function() {
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
document.addEventListener("keydown", this.onKeyDown);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
document.removeEventListener("keydown", this.onKeyDown);
|
||||
},
|
||||
|
||||
onKeyDown: function(ev) {
|
||||
if (ev.keyCode == 27) { // escape
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.props.onFinished();
|
||||
}
|
||||
},
|
||||
|
||||
onAction: function(payload) {
|
||||
if (payload.action === 'close_scalar') {
|
||||
this.props.onFinished();
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<iframe src={ this.props.src }></iframe>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -21,11 +21,10 @@ var sdk = require('matrix-react-sdk');
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var UserSettingsStore = require('matrix-react-sdk/lib/UserSettingsStore');
|
||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
||||
var configJson = require("../../../../config.json");
|
||||
|
||||
var notifications = require('../../../notifications');
|
||||
|
||||
// TODO: this "view" component still has far to much application logic in it,
|
||||
// TODO: this "view" component still has far too much application logic in it,
|
||||
// which should be factored out to other files.
|
||||
|
||||
// TODO: this component also does a lot of direct poking into this.state, which
|
||||
@@ -73,6 +72,8 @@ module.exports = React.createClass({
|
||||
propTypes: {
|
||||
// The array of threepids from the JS SDK (required for email notifications)
|
||||
threepids: React.PropTypes.array.isRequired,
|
||||
// The brand string set when creating an email pusher
|
||||
brand: React.PropTypes.string,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
@@ -118,9 +119,7 @@ module.exports = React.createClass({
|
||||
var emailPusherPromise;
|
||||
if (event.target.checked) {
|
||||
var data = {}
|
||||
if (configJson.brand) {
|
||||
data['brand'] = configJson.brand;
|
||||
}
|
||||
data['brand'] = this.props.brand || 'Riot';
|
||||
emailPusherPromise = UserSettingsStore.addEmailPusher(address, data);
|
||||
} else {
|
||||
var emailPusher = UserSettingsStore.getEmailPusher(this.state.pushers, address);
|
||||
@@ -133,7 +132,7 @@ module.exports = React.createClass({
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Error saving email notification preferences",
|
||||
description: "Vector was unable to save your email notification preferences.",
|
||||
description: "An error occurred whilst saving your email notification preferences.",
|
||||
});
|
||||
});
|
||||
},
|
||||
@@ -785,7 +784,7 @@ module.exports = React.createClass({
|
||||
<div>
|
||||
<h3>Advanced notifications settings</h3>
|
||||
There are advanced notifications which are not shown here.<br/>
|
||||
You might have configured them in another client than Vector. You cannot tune them in Vector but they still apply.
|
||||
You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply.
|
||||
<ul>
|
||||
{ externalRules }
|
||||
</ul>
|
||||
@@ -844,7 +843,7 @@ module.exports = React.createClass({
|
||||
<th width="55%"></th>
|
||||
<th width="15%">Off</th>
|
||||
<th width="15%">On</th>
|
||||
<th width="15%">Highlight<br/>& sound</th>
|
||||
<th width="15%">Noisy</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -65,7 +65,7 @@ module.exports = {
|
||||
// Messages containing user's display name
|
||||
// (skip contains_user_name which is too geeky)
|
||||
".m.rule.contains_display_name": new VectorPushRuleDefinition({
|
||||
kind: "underride",
|
||||
kind: "override",
|
||||
description: "Messages containing my name",
|
||||
vectorStateToActions: { // The actions for each vector state, or null to disable the rule.
|
||||
on: StandardActions.ACTION_NOTIFY,
|
||||
|
||||
+111
-61
@@ -32,6 +32,8 @@ body {
|
||||
color: #454545;
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
/* This should render the fonts the same accross browsers */
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
}
|
||||
|
||||
div.error {
|
||||
@@ -52,12 +54,26 @@ a:visited {
|
||||
color: #76cfa6;
|
||||
}
|
||||
|
||||
input[type=text].error, input[type=password].error {
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
input[type=text]:focus, textarea:focus {
|
||||
border: 1px solid #76CFA6;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Required by Firefox */
|
||||
textarea {
|
||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||
}
|
||||
|
||||
/* Prevent ugly dotted highlight around selected elements in Firefox */
|
||||
::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* applied to side-panels and messagepanel when in RoomSettings */
|
||||
.mx_fadable {
|
||||
opacity: 1;
|
||||
@@ -75,53 +91,27 @@ input[type=text]:focus, textarea:focus {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* hack to avoid accidental click-throughs if you miss the narrow scrollbar */
|
||||
/* Expand thumbs on hoverover */
|
||||
.gm-scrollbar {
|
||||
border-radius: 5px ! important;
|
||||
}
|
||||
.gm-scrollbar.-vertical {
|
||||
border-left: 6px solid transparent;
|
||||
width: 6px;
|
||||
transition: width 120ms ease-out ! important;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 1.0;
|
||||
z-index: 2000;
|
||||
.gm-scrollbar.-vertical:hover,
|
||||
.gm-scrollbar.-vertical:active {
|
||||
width: 8px;
|
||||
transition: width 120ms ease-out ! important;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu {
|
||||
border: 1px solid #a4a4a4;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
color: #747474;
|
||||
position: fixed;
|
||||
z-index: 2001;
|
||||
padding: 6px;
|
||||
.gm-scrollbar.-horizontal {
|
||||
height: 6px;
|
||||
transition: height 120ms ease-out ! important;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_chevron_right {
|
||||
padding: 12px;
|
||||
position: absolute;
|
||||
right: -21px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_chevron_left {
|
||||
padding: 12px;
|
||||
position: absolute;
|
||||
left: -21px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_field {
|
||||
padding: 3px 6px 3px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_spinner {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
.gm-scrollbar.-horizontal:hover,
|
||||
.gm-scrollbar.-horizontal:active {
|
||||
height: 8px;
|
||||
transition: height 120ms ease-out ! important;
|
||||
}
|
||||
|
||||
.mx_Dialog_wrapper {
|
||||
@@ -143,16 +133,33 @@ input[type=text]:focus, textarea:focus {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Spinner Dialog overide */
|
||||
.mx_Dialog_wrapper.mx_Dialog_spinner .mx_Dialog {
|
||||
width: auto;
|
||||
border-radius: 8px;
|
||||
padding-left: 0px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* View Source Dialog overide */
|
||||
.mx_Dialog_wrapper.mx_Dialog_viewsource .mx_Dialog {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.mx_Dialog {
|
||||
background-color: #fff;
|
||||
color: #747474;
|
||||
text-align: center;
|
||||
z-index: 4010;
|
||||
font-weight: 300;
|
||||
font-size: 15px;
|
||||
position: relative;
|
||||
border-radius: 8px;
|
||||
max-width: 80%;
|
||||
padding-left: 58px;
|
||||
width: 60%;
|
||||
max-width: 704px;
|
||||
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2);
|
||||
max-height: 80%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mx_Dialog_background {
|
||||
@@ -161,12 +168,13 @@ input[type=text]:focus, textarea:focus {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
opacity: 0.2;
|
||||
background-color: #e9e9e9;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.mx_Dialog_lightbox .mx_Dialog_background {
|
||||
opacity: 0.85;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.mx_Dialog_lightbox .mx_Dialog {
|
||||
@@ -180,34 +188,64 @@ input[type=text]:focus, textarea:focus {
|
||||
}
|
||||
|
||||
.mx_Dialog_content {
|
||||
margin: 24px;
|
||||
margin: 24px 58px 68px 0;
|
||||
font-size: 14px;
|
||||
color: #4a4a4a;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.mx_Dialog_buttons {
|
||||
padding-bottom: 24px;
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
|
||||
.mx_Dialog button, .mx_Dialog input[type="submit"] {
|
||||
border: 0px;
|
||||
height: 36px;
|
||||
border-radius: 36px;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
border-radius: 40px;
|
||||
border: solid 1px #76cfa6;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||
margin-left: 0px;
|
||||
margin-right: 8px;
|
||||
padding-left: 1.5em;
|
||||
padding-right: 1.5em;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: #76cfa6;
|
||||
background-color: #fff;
|
||||
|
||||
/* align images in buttons (eg spinners) */
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary {
|
||||
color: #fff;
|
||||
background-color: #76cfa6;
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.mx_Dialog button.danger, .mx_Dialog input[type="submit"].danger {
|
||||
background-color: #ff0064;
|
||||
border: solid 1px #ff0064;
|
||||
}
|
||||
|
||||
.mx_Dialog button:disabled, .mx_Dialog input[type="submit"]:disabled {
|
||||
background-color: #777777;
|
||||
border: solid 1px #777777;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.mx_Dialog_title {
|
||||
min-height: 16px;
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid #a4a4a4;
|
||||
padding-top: 40px;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
font-size: 22px;
|
||||
line-height: 1.4;
|
||||
color: #454545;
|
||||
}
|
||||
|
||||
.mx_Dialog_title.danger {
|
||||
color: #ff0064;
|
||||
}
|
||||
|
||||
.mx_TextInputDialog_label {
|
||||
@@ -224,7 +262,7 @@ input[type=text]:focus, textarea:focus {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.emojione {
|
||||
.mx_emojione {
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -238,3 +276,15 @@ input[type=text]:focus, textarea:focus {
|
||||
background-color: #76CFA6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/** green button with rounded corners */
|
||||
.mx_textButton {
|
||||
color: #fff;
|
||||
background-color: #76cfa6;
|
||||
border-radius: 17px;
|
||||
text-align: center;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
cursor: pointer;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
.mx_RoomSettings_encrypt,
|
||||
.mx_CreateRoom_encrypt,
|
||||
.mx_RightPanel_filebutton
|
||||
{
|
||||
display: none !important;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_ContextualMenu_wrapper {
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 1.0;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu {
|
||||
border: solid 1px rgba(187, 187, 187, 0.5);
|
||||
border-radius: 4px;
|
||||
background-color: #f6f6f6;
|
||||
color: #4a4a4a;
|
||||
position: absolute;
|
||||
padding: 6px;
|
||||
font-size: 14px;
|
||||
z-index: 2001;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu.mx_ContextualMenu_right {
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_chevron_right {
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: 0px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 8px solid transparent;
|
||||
border-left: 8px solid rgba(187, 187, 187, 0.5);
|
||||
border-bottom: 8px solid transparent;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_chevron_right:after {
|
||||
content:'';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 7px solid transparent;
|
||||
border-left: 7px solid #f6f6f6;
|
||||
border-bottom: 7px solid transparent;
|
||||
position:absolute;
|
||||
top: -7px;
|
||||
right: 1px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu.mx_ContextualMenu_left {
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_chevron_left {
|
||||
position: absolute;
|
||||
left: -8px;
|
||||
top: 0px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 8px solid transparent;
|
||||
border-right: 8px solid rgba(187, 187, 187, 0.5);
|
||||
border-bottom: 8px solid transparent;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_chevron_left:after{
|
||||
content:'';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 7px solid transparent;
|
||||
border-right: 7px solid #f6f6f6;
|
||||
border-bottom: 7px solid transparent;
|
||||
position:absolute;
|
||||
top: -7px;
|
||||
left: 1px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_field {
|
||||
padding: 3px 6px 3px 6px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_spinner {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
.mx_FilePanel {
|
||||
-webkit-box-ordinal-group: 2;
|
||||
-moz-box-ordinal-group: 2;
|
||||
-ms-flex-order: 2;
|
||||
-webkit-order: 2;
|
||||
order: 2;
|
||||
|
||||
-webkit-flex: 1 1 0;
|
||||
flex: 1 1 0;
|
||||
|
||||
width: 100%;
|
||||
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_RoomView_messageListWrapper {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_RoomView_MessageList h2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* FIXME: rather than having EventTile's default CSS be for MessagePanel,
|
||||
we should make EventTile a base CSS class and customise it specifically
|
||||
for usage in {Message,File,Notification}Panel. */
|
||||
|
||||
.mx_FilePanel .mx_EventTile_avatar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Overrides for the attachment body tiles */
|
||||
|
||||
.mx_FilePanel .mx_EventTile {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile .mx_MImageBody {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile .mx_MImageBody_download {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
color: #acacac;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile .mx_MImageBody_downloadLink {
|
||||
flex: 1 1 auto;
|
||||
color: #747474;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile .mx_MImageBody_size {
|
||||
flex: 1 0 0;
|
||||
font-size: 11px;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Overides for the sender details line */
|
||||
|
||||
.mx_FilePanel .mx_EventTile_senderDetails {
|
||||
display: flex;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile_senderDetailsLink {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile .mx_SenderProfile {
|
||||
flex: 1 1 auto;
|
||||
line-height: initial;
|
||||
padding: 0px;
|
||||
font-size: 11px;
|
||||
opacity: 1.0;
|
||||
color: #acacac;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile .mx_MessageTimestamp {
|
||||
flex: 1 0 0;
|
||||
text-align: right;
|
||||
visibility: visible;
|
||||
position: initial;
|
||||
font-size: 11px;
|
||||
opacity: 1.0;
|
||||
color: #acacac;
|
||||
}
|
||||
|
||||
/* Overrides for the wrappers around the body tile */
|
||||
|
||||
.mx_FilePanel .mx_EventTile_line {
|
||||
margin-right: 0px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile:hover .mx_EventTile_line {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile_selected .mx_EventTile_line {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
@@ -93,8 +93,8 @@ limitations under the License.
|
||||
|
||||
background-color: #eaf5f0;
|
||||
|
||||
-webkit-flex: 0 0 210px;
|
||||
flex: 0 0 210px;
|
||||
-webkit-flex: 0 0 235px;
|
||||
flex: 0 0 235px;
|
||||
}
|
||||
|
||||
.mx_MatrixChat .mx_LeftPanel.collapsed {
|
||||
@@ -109,7 +109,7 @@ limitations under the License.
|
||||
-webkit-order: 2;
|
||||
order: 2;
|
||||
|
||||
padding-left: 25px;
|
||||
padding-left: 20px;
|
||||
padding-right: 22px;
|
||||
background-color: #fff;
|
||||
|
||||
@@ -151,6 +151,6 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_MatrixChat .mx_RightPanel.collapsed {
|
||||
-webkit-flex: 0 0 72px;
|
||||
flex: 0 0 72px;
|
||||
-webkit-flex: 0 0 122px;
|
||||
flex: 0 0 122px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_NotificationPanel {
|
||||
-webkit-box-ordinal-group: 2;
|
||||
-moz-box-ordinal-group: 2;
|
||||
-ms-flex-order: 2;
|
||||
-webkit-order: 2;
|
||||
order: 2;
|
||||
|
||||
-webkit-flex: 1 1 0;
|
||||
flex: 1 1 0;
|
||||
|
||||
width: 100%;
|
||||
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_RoomView_messageListWrapper {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_RoomView_MessageList h2 {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
/* FIXME: rather than having EventTile's default CSS be for MessagePanel,
|
||||
we should make EventTile a base CSS class and customise it specifically
|
||||
for usage in {Message,File,Notification}Panel. */
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile_roomName {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile_roomName a {
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile_avatar {
|
||||
top: 8px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile .mx_SenderProfile,
|
||||
.mx_NotificationPanel .mx_EventTile .mx_MessageTimestamp {
|
||||
color: #000;
|
||||
opacity: 0.3;
|
||||
font-size: 12px;
|
||||
display: inline;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile_senderDetails {
|
||||
padding-left: 32px;
|
||||
padding-top: 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile_roomName a,
|
||||
.mx_NotificationPanel .mx_EventTile_senderDetails a {
|
||||
text-decoration: none ! important;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile .mx_MessageTimestamp {
|
||||
visibility: visible;
|
||||
position: initial;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile_line {
|
||||
margin-right: 0px;
|
||||
padding-left: 32px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile:hover .mx_EventTile_line {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile_selected .mx_EventTile_line {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile_content {
|
||||
margin-right: 0px;
|
||||
}
|
||||
@@ -15,7 +15,6 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_RoomStatusBar {
|
||||
margin-top: 15px;
|
||||
margin-left: 65px;
|
||||
min-height: 34px;
|
||||
}
|
||||
@@ -25,11 +24,17 @@ limitations under the License.
|
||||
padding-left: 18px;
|
||||
padding-right: 12px;
|
||||
margin-left: -73px;
|
||||
margin-top: 13px;
|
||||
float: left;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mx_RoomStatusBar_callBar {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.mx_RoomStatusBar_placeholderIndicator span {
|
||||
color: #4a4a4a;
|
||||
opacity: 0.5;
|
||||
@@ -70,6 +75,7 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_RoomStatusBar_unreadMessagesBar {
|
||||
padding-top: 10px;
|
||||
color: #ff0064;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -103,10 +109,12 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_RoomStatusBar_tabCompleteBar {
|
||||
padding-top: 10px;
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.mx_RoomStatusBar_typingBar {
|
||||
padding-top: 10px;
|
||||
color: #4a4a4a;
|
||||
opacity: 0.5;
|
||||
overflow-y: hidden;
|
||||
|
||||
@@ -207,7 +207,7 @@ hr.mx_RoomView_myReadMarker {
|
||||
.mx_RoomView_statusAreaBox {
|
||||
max-width: 960px;
|
||||
margin: auto;
|
||||
min-height: 60px;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.mx_RoomView_statusAreaBox_line {
|
||||
@@ -216,6 +216,15 @@ hr.mx_RoomView_myReadMarker {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.mx_RoomView_callStatusBar .mx_UploadBar_uploadProgressInner {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.mx_RoomView_callStatusBar .mx_UploadBar_uploadFilename {
|
||||
color: #fff;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.mx_RoomView_inCall .mx_RoomView_statusAreaBox_line {
|
||||
border-top: 1px hidden;
|
||||
}
|
||||
@@ -239,6 +248,7 @@ hr.mx_RoomView_myReadMarker {
|
||||
.mx_RoomView_voipButton {
|
||||
float: right;
|
||||
margin-right: 13px;
|
||||
margin-top: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -268,3 +278,7 @@ hr.mx_RoomView_myReadMarker {
|
||||
padding: 6px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_RoomView_ongoingConfCallNotification a {
|
||||
color: #fff ! important;
|
||||
}
|
||||
@@ -17,10 +17,9 @@ limitations under the License.
|
||||
.mx_SearchBox {
|
||||
height: 24px;
|
||||
margin-left: 16px;
|
||||
margin-right: 20px;
|
||||
margin-right: 16px;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 22px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
@@ -28,11 +27,13 @@ limitations under the License.
|
||||
|
||||
.mx_SearchBox_searchButton {
|
||||
margin-right: 10px;
|
||||
margin-top: 5px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mx_SearchBox_closeButton {
|
||||
cursor: pointer;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.mx_SearchBox_search {
|
||||
@@ -65,4 +66,4 @@ limitations under the License.
|
||||
|
||||
.mx_SearchBox object {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,12 +94,38 @@ limitations under the License.
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_UserSettings_button.danger {
|
||||
background-color: #ff0064;
|
||||
}
|
||||
|
||||
.mx_UserSettings_section {
|
||||
margin-left: 63px;
|
||||
margin-top: 28px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.mx_UserSettings_cryptoSection ul {
|
||||
display: table;
|
||||
}
|
||||
.mx_UserSettings_cryptoSection li {
|
||||
display: table-row;
|
||||
}
|
||||
.mx_UserSettings_cryptoSection label,
|
||||
.mx_UserSettings_cryptoSection span {
|
||||
display: table-cell;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.mx_UserSettings_toggle input {
|
||||
width: 16px;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.mx_UserSettings_toggle label {
|
||||
padding-bottom: 21px;
|
||||
}
|
||||
|
||||
.mx_UserSettings_accountTable
|
||||
.mx_UserSettings_notifTable
|
||||
{
|
||||
|
||||
@@ -131,9 +131,19 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_Login_loader {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-top: 12px;
|
||||
display: inline;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
.mx_Login_loader .mx_Spinner {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.mx_Login_loader .mx_Spinner img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.mx_Login_error {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
/* Using a textarea for this element, to circumvent autofill */
|
||||
.mx_ChatInviteDialog_input,
|
||||
.mx_ChatInviteDialog_input:focus
|
||||
{
|
||||
height: 26px;
|
||||
font-size: 14px;
|
||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
margin: 0 !important;
|
||||
border: 0 !important;
|
||||
outline: 0 !important;
|
||||
width: 1000%; /* Pretend that this is an "input type=text" */
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
word-wrap: nowrap;
|
||||
}
|
||||
|
||||
.mx_ChatInviteDialog_inputContainer {
|
||||
border-radius: 3px;
|
||||
border: solid 1px #f0f0f0;
|
||||
line-height: 36px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
max-height: 150px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mx_ChatInviteDialog_error {
|
||||
position: absolute;
|
||||
color: #ff0064;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.mx_ChatInviteDialog_cancel {
|
||||
position: absolute;
|
||||
right: 11px;
|
||||
top: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_ChatInviteDialog_cancel object {
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
.mx_EncryptedEventDialog .mx_MemberDeviceInfo {
|
||||
float: right;
|
||||
padding: 0px;
|
||||
margin-right: 42px;
|
||||
}
|
||||
|
||||
.mx_EncryptedEventDialog .mx_MemberDeviceInfo_textButton {
|
||||
border: 0px;
|
||||
height: 36px;
|
||||
border-radius: 40px;
|
||||
border: solid 1px #76cfa6;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||
margin-left: 0px;
|
||||
margin-right: 8px;
|
||||
padding-left: 1.5em;
|
||||
padding-right: 1.5em;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: #76cfa6;
|
||||
background-color: #fff;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
.mx_AddressSelector {
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
width: 485px;
|
||||
max-height: 116px;
|
||||
overflow-y: auto;
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
border: solid 1px #76cfa6;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_AddressSelector.mx_AddressSelector_empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_AddressSelector_addressListElement .mx_AddressTile {
|
||||
background-color: #fff;
|
||||
border: solid 1px #fff;
|
||||
}
|
||||
|
||||
.mx_AddressSelector_addressListElement.mx_AddressSelector_selected {
|
||||
background-color: #eaf5f0; /* selected colour */
|
||||
}
|
||||
|
||||
.mx_AddressSelector_addressListElement.mx_AddressSelector_selected .mx_AddressTile {
|
||||
background-color: #eaf5f0; /* selected colour */
|
||||
border: solid 1px #eaf5f0; /* selected colour */
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_AddressTile {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: rgba(74, 73, 74, 0.1);
|
||||
border: solid 1px #f0f0f0;
|
||||
line-height: 26px;
|
||||
color: #454545;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.mx_AddressTile.mx_AddressTile_error {
|
||||
background-color: rgba(255, 0, 100, 0.1);
|
||||
color: #ff0064;
|
||||
border-color: #ff0064;
|
||||
}
|
||||
|
||||
.mx_AddressTile_network {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding-left: 2px;
|
||||
padding-right: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_AddressTile_avatar {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding-left: 2px;
|
||||
padding-right: 7px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_AddressTile_mx {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mx_AddressTile_name {
|
||||
display: inline-block;
|
||||
padding-right: 4px;
|
||||
font-weight: 600;
|
||||
overflow: hidden;
|
||||
height: 26px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_AddressTile_name.mx_AddressTile_justified {
|
||||
width: 180px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_AddressTile_id {
|
||||
display: inline-block;
|
||||
padding-right: 11px;
|
||||
}
|
||||
|
||||
.mx_AddressTile_id.mx_AddressTile_justified {
|
||||
width: 200px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_AddressTile_unknownMx {
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
padding-right: 11px;
|
||||
}
|
||||
|
||||
.mx_AddressTile_unknownMxl.mx_AddressTile_justified {
|
||||
width: 380px; /* name + id width */
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_AddressTile_email {
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
padding-right: 11px;
|
||||
}
|
||||
|
||||
.mx_AddressTile_email.mx_AddressTile_justified {
|
||||
width: 380px; /* name + id width */
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_AddressTile_unknown {
|
||||
display: inline-block;
|
||||
padding-right: 11px;
|
||||
}
|
||||
|
||||
.mx_AddressTile_unknown.mx_AddressTile_justified {
|
||||
width: 380px; /* name + id width */
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_AddressTile_dismiss {
|
||||
display: inline-block;
|
||||
padding-right: 11px;
|
||||
padding-left: 1px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_AddressTile_dismiss object {
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
.mx_DirectorySearchBox {
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #c7c7c7;
|
||||
}
|
||||
|
||||
.mx_DirectorySearchBox_container {
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
padding-left: 9px;
|
||||
padding-right: 9px;
|
||||
}
|
||||
|
||||
.mx_DirectorySearchBox_input {
|
||||
flex-grow: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
font-weight: 300;
|
||||
font-size: 13px;
|
||||
}
|
||||
input[type=text].mx_DirectorySearchBox_input:focus {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.mx_DirectorySearchBox_joinButton {
|
||||
display: table-cell;
|
||||
padding: 3px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
background-color: #efefef;
|
||||
border-radius: 3px;
|
||||
background-image: url('img/icon-return.svg');
|
||||
background-position: 8px 70%;
|
||||
background-repeat: no-repeat;
|
||||
text-indent: 18px;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_DirectorySearchBox_clear_wrapper {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.mx_DirectorySearchBox_clear {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background: url('img/icon_context_delete.svg');
|
||||
background-position: 0 50%;
|
||||
background-repeat: no-repeat;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
.mx_UserPill {
|
||||
color: white;
|
||||
background-color: #76cfa6;
|
||||
padding: 2px 8px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.mx_RoomPill {
|
||||
background-color: white;
|
||||
color: #76cfa6;
|
||||
border: 1px solid #76cfa6;
|
||||
padding: 2px 8px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.mx_Markdown_BOLD {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mx_Markdown_ITALIC {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.mx_Markdown_CODE {
|
||||
padding: .2em 0;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: rgba(0,0,0,.04);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.mx_Markdown_HR {
|
||||
display: block;
|
||||
background: #e7e7e7;
|
||||
}
|
||||
|
||||
.mx_Markdown_STRIKETHROUGH {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
@@ -16,6 +16,7 @@ limitations under the License.
|
||||
|
||||
.mx_MImageBody {
|
||||
display: block;
|
||||
margin-right: 34px;
|
||||
}
|
||||
|
||||
.mx_MImageBody_thumbnail {
|
||||
@@ -29,7 +30,6 @@ limitations under the License.
|
||||
|
||||
.mx_MImageBody_download {
|
||||
color: #76cfa6;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_MImageBody_download a {
|
||||
|
||||
@@ -17,3 +17,8 @@ limitations under the License.
|
||||
.mx_MTextBody {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.mx_MTextBody pre{
|
||||
overflow-y: auto;
|
||||
max-height: 30vh;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_UnknownBody {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
.mx_Autocomplete {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
width: 100%;
|
||||
border: 1px solid #e5e5e5;
|
||||
background: white;
|
||||
border-bottom: none;
|
||||
border-radius: 4px 4px 0 0;
|
||||
max-height: 50vh;
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
.mx_Autocomplete_ProviderSection {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.mx_Autocomplete_Completion_container_pill {
|
||||
margin: 12px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* a "block" completion takes up a whole line */
|
||||
.mx_Autocomplete_Completion_block {
|
||||
height: 34px;
|
||||
display: flex;
|
||||
padding: 0 12px;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.mx_Autocomplete_Completion_block * {
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.mx_Autocomplete_Completion_pill {
|
||||
border-radius: 17px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.mx_Autocomplete_Completion_pill * {
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
/* container for pill-style completions */
|
||||
.mx_Autocomplete_Completion_container_pill {
|
||||
margin: 12px;
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
}
|
||||
|
||||
.mx_Autocomplete_Completion.selected {
|
||||
background: #f6f6f6;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.mx_Autocomplete_provider_name {
|
||||
margin: 12px;
|
||||
color: #454545;
|
||||
font-weight: 400;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* styling for common completion elements */
|
||||
.mx_Autocomplete_Completion_subtitle {
|
||||
font-style: italic;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mx_Autocomplete_Completion_description {
|
||||
color: gray;
|
||||
}
|
||||
@@ -87,14 +87,17 @@ limitations under the License.
|
||||
|
||||
.mx_EntityTile_unavailable .mx_EntityTile_avatar,
|
||||
.mx_EntityTile_unavailable .mx_EntityTile_name,
|
||||
.mx_EntityTile_unavailable .mx_EntityTile_name_hover
|
||||
.mx_EntityTile_unavailable .mx_EntityTile_name_hover,
|
||||
.mx_EntityTile_offline_beenactive .mx_EntityTile_avatar,
|
||||
.mx_EntityTile_offline_beenactive .mx_EntityTile_name,
|
||||
.mx_EntityTile_offline_beenactive .mx_EntityTile_name_hover
|
||||
{
|
||||
opacity: 0.66;
|
||||
}
|
||||
|
||||
.mx_EntityTile_offline .mx_EntityTile_avatar,
|
||||
.mx_EntityTile_offline .mx_EntityTile_name,
|
||||
.mx_EntityTile_offline .mx_EntityTile_name_hover
|
||||
.mx_EntityTile_offline_neveractive .mx_EntityTile_avatar,
|
||||
.mx_EntityTile_offline_neveractive .mx_EntityTile_name,
|
||||
.mx_EntityTile_offline_neveractive .mx_EntityTile_name_hover
|
||||
{
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
@@ -17,103 +17,91 @@ limitations under the License.
|
||||
.mx_EventTile {
|
||||
max-width: 100%;
|
||||
clear: both;
|
||||
margin-top: 24px;
|
||||
margin-left: 65px;
|
||||
padding-top: 18px;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mx_EventTile.mx_EventTile_info {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.mx_EventTile_avatar {
|
||||
padding-left: 18px;
|
||||
padding-right: 12px;
|
||||
margin-left: -73px;
|
||||
margin-top: -2px;
|
||||
float: left;
|
||||
position: relative;
|
||||
top: 0px;
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
left: 8px;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.mx_EventTile.mx_EventTile_info .mx_EventTile_avatar {
|
||||
top: 8px;
|
||||
left: 65px;
|
||||
}
|
||||
|
||||
.mx_EventTile_continuation {
|
||||
margin-top: 8px ! important;
|
||||
padding-top: 0px ! important;
|
||||
}
|
||||
|
||||
.mx_EventTile .mx_SenderProfile {
|
||||
color: #454545;
|
||||
opacity: 0.5;
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
display: block; /* anti-zalgo, with overflow hidden */
|
||||
overflow-y: hidden;
|
||||
cursor: pointer;
|
||||
padding-left: 65px; /* left gutter */
|
||||
padding-bottom: 0px;
|
||||
padding-top: 0px;
|
||||
margin: 0px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.mx_EventTile .mx_MessageTimestamp {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
white-space: nowrap;
|
||||
color: #acacac;
|
||||
font-size: 11px;
|
||||
left: 8px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.mx_EventTile_line {
|
||||
position: relative;
|
||||
/* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */
|
||||
margin-right: 95px;
|
||||
margin-right: 110px;
|
||||
padding-left: 65px; /* left gutter */
|
||||
padding-top: 4px;
|
||||
padding-bottom: 2px;
|
||||
border-radius: 4px;
|
||||
min-height: 24px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
/* all the overflow-y: hidden; are to trap Zalgos -
|
||||
but they introduce an implicit overflow-x: auto.
|
||||
so make that explicitly hidden too to avoid random
|
||||
horizontal scrollbars occasionally appearing, like in
|
||||
https://github.com/vector-im/vector-web/issues/1154
|
||||
*/
|
||||
.mx_EventTile_content {
|
||||
display: block;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
.mx_EventTile_info .mx_EventTile_line {
|
||||
padding-left: 83px;
|
||||
}
|
||||
|
||||
/* Various markdown overrides */
|
||||
|
||||
.mx_EventTile_content .markdown-body {
|
||||
font-family: inherit ! important;
|
||||
white-space: normal ! important;
|
||||
line-height: inherit ! important;
|
||||
color: inherit;
|
||||
font-size: 15px;
|
||||
/* HACK to override line-height which is already marked important elsewhere */
|
||||
.mx_EventTile_bigEmoji.mx_EventTile_bigEmoji {
|
||||
font-size: 48px ! important;
|
||||
line-height: 48px ! important;
|
||||
}
|
||||
|
||||
/* have to use overlay rather than auto otherwise Linux and Windows
|
||||
Chrome gets very confused about vertical spacing:
|
||||
https://github.com/vector-im/vector-web/issues/754
|
||||
*/
|
||||
.mx_EventTile_content .markdown-body pre {
|
||||
overflow-x: overlay;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
.mx_EventTile_content .markdown-body h1,
|
||||
.mx_EventTile_content .markdown-body h2,
|
||||
.mx_EventTile_content .markdown-body h3,
|
||||
.mx_EventTile_content .markdown-body h4,
|
||||
.mx_EventTile_content .markdown-body h5,
|
||||
.mx_EventTile_content .markdown-body h6
|
||||
{
|
||||
font-family: inherit ! important;
|
||||
}
|
||||
|
||||
.mx_EventTile_content .markdown-body a {
|
||||
color: #76cfa6;
|
||||
}
|
||||
|
||||
.mx_EventTile_content .markdown-body .hljs {
|
||||
display: inline ! important;
|
||||
}
|
||||
|
||||
/* end of overrides */
|
||||
|
||||
/* this is used for the tile for the event which is selected via the URL.
|
||||
* TODO: ultimately we probably want some transition on here.
|
||||
*/
|
||||
.mx_EventTile_selected {
|
||||
.mx_EventTile_selected .mx_EventTile_line {
|
||||
border-left: #76cfa6 5px solid;
|
||||
margin-left: 53px;
|
||||
padding-left: 7px;
|
||||
padding-left: 60px;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.mx_EventTile:hover .mx_EventTile_line,
|
||||
.mx_EventTile.menu .mx_EventTile_line
|
||||
{
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.mx_EventTile_searchHighlight {
|
||||
@@ -130,6 +118,10 @@ limitations under the License.
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.mx_EventTile_encrypting {
|
||||
color: #abddbc ! important;
|
||||
}
|
||||
|
||||
.mx_EventTile_sending {
|
||||
color: #ddd;
|
||||
}
|
||||
@@ -162,32 +154,29 @@ limitations under the License.
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mx_EventTile .mx_MessageTimestamp {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mx_EventTile_last .mx_MessageTimestamp {
|
||||
.mx_EventTile_last .mx_MessageTimestamp,
|
||||
.mx_EventTile:hover .mx_MessageTimestamp,
|
||||
.mx_EventTile.menu .mx_MessageTimestamp
|
||||
{
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.mx_EventTile:hover .mx_MessageTimestamp {
|
||||
visibility: visible;
|
||||
.mx_EventTile_selected .mx_MessageTimestamp {
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
.mx_EventTile_editButton {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
cursor: pointer;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
.mx_EventTile:hover .mx_EventTile_editButton {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.mx_EventTile.menu .mx_EventTile_editButton {
|
||||
.mx_EventTile:hover .mx_EventTile_editButton,
|
||||
.mx_EventTile.menu .mx_EventTile_editButton
|
||||
{
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -200,6 +189,13 @@ limitations under the License.
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
top: 29px;
|
||||
}
|
||||
|
||||
.mx_EventTile_continuation .mx_EventTile_readAvatars,
|
||||
.mx_EventTile_info .mx_EventTile_readAvatars
|
||||
{
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
.mx_EventTile_readAvatars .mx_BaseAvatar {
|
||||
@@ -212,3 +208,100 @@ limitations under the License.
|
||||
font-size: 11px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* all the overflow-y: hidden; are to trap Zalgos -
|
||||
but they introduce an implicit overflow-x: auto.
|
||||
so make that explicitly hidden too to avoid random
|
||||
horizontal scrollbars occasionally appearing, like in
|
||||
https://github.com/vector-im/vector-web/issues/1154
|
||||
*/
|
||||
.mx_EventTile_content {
|
||||
display: block;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
margin-right: 34px;
|
||||
}
|
||||
|
||||
/* De-zalgoing */
|
||||
.mx_EventTile_body {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
/* End to end encryption stuff */
|
||||
|
||||
.mx_EventTile_e2eIcon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
left: 46px;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line,
|
||||
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line {
|
||||
padding-left: 60px;
|
||||
}
|
||||
|
||||
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line {
|
||||
border-left: #76cfa5 5px solid;
|
||||
}
|
||||
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line {
|
||||
border-left: #e8bf37 5px solid;
|
||||
}
|
||||
|
||||
.mx_EventTile:hover.mx_EventTile_verified .mx_MessageTimestamp,
|
||||
.mx_EventTile:hover.mx_EventTile_unverified .mx_MessageTimestamp {
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
/*
|
||||
.mx_EventTile_verified .mx_EventTile_e2eIcon {
|
||||
display: none;
|
||||
}
|
||||
*/
|
||||
|
||||
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_e2eIcon,
|
||||
.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_e2eIcon {
|
||||
display: block;
|
||||
left: 41px;
|
||||
}
|
||||
|
||||
/* Various markdown overrides */
|
||||
|
||||
.mx_EventTile_content .markdown-body {
|
||||
font-family: inherit ! important;
|
||||
white-space: normal ! important;
|
||||
line-height: inherit ! important;
|
||||
color: inherit;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* have to use overlay rather than auto otherwise Linux and Windows
|
||||
Chrome gets very confused about vertical spacing:
|
||||
https://github.com/vector-im/vector-web/issues/754
|
||||
*/
|
||||
.mx_EventTile_content .markdown-body pre {
|
||||
overflow-x: overlay;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
.mx_EventTile_content .markdown-body h1,
|
||||
.mx_EventTile_content .markdown-body h2,
|
||||
.mx_EventTile_content .markdown-body h3,
|
||||
.mx_EventTile_content .markdown-body h4,
|
||||
.mx_EventTile_content .markdown-body h5,
|
||||
.mx_EventTile_content .markdown-body h6
|
||||
{
|
||||
font-family: inherit ! important;
|
||||
}
|
||||
|
||||
.mx_EventTile_content .markdown-body a {
|
||||
color: #76cfa6;
|
||||
}
|
||||
|
||||
.mx_EventTile_content .markdown-body .hljs {
|
||||
display: inline ! important;
|
||||
}
|
||||
|
||||
/* end of overrides */
|
||||
|
||||
@@ -50,7 +50,7 @@ limitations under the License.
|
||||
.mx_LinkPreviewWidget_description {
|
||||
margin-top: 8px;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.mx_LinkPreviewWidget_cancel {
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
.mx_MemberDeviceInfo {
|
||||
padding: 10px 0px;
|
||||
}
|
||||
|
||||
|
||||
.mx_MemberDeviceInfo_textButton {
|
||||
color: #fff;
|
||||
background-color: #76cfa6;
|
||||
border-radius: 17px;
|
||||
text-align: center;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
width: 95px;
|
||||
border: 0px;
|
||||
font-size: 14px;
|
||||
|
||||
cursor: pointer;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.mx_MemberDeviceInfo_deviceId {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.mx_MemberDeviceInfo_deviceInfo {
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.mx_MemberDeviceInfo_block,
|
||||
.mx_MemberDeviceInfo_unblock {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.mx_MemberDeviceInfo div.mx_MemberDeviceInfo_verified,
|
||||
.mx_MemberDeviceInfo div.mx_MemberDeviceInfo_unverified,
|
||||
.mx_MemberDeviceInfo div.mx_MemberDeviceInfo_blocked {
|
||||
float: right;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.mx_MemberDeviceInfo div.mx_MemberDeviceInfo_verified {
|
||||
color: #76cfa5;
|
||||
}
|
||||
|
||||
.mx_MemberDeviceInfo div.mx_MemberDeviceInfo_unverified {
|
||||
color: #e8bf37;
|
||||
}
|
||||
|
||||
.mx_MemberDeviceInfo div.mx_MemberDeviceInfo_blocked {
|
||||
color: #ba6363;
|
||||
}
|
||||
@@ -16,16 +16,30 @@ limitations under the License.
|
||||
|
||||
.mx_MemberInfo {
|
||||
margin-top: 20px;
|
||||
padding-right: 20px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mx_MemberInfo h2 {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.mx_MemberInfo .mx_RoomTile_nameContainer {
|
||||
width: 154px;
|
||||
}
|
||||
|
||||
.mx_MemberInfo .mx_RoomTile_badge {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_MemberInfo .mx_RoomTile_name {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.mx_MemberInfo_cancel {
|
||||
float: right;
|
||||
margin-right: 18px;
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -72,3 +86,13 @@ limitations under the License.
|
||||
margin-left: 8px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.mx_MemberInfo_createRoom {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_MemberInfo_createRoom_label {
|
||||
width: initial ! important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,15 +52,29 @@ limitations under the License.
|
||||
flex: 1 1 0px;
|
||||
}
|
||||
|
||||
.mx_MemberList .mx_SearchableEntityList {
|
||||
order: 1;
|
||||
flex: 0 0 auto;
|
||||
-webkit-flex: 0 0 auto;
|
||||
.mx_MemberList_query {
|
||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #f0f0f0;
|
||||
padding: 9px;
|
||||
color: #454545;
|
||||
background-color: #fff;
|
||||
margin-left: 3px;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
width: 189px;
|
||||
}
|
||||
|
||||
.mx_MemberList .mx_SearchableEntityList_expanded {
|
||||
flex: 1 0 0;
|
||||
-webkit-flex: 1 0 0;
|
||||
.mx_MemberList_query::-moz-placeholder {
|
||||
color: #454545;
|
||||
opacity: 0.5;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mx_MemberList_query::-webkit-input-placeholder {
|
||||
color: #454545;
|
||||
opacity: 0.5;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mx_MemberList_joined {
|
||||
|
||||
@@ -19,18 +19,24 @@ limitations under the License.
|
||||
vertical-align: middle;
|
||||
margin: auto;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_autocomplete_wrapper {
|
||||
position: relative;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_row {
|
||||
display: table-row;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mx_MessageComposer .mx_MessageComposer_avatar {
|
||||
display: table-cell;
|
||||
padding-left: 10px;
|
||||
padding-right: 28px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_MessageComposer .mx_MessageComposer_avatar .mx_BaseAvatar {
|
||||
@@ -41,26 +47,57 @@ limitations under the License.
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_e2eIcon {
|
||||
position: absolute;
|
||||
left: 44px;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_noperm_error {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
height: 60px;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_input_wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_input {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
vertical-align: middle;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 60px;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
font-size: 14px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_input_empty .public-DraftEditorPlaceholder-root {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_input .DraftEditor-root {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
max-height: 120px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_input blockquote {
|
||||
color: rgb(119, 119, 119);
|
||||
margin: 0 0 16px;
|
||||
padding: 0 15px;
|
||||
border-left: 4px solid rgb(221, 221, 221);
|
||||
}
|
||||
|
||||
.mx_MessageComposer_input textarea {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
width: 100%;
|
||||
padding: 0px;
|
||||
margin-top: 6px;
|
||||
@@ -73,7 +110,9 @@ limitations under the License.
|
||||
box-shadow: none;
|
||||
color: #454545;
|
||||
background-color: #fff;
|
||||
|
||||
font-size: 14px;
|
||||
max-height: 120px;
|
||||
overflow: auto;
|
||||
/* needed for FF */
|
||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||
}
|
||||
@@ -92,11 +131,12 @@ limitations under the License.
|
||||
.mx_MessageComposer_hangup,
|
||||
.mx_MessageComposer_voicecall,
|
||||
.mx_MessageComposer_videocall {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
/*display: table-cell;*/
|
||||
/*vertical-align: middle;*/
|
||||
/*padding-left: 10px;*/
|
||||
padding-right: 5px;
|
||||
cursor: pointer;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_upload object,
|
||||
@@ -106,16 +146,59 @@ limitations under the License.
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_videocall {
|
||||
padding-right: 10px;
|
||||
padding-top: 4px;
|
||||
.mx_MessageComposer_formatting {
|
||||
cursor: pointer;
|
||||
margin: 0 11px;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_voicecall {
|
||||
padding-right: 10px;
|
||||
padding-top: 4px;
|
||||
.mx_MessageComposer_formatbar_wrapper {
|
||||
width: 100%;
|
||||
background-color: #f7f7f7;
|
||||
box-shadow: inset 0 1px 0 0 rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.mx_MessageComposer_upload object {
|
||||
margin-top: 5px;
|
||||
.mx_MessageComposer_formatbar {
|
||||
margin: auto;
|
||||
max-width: 960px;
|
||||
display: flex;
|
||||
|
||||
height: 30px;
|
||||
|
||||
box-sizing: border-box;
|
||||
padding-left: 62px;
|
||||
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
font-size: 10px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_formatbar * {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_format_button,
|
||||
.mx_MessageComposer_formatbar_cancel,
|
||||
.mx_MessageComposer_formatbar_markdown {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_format_button_disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_formatbar_cancel {
|
||||
margin-right: 22px;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_formatbar_markdown {
|
||||
margin-right: 64px;
|
||||
}
|
||||
|
||||
.mx_MessageComposer_input_markdownIndicator {
|
||||
cursor: pointer;
|
||||
height: 10px;
|
||||
padding: 4px 4px 4px 0;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,8 @@ limitations under the License.
|
||||
.mx_RoomHeader_rightRow {
|
||||
margin-top: 4px;
|
||||
background-color: #fff;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
-webkit-box-ordinal-group: 3;
|
||||
-moz-box-ordinal-group: 3;
|
||||
-ms-flex-order: 3;
|
||||
@@ -161,13 +162,6 @@ limitations under the License.
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_settingsButton {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
bottom: 10px;
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_settingsButton object {
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -183,10 +177,6 @@ limitations under the License.
|
||||
color: #76cfa6;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_leaveButton {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_placeholder {
|
||||
color: #a2a2a2 ! important;
|
||||
}
|
||||
@@ -243,10 +233,7 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_RoomHeader_button {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
margin-left: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_RoomList {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 12px;
|
||||
min-height: 400px;
|
||||
}
|
||||
@@ -33,3 +32,8 @@ limitations under the License.
|
||||
overflow-x: hidden ! important;
|
||||
overflow-y: scroll ! important;
|
||||
}
|
||||
|
||||
/* Make sure the scrollbar is above the sticky headers from RoomList */
|
||||
.mx_RoomList_scrollbar .gm-scrollbar.-vertical {
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,30 @@ limitations under the License.
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.mx_RoomSettings_leaveButton,
|
||||
.mx_RoomSettings_integrationsButton {
|
||||
height: 36px;
|
||||
background-color: #76cfa6;
|
||||
border-radius: 36px;
|
||||
margin-right: 8px;
|
||||
color: #fff;
|
||||
line-height: 34px;
|
||||
text-align: center;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
.mx_RoomSettings_e2eIcon {
|
||||
padding-left: 4px;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
.mx_RoomSettings_leaveButton {
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.mx_RoomSettings_powerLevels {
|
||||
display: table;
|
||||
}
|
||||
@@ -73,12 +97,14 @@ limitations under the License.
|
||||
height: 37px;
|
||||
border: 1px solid #979797;
|
||||
margin-right: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_RoomSettings .mx_RoomSettings_roomColor_selected {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 4px;
|
||||
cursor: default ! important;
|
||||
}
|
||||
|
||||
.mx_RoomSettings .mx_RoomSettings_roomColorPrimary {
|
||||
|
||||
@@ -15,43 +15,106 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_RoomTile {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
/* This fixes wrapping of long room names, but breaks drag & drop previews */
|
||||
/* display: table-row; */
|
||||
font-size: 13px;
|
||||
display: block;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_tooltip {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: -54px;
|
||||
left: -12px;
|
||||
}
|
||||
|
||||
|
||||
.mx_RoomTile_nameContainer {
|
||||
display: inline-block;
|
||||
width: 180px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_avatar_container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mx_RoomTile_avatar {
|
||||
display: table-cell;
|
||||
padding-right: 11px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
padding-left: 18px;
|
||||
display: inline-block;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 16px;
|
||||
padding-right: 6px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_RoomTile_dm {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: -5px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.mx_RoomTile:hover .mx_RoomTile_avatar_container:before,
|
||||
.mx_RoomTile_avatar_container.mx_RoomTile_avatar_roomTagMenu:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
content: "";
|
||||
border-radius: 40px;
|
||||
background-image: url("img/icons_ellipsis.svg");
|
||||
background-size: 25px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.mx_RoomTile:hover .mx_RoomTile_avatar_container:after,
|
||||
.mx_RoomTile_avatar_container.mx_RoomTile_avatar_roomTagMenu:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
content: "";
|
||||
border-radius: 40px;
|
||||
background: #4A4A4A;
|
||||
bottom: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
opacity: 0.6;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomTile:hover .mx_RoomTile_avatar_container:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomTile:hover .mx_RoomTile_avatar_container:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RoomTile_name {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 165px;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
padding-right: 15px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 3px;
|
||||
color: rgba(69, 69, 69, 0.8);
|
||||
}
|
||||
|
||||
.mx_RoomTile_ellipsis .mx_RoomTile_name {
|
||||
font-style: italic;
|
||||
color: #454545;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mx_RoomTile_invite {
|
||||
/* color: rgba(69, 69, 69, 0.5);
|
||||
*/
|
||||
/* color: rgba(69, 69, 69, 0.5); */
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomTile_nameContainer {
|
||||
width: 60px; /* colapsed panel width */
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomTile_name {
|
||||
@@ -59,23 +122,56 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomTile_badge {
|
||||
margin-top: -15px;
|
||||
right: 7px;
|
||||
top: 0px;
|
||||
min-width: 12px;
|
||||
border-radius: 16px;
|
||||
padding: 0px 4px 0px 4px;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
/* Hide the bottom of speech bubble */
|
||||
.collapsed .mx_RoomTile_highlight .mx_RoomTile_badge:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* This is the bottom of the speech bubble */
|
||||
.mx_RoomTile_highlight .mx_RoomTile_badge:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: 5px;
|
||||
border-top: 5px solid #ff0064;
|
||||
border-right: 7px solid transparent;
|
||||
}
|
||||
|
||||
.mx_RoomTile_badge {
|
||||
min-width: 12px;
|
||||
height: 16px;
|
||||
display: inline-block;
|
||||
min-width: 15px;
|
||||
height: 15px;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 50%;
|
||||
margin-top: -8px;
|
||||
border-radius: 16px;
|
||||
right: 8px; /*gutter */
|
||||
top: 9px;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
padding: 0px 4px 0px 4px;
|
||||
padding-top: 1px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.mx_RoomTile .mx_RoomTile_badge.mx_RoomTile_badgeButton,
|
||||
.mx_RoomTile.mx_RoomTile_notificationStateMenu .mx_RoomTile_badge {
|
||||
letter-spacing: 0.1em;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.mx_RoomTile.mx_RoomTile_noBadges .mx_RoomTile_badge.mx_RoomTile_badgeButton,
|
||||
.mx_RoomTile.mx_RoomTile_notificationStateMenu.mx_RoomTile_noBadges .mx_RoomTile_badge {
|
||||
background-color: rgb(214, 214, 214);
|
||||
}
|
||||
|
||||
.mx_RoomTile_unreadNotify .mx_RoomTile_badge {
|
||||
@@ -86,41 +182,16 @@ limitations under the License.
|
||||
background-color: #ff0064;
|
||||
}
|
||||
|
||||
.mx_RoomTile_unread,
|
||||
.mx_RoomTile_highlight {
|
||||
font-weight: bold;
|
||||
.mx_RoomTile_unread, .mx_RoomTile_highlight {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
/* the inner highlight span has 4px of padding on it, so we shrink the _avatar by 4px and grow the _name by 4px to fit it in */
|
||||
.mx_RoomTile_selected .mx_RoomTile_name {
|
||||
padding-right: 19px;
|
||||
}
|
||||
.mx_RoomTile_selected .mx_RoomTile_avatar {
|
||||
padding-right: 7px;
|
||||
.mx_RoomTile_selected {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
/* leave room for the badge, if present.
|
||||
N.B. this has to come after the above _selected width tweaks */
|
||||
.mx_RoomTile_unreadNotify .mx_RoomTile_name,
|
||||
.mx_RoomTile_highlight .mx_RoomTile_name {
|
||||
padding-right: 40px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_selected .mx_RoomTile_name span {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 4px;
|
||||
margin-top: -4px;
|
||||
margin-bottom: -4px;
|
||||
border-radius: 2px;
|
||||
background-color: rgba(118,207,166,0.2);
|
||||
}
|
||||
|
||||
/* stop the span from overlapping with the badge */
|
||||
.mx_RoomTile_unreadNotify.mx_RoomTile_selected .mx_RoomTile_name span,
|
||||
.mx_RoomTile_highlight.mx_RoomTile_selected .mx_RoomTile_name span {
|
||||
padding-right: 22px;
|
||||
.mx_RoomTile .mx_RoomTile_name.mx_RoomTile_badgeShown {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_arrow {
|
||||
@@ -128,5 +199,3 @@ limitations under the License.
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.mx_RoomTile:hover {
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ limitations under the License.
|
||||
padding-bottom: 2px;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 30px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.mx_TabCompleteBar_command .mx_TabCompleteBar_text {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
.mx_DevicesPanel {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 880px;
|
||||
border-spacing: 2px;
|
||||
}
|
||||
|
||||
.mx_DevicesPanel_header {
|
||||
display: table-header-group;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mx_DevicesPanel_header > div {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.mx_DevicesPanel_header .mx_DevicesPanel_deviceLastSeen {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.mx_DevicesPanel_header .mx_DevicesPanel_deviceButtons {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.mx_DevicesPanel_device {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.mx_DevicesPanel_device > div {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.mx_DevicesPanel_myDevice {
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_IntegrationsManager .mx_Dialog {
|
||||
width: 60%;
|
||||
height: 70%;
|
||||
overflow: hidden;
|
||||
padding: 0px;
|
||||
max-width: initial;
|
||||
max-height: initial;
|
||||
}
|
||||
|
||||
.mx_IntegrationsManager iframe {
|
||||
background-color: #fff;
|
||||
border: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -12,4 +12,14 @@ 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_CallView_voice {
|
||||
background-color: #76cfa6;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
padding: 6px;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Open Sans
|
||||
* Includes extended Latin, Greek, Cyrillic and Vietnamese character sets
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('fonts/Open_Sans/OpenSans-Regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('fonts/Open_Sans/OpenSans-Italic.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('fonts/Open_Sans/OpenSans-Semibold.ttf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('fonts/Open_Sans/OpenSans-SemiboldItalic.ttf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('fonts/Open_Sans/OpenSans-Bold.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('fonts/Open_Sans/OpenSans-BoldItalic.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fira Mono
|
||||
* Used for monospace copy, i.e. code
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Fira Mono';
|
||||
src: url('fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Fira Mono';
|
||||
src: url('fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -49,6 +49,11 @@ limitations under the License.
|
||||
flex: 1 1 0;
|
||||
|
||||
overflow-y: auto;
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
.mx_LeftPanel.collapsed .mx_BottomLeftMenu {
|
||||
flex: 0 0 160px;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_BottomLeftMenu {
|
||||
@@ -58,11 +63,12 @@ limitations under the License.
|
||||
-webkit-order: 3;
|
||||
order: 3;
|
||||
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
margin-left: 18px;
|
||||
margin-right: 18px;
|
||||
border-top: 1px solid rgba(118, 207, 166, 0.2);
|
||||
margin-left: 16px; /* gutter */
|
||||
margin-right: 16px; /* gutter */
|
||||
-webkit-flex: 0 0 60px;
|
||||
flex: 0 0 60px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_options {
|
||||
@@ -73,25 +79,40 @@ limitations under the License.
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_createRoom,
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_directory,
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_createRoom,
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_people,
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_settings {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapsed .mx_BottomLeftMenu_createRoom,
|
||||
.collapsed .mx_BottomLeftMenu_directory,
|
||||
.collapsed .mx_BottomLeftMenu_createRoom,
|
||||
.collapsed .mx_BottomLeftMenu_people,
|
||||
.collapsed .mx_BottomLeftMenu_settings {
|
||||
margin-left: 0px ! important;
|
||||
margin-right: 0px ! important;
|
||||
padding-top: 3px ! important;
|
||||
padding-bottom: 3px ! important;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_directory {
|
||||
margin-left: 10px;
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_directory,
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_createRoom,
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_people {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_settings {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_BottomLeftMenu_tooltip {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: -25px;
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
@@ -43,46 +43,39 @@ limitations under the License.
|
||||
/** Fixme - factor this out with the main header **/
|
||||
|
||||
.mx_RightPanel_headerButtonGroup {
|
||||
margin-top: 25px;
|
||||
margin-top: 6px;
|
||||
float: left;
|
||||
background-color: #fff;
|
||||
margin-left: -4px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.mx_RightPanel_headerButton {
|
||||
cursor: pointer;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
vertical-align: top;
|
||||
padding-left: 4px;
|
||||
padding-right: 5px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mx_RightPanel_headerButton object {
|
||||
pointer-events: none;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.mx_RightPanel_headerButton_highlight {
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 10px;
|
||||
width: 25px;
|
||||
height: 4px;
|
||||
background-color: #76cfa6;
|
||||
height: 5px;
|
||||
border-radius: 5px;
|
||||
background-color: rgba(118, 207, 166, 0.2);
|
||||
}
|
||||
|
||||
.mx_RightPanel_headerButton_badge {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 28px;
|
||||
font-size: 12px;
|
||||
background-color: #76cfa6;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
color: #76cfa6;
|
||||
font-weight: bold;
|
||||
border-radius: 20px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.mx_RightPanel .mx_MemberList,
|
||||
@@ -93,8 +86,8 @@ limitations under the License.
|
||||
-ms-flex-order: 2;
|
||||
-webkit-order: 2;
|
||||
order: 2;
|
||||
flex: 1;
|
||||
-webkit-flex: 1;
|
||||
flex: 1 1 0;
|
||||
-webkit-flex: 1 1 0;
|
||||
}
|
||||
|
||||
.mx_RightPanel_footer {
|
||||
@@ -110,3 +103,30 @@ limitations under the License.
|
||||
-webkit-flex: 0 0 60px;
|
||||
flex: 0 0 60px;
|
||||
}
|
||||
|
||||
.mx_RightPanel_footer .mx_RightPanel_invite {
|
||||
line-height: 35px;
|
||||
font-size: 14px;
|
||||
color: #4A4A4A;
|
||||
padding-top: 13px;
|
||||
padding-left: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapsed .mx_RightPanel_footer .mx_RightPanel_invite {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RightPanel_invite .mx_RightPanel_icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mx_RightPanel_invite .mx_RightPanel_icon object {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mx_RightPanel_invite .mx_RightPanel_message {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
padding-left: 10px
|
||||
}
|
||||
|
||||
@@ -46,15 +46,27 @@ limitations under the License.
|
||||
-webkit-flex-direction: column;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_input {
|
||||
margin: auto;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #c7c7c7;
|
||||
font-weight: 300;
|
||||
font-size: 13px;
|
||||
padding: 9px;
|
||||
.mx_RoomDirectory_list .mx_RoomView_messageListWrapper {
|
||||
justify-content: flex-start;
|
||||
-webkit-justify-content: flex-start;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_listheader {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
border-spacing: 5px;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_searchbox {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_listheader .mx_NetworkDropdown {
|
||||
display: table-cell;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_tableWrapper {
|
||||
|
||||
@@ -20,23 +20,222 @@ limitations under the License.
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_labelContainer {
|
||||
height: 31px; /* mx_RoomSubList_label height including border */
|
||||
width: 235px; /* LHS Panel width */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_label {
|
||||
position: relative;
|
||||
text-transform: uppercase;
|
||||
color: #3d3b39;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
width: 203px; /* padding + width = LHS Panel width */
|
||||
height: 17px; /* padding + height = 29px, same as mx_RoomSubList_stickyContainer */
|
||||
padding-left: 16px; /* gutter */
|
||||
padding-right: 16px; /* gutter */
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
cursor: pointer;
|
||||
background-color: #d3efe1;
|
||||
border-top: solid 2px #eaf5f0;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_label.mx_RoomSubList_fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
/* pointer-events: none; */
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomSubList_label {
|
||||
height: 17px;
|
||||
width: 28px; /* collapsed LHS Panel width */
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomSubList_labelContainer {
|
||||
width: 28px; /* collapsed LHS Panel width */
|
||||
}
|
||||
|
||||
.mx_RoomSubList_roomCount {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
color: #76cfa6;
|
||||
padding-left: 5px;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomSubList_roomCount {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_badge {
|
||||
display: inline-block;
|
||||
min-width: 15px;
|
||||
height: 15px;
|
||||
position: absolute;
|
||||
right: 8px; /*gutter */
|
||||
top: 7px;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
padding-top: 1px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
background-color: #76cfa6;
|
||||
}
|
||||
|
||||
/*
|
||||
.collapsed .mx_RoomSubList_badge {
|
||||
display: none;
|
||||
}
|
||||
*/
|
||||
|
||||
.mx_RoomSubList_badgeHighlight {
|
||||
background-color: #ff0064;
|
||||
}
|
||||
|
||||
/* This is the bottom of the speech bubble */
|
||||
.mx_RoomSubList_badgeHighlight:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: 5px;
|
||||
border-top: 5px solid #ff0064;
|
||||
border-right: 7px solid transparent;
|
||||
}
|
||||
|
||||
/* Hide the bottom of speech bubble */
|
||||
.collapsed .mx_RoomSubList_badgeHighlight:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_chevron {
|
||||
padding-left: 4px;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: 41px;
|
||||
top: 11px;
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomSubList_chevron {
|
||||
padding-left: 12px;
|
||||
.mx_RoomSubList_chevronDown {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-top: 6px solid #76cfa6;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_chevronUp {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-bottom: 6px solid #76cfa6;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_chevronRight {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 5px solid transparent;
|
||||
border-left: 6px solid #76cfa6;
|
||||
border-bottom: 5px solid transparent;
|
||||
}
|
||||
|
||||
/* The overflow section */
|
||||
.mx_RoomSubList_ellipsis {
|
||||
display: block;
|
||||
line-height: 11px;
|
||||
height: 18px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomSubList_ellipsis {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_line {
|
||||
display: inline-block;
|
||||
width: 159px;
|
||||
border-top: dotted 2px #76cfa6;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomSubList_line {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_more {
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
color: #76cfa6;
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
padding-left: 7px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomSubList_more {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_moreBadge {
|
||||
display: inline-block;
|
||||
min-width: 15px;
|
||||
height: 13px;
|
||||
position: absolute;
|
||||
right: 8px; /*gutter */
|
||||
top: -2px;
|
||||
border-radius: 8px;
|
||||
border: solid 1px #76cfa6;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
padding-top: 1px;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
background-color: #fff;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_moreBadge.mx_RoomSubList_moreBadgeNotify {
|
||||
background-color: #76cfa6;
|
||||
border: 0;
|
||||
padding-top: 3px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_moreBadge.mx_RoomSubList_moreBadgeHighlight {
|
||||
background-color: #ff0064;
|
||||
border: 0;
|
||||
padding-top: 3px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.collapsed .mx_RoomSubList_moreBadge {
|
||||
position: static;
|
||||
margin-left: 16px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.mx_RoomSubList_ellipsis .mx_RoomSubList_chevronDown {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
left: 2px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_MessageContextMenu_field {
|
||||
padding: 3px 6px 3px 6px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mx_MessageContextMenu_field.mx_MessageContextMenu_fieldSet {
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_NotificationStateContextMenu_picker {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.mx_NotificationStateContextMenu_field {
|
||||
padding-top: 4px;
|
||||
padding-right: 6px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 8px; /* 20px */
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mx_NotificationStateContextMenu_field.mx_NotificationStateContextMenu_fieldSet {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mx_NotificationStateContextMenu_field.mx_NotificationStateContextMenu_fieldDisabled {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.mx_NotificationStateContextMenu_icon {
|
||||
padding-right: 4px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.mx_NotificationStateContextMenu_activeIcon {
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
position: relative;
|
||||
left: -5px;
|
||||
}
|
||||
|
||||
.mx_NotificationStateContextMenu_fieldSet .mx_NotificationStateContextMenu_activeIcon {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_RoomTagContextMenu_field {
|
||||
padding-top: 8px;
|
||||
padding-right: 20px;
|
||||
padding-bottom: 8px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_field:first-child {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_field:last-child {
|
||||
padding-bottom: 4px;
|
||||
color: #ff0064;
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_field.mx_RoomTagContextMenu_fieldSet {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_field.mx_RoomTagContextMenu_fieldSet .mx_RoomTagContextMenu_icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_field.mx_RoomTagContextMenu_fieldSet .mx_RoomTagContextMenu_icon_set {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_field.mx_RoomTagContextMenu_fieldDisabled {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_icon {
|
||||
padding-right: 8px;
|
||||
padding-left: 4px;
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_icon_set {
|
||||
padding-right: 8px;
|
||||
padding-left: 4px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_separator {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
border-right-style: none;
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
border-color: #bbbbbb;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.mx_RoomTagContextMenu_fieldSet .mx_RoomTagContextMenu_icon {
|
||||
/* Something to indicate that the icon is the set tag */
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2016 Aviral Dasgupta
|
||||
|
||||
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_ChangelogDialog_content {
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.mx_ChangelogDialog_li {
|
||||
padding: 0.2em;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_NetworkDropdown {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mx_NetworkDropdown_input {
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #c7c7c7;
|
||||
font-weight: 300;
|
||||
font-size: 13px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.mx_NetworkDropdown_arrow {
|
||||
border-color: #4a4a4a transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 5px 0;
|
||||
display: block;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 14px;
|
||||
width: 0
|
||||
}
|
||||
|
||||
.mx_NetworkDropdown_networkoption {
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.mx_NetworkDropdown_networkoption img {
|
||||
margin: 5px;
|
||||
width: 25px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
input.mx_NetworkDropdown_networkoption, input.mx_NetworkDropdown_networkoption:focus {
|
||||
border: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.mx_NetworkDropdown_menu {
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
right: -1px;
|
||||
top: 100%;
|
||||
z-index: 2;
|
||||
margin: 0;
|
||||
padding: 0px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #76cfa6;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.mx_NetworkDropdown_menu .mx_NetworkDropdown_networkoption:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.mx_NetworkDropdown_menu_network {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ limitations under the License.
|
||||
.mx_ImageView_labelWrapper {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
pointer-events: all;
|
||||
|
||||
@@ -33,6 +33,11 @@ limitations under the License.
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.mx_MatrixToolbar_content {
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mx_MatrixToolbar_link
|
||||
{
|
||||
color: #fff ! important;
|
||||
@@ -41,10 +46,7 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_MatrixToolbar_close {
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mx_MatrixToolbar_close img {
|
||||
@@ -52,3 +54,7 @@ limitations under the License.
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.mx_MatrixToolbar_action {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@ limitations under the License.
|
||||
|
||||
.mx_RoomDropTarget {
|
||||
font-size: 13px;
|
||||
margin-left: 10px;
|
||||
margin-right: 15px;
|
||||
margin-left: 18px;
|
||||
margin-right: 18px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 7px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border: 1px dashed #76cfa6;
|
||||
@@ -28,6 +30,7 @@ limitations under the License.
|
||||
|
||||
.collapsed .mx_RoomDropTarget {
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.mx_RoomDropTarget_placeholder {
|
||||
|
||||
@@ -14,19 +14,40 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_RoomTooltip_chevron {
|
||||
position: absolute;
|
||||
left: -8px;
|
||||
top: 4px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 8px solid transparent;
|
||||
border-right: 8px solid rgba(187, 187, 187, 0.5);
|
||||
border-bottom: 8px solid transparent;
|
||||
}
|
||||
|
||||
.mx_RoomTooltip_chevron:after{
|
||||
content:'';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 7px solid transparent;
|
||||
border-right: 7px solid #fff;
|
||||
border-bottom: 7px solid transparent;
|
||||
position:absolute;
|
||||
top: -7px;
|
||||
left: 1px;
|
||||
}
|
||||
|
||||
.mx_RoomTooltip {
|
||||
display: none;
|
||||
position: fixed;
|
||||
border: 1px solid #a4a4a4;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(187, 187, 187, 0.5);
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
z-index: 1000;
|
||||
left: 64px;
|
||||
padding: 6px;
|
||||
z-index: 2000;
|
||||
padding: 5px;
|
||||
pointer-events: none;
|
||||
line-height: 14px;
|
||||
font-size: 13px;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.mx_RoomTooltip_chevron {
|
||||
position: absolute;
|
||||
left: -9px;
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
@@ -21,20 +21,20 @@ limitations under the License.
|
||||
|
||||
.mx_UserNotifSettings_inputCell {
|
||||
display: table-cell;
|
||||
padding-bottom: 21px;
|
||||
padding-bottom: 8px;
|
||||
padding-right: 8px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.mx_UserNotifSettings_labelCell
|
||||
{
|
||||
padding-bottom: 21px;
|
||||
padding-bottom: 8px;
|
||||
width: 400px;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.mx_UserNotifSettings_pushRulesTableWrapper {
|
||||
padding-bottom: 21px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.mx_UserNotifSettings_pushRulesTable {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Executable
+92
@@ -0,0 +1,92 @@
|
||||
Copyright (c) 2012-2013, The Mozilla Corporation and Telefonica S.A.
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
@@ -1,48 +0,0 @@
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Lato Light'), local('Lato-Light'), url(IY9HZVvI1cMoAHxvl0w9LVKPGs1ZzpMvnHX-7fPOuAc.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Lato Light'), local('Lato-Light'), url(22JRxvfANxSmnAhzbFH8PgLUuEpTyoUstqEm5AMlJo4.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Lato Regular'), local('Lato-Regular'), url(8qcEw_nrk_5HEcCpYdJu8BTbgVql8nDJpwnrE27mub0.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Lato Regular'), local('Lato-Regular'), url(MDadn8DQ_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Lato Bold'), local('Lato-Bold'), url(rZPI2gHXi8zxUjnybc2ZQFKPGs1ZzpMvnHX-7fPOuAc.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Lato Bold'), local('Lato-Bold'), url(MgNNr5y1C_tIEuLEmicLmwLUuEpTyoUstqEm5AMlJo4.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,24 +0,0 @@
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans'), local('OpenSans'), url(opensans/v13/cJZKeOuBrn4kERxqtaUH3ZBw1xU1rKptJj_0jans920.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(opensans/v13/MTP_ySUJH_bn48VBG8sNShampu5_7CjHW5spxoeN3Vs.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url(opensans/v13/k3k702ZOKiLJc3WVjuplzBampu5_7CjHW5spxoeN3Vs.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
Executable
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user