Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22060ac5a4 | ||
|
|
3f3a31e475 | ||
|
|
231306ea7c | ||
|
|
e1c1937855 | ||
|
|
9471c30f89 | ||
|
|
40545bd48e | ||
|
|
6b02bf8e8c | ||
|
|
0d05e607f0 | ||
|
|
717aa94ba9 | ||
|
|
9caba57c14 | ||
|
|
70f48343ee | ||
|
|
f17f103d12 | ||
|
|
27e311f7e8 | ||
|
|
5258bf9c84 | ||
|
|
10f0631487 | ||
|
|
97fc92b1bb | ||
|
|
06718c580e | ||
|
|
15528ef8d7 | ||
|
|
b71f96e4e5 | ||
|
|
278de1398b | ||
|
|
c5459a2f19 | ||
|
|
6a1af891b7 | ||
|
|
b0319ec0f1 | ||
|
|
b06d045188 | ||
|
|
79d164309f | ||
|
|
f2afcc0bc8 | ||
|
|
43f82cd95d | ||
|
|
2b70cb436e | ||
|
|
9a861f46d0 | ||
|
|
bb28903c8e | ||
|
|
e8eadc5d20 | ||
|
|
e741a4f294 | ||
|
|
1678a25fd6 | ||
|
|
ff70b0a2c8 | ||
|
|
3803c64226 | ||
|
|
35a541c824 | ||
|
|
ab8420f5a9 | ||
|
|
fa46757830 | ||
|
|
ed35a90cfb | ||
|
|
d8bce0f202 | ||
|
|
e6f600bb47 | ||
|
|
519af6a5d0 | ||
|
|
c6c4aff8ae | ||
|
|
6d4abac016 | ||
|
|
d34cb80b68 | ||
|
|
57641f7228 | ||
|
|
9ae86f2585 | ||
|
|
1e7e9d6101 | ||
|
|
8bbc16ed4b | ||
|
|
4745b3efeb | ||
|
|
09f79b94dd | ||
|
|
42357dee0b | ||
|
|
2e73cd6c4d | ||
|
|
161978ab05 | ||
|
|
994bc9279f | ||
|
|
fb08910db3 | ||
|
|
e607f49ae6 | ||
|
|
52cf1f6a4b | ||
|
|
61f9966fe0 | ||
|
|
5f7cdb8d42 | ||
|
|
901c0e7e41 | ||
|
|
98cad8779c | ||
|
|
fc597ba86e | ||
|
|
f5bd8abfda | ||
|
|
8be72e6c27 | ||
|
|
2740013625 | ||
|
|
119e03b64f | ||
|
|
c6dbeee245 | ||
|
|
feb3a13a71 | ||
|
|
c80d1c15d2 |
@@ -3,4 +3,5 @@ node_js:
|
||||
- 6 # node v6, to match jenkins
|
||||
install:
|
||||
- npm install
|
||||
- (cd node_modules/matrix-js-sdk && npm install)
|
||||
- (cd node_modules/matrix-react-sdk && npm run build)
|
||||
|
||||
66
CHANGELOG.md
66
CHANGELOG.md
@@ -1,3 +1,67 @@
|
||||
Changes in [0.9.6](https://github.com/vector-im/riot-web/releases/tag/v0.9.6) (2017-01-16)
|
||||
==========================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.6-rc.1...v0.9.6)
|
||||
|
||||
* Update to matrix-js-sdk 0.9.6 for video calling fix
|
||||
|
||||
Changes in [0.9.6-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.6-rc.1) (2017-01-13)
|
||||
====================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.5...v0.9.6-rc.1)
|
||||
|
||||
* Build the js-sdk in the CI script
|
||||
[\#2920](https://github.com/vector-im/riot-web/pull/2920)
|
||||
* Hopefully fix Windows shortcuts
|
||||
[\#2917](https://github.com/vector-im/riot-web/pull/2917)
|
||||
* Update README now the js-sdk has a transpile step
|
||||
[\#2921](https://github.com/vector-im/riot-web/pull/2921)
|
||||
* Use the role for 'toggle dev tools'
|
||||
[\#2915](https://github.com/vector-im/riot-web/pull/2915)
|
||||
* Enable screen sharing easter-egg in desktop app
|
||||
[\#2909](https://github.com/vector-im/riot-web/pull/2909)
|
||||
* make electron send email validation URLs with a nextlink of riot.im
|
||||
[\#2808](https://github.com/vector-im/riot-web/pull/2808)
|
||||
* add Debian Stretch install steps to readme
|
||||
[\#2809](https://github.com/vector-im/riot-web/pull/2809)
|
||||
* Update desktop build instructions fixes #2792
|
||||
[\#2793](https://github.com/vector-im/riot-web/pull/2793)
|
||||
* CSS for the delete threepid button
|
||||
[\#2784](https://github.com/vector-im/riot-web/pull/2784)
|
||||
|
||||
Changes in [0.9.5](https://github.com/vector-im/riot-web/releases/tag/v0.9.5) (2016-12-24)
|
||||
==========================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.4...v0.9.5)
|
||||
|
||||
* make electron send email validation URLs with a nextlink of riot.im rather than file:///
|
||||
* add gnu-tar to debian electron build deps
|
||||
* fix win32 shortcut in start menu
|
||||
|
||||
Changes in [0.9.4](https://github.com/vector-im/riot-web/releases/tag/v0.9.4) (2016-12-22)
|
||||
==========================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.3...v0.9.4)
|
||||
|
||||
* Update to libolm 2.1.0. This should help resolve a problem with browser
|
||||
sessions being logged out ([\#2726](https://github.com/vector-im/riot-web/issues/2726)).
|
||||
|
||||
Changes in [0.9.3](https://github.com/vector-im/riot-web/releases/tag/v0.9.3) (2016-12-22)
|
||||
==========================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.2...v0.9.3)
|
||||
|
||||
* (from matrix-react-sdk) Fix regression where the date separator would be displayed
|
||||
at the wrong time of day.
|
||||
* README.md: fix GFMD for nativefier
|
||||
[\#2755](https://github.com/vector-im/riot-web/pull/2755)
|
||||
|
||||
Changes in [0.9.2](https://github.com/vector-im/riot-web/releases/tag/v0.9.2) (2016-12-16)
|
||||
==========================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.1...v0.9.2)
|
||||
|
||||
* Remove the client side filtering from the room dir
|
||||
[\#2750](https://github.com/vector-im/riot-web/pull/2750)
|
||||
* Configure olm memory size
|
||||
[\#2745](https://github.com/vector-im/riot-web/pull/2745)
|
||||
* Support room dir 3rd party network filtering
|
||||
[\#2747](https://github.com/vector-im/riot-web/pull/2747)
|
||||
|
||||
Changes in [0.9.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.1) (2016-12-09)
|
||||
==========================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.1-rc.2...v0.9.1)
|
||||
@@ -98,7 +162,7 @@ Changes in [0.9.0](https://github.com/vector-im/vector-web/releases/tag/v0.9.0)
|
||||
* Implement Platforms
|
||||
[\#2531](https://github.com/vector-im/vector-web/pull/2531)
|
||||
|
||||
hanges in [0.8.4](https://github.com/vector-im/vector-web/releases/tag/v0.8.4) (2016-11-04)
|
||||
Changes in [0.8.4](https://github.com/vector-im/vector-web/releases/tag/v0.8.4) (2016-11-04)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.4-rc.2...v0.8.4)
|
||||
|
||||
|
||||
66
README.md
66
README.md
@@ -25,6 +25,14 @@ Note that Chrome does not allow microphone or webcam access for sites served
|
||||
over http (except localhost), so for working VoIP you will need to serve Riot
|
||||
over https.
|
||||
|
||||
### Installation Steps for Debian Stretch
|
||||
1. Add the repository to your sources.list using either of the following two options:
|
||||
- Directly to sources.list: `echo "deb https://riot.im/packages/debian/ stretch main" | sudo tee -a /etc/apt/sources.list`
|
||||
- As a separate entry in sources.list.d: `echo "deb https://riot.im/packages/debian/ stretch main" | sudo tee /etc/apt/sources.list.d/riot.list`
|
||||
2. Add the gpg signing key for the riot repository: `curl -s https://riot.im/packages/debian/repo-key.asc | sudo apt-key add -`
|
||||
3. Update your package lists: `sudo apt-get update`
|
||||
4. Install Riot: `sudo apt-get install riot-web`
|
||||
|
||||
Important Security Note
|
||||
=======================
|
||||
|
||||
@@ -49,9 +57,13 @@ to build.
|
||||
1. Switch to the vector-web directory: `cd vector-web`
|
||||
1. Install the prerequisites: `npm install`
|
||||
1. If you are using the `develop` branch of vector-web, 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)`
|
||||
to rebuild some of the dependencies, due to
|
||||
https://github.com/npm/npm/issues/3055:
|
||||
|
||||
```
|
||||
(cd node_modules/matrix-js-sdk && npm install)
|
||||
(cd node_modules/matrix-react-sdk && npm install)
|
||||
```
|
||||
1. Configure the app by copying `config.sample.json` to `config.json` and
|
||||
modifying it (see below for details)
|
||||
1. `npm run dist` to build a tarball to deploy. Untaring this file will give
|
||||
@@ -81,35 +93,12 @@ You can configure the app by copying `config.sample.json` to
|
||||
and https://vector.im. In future identity servers will be decentralised.
|
||||
1. `integrations_ui_url`: URL to the web interface for the integrations server.
|
||||
1. `integrations_rest_url`: URL to the REST interface for the integrations server.
|
||||
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`: config for the public room directory. 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.
|
||||
1. `update_base_url` (electron app only): HTTPS URL to a web server to download
|
||||
updates from. This should be the path to the directory containing `install`
|
||||
and `update`.
|
||||
updates from. This should be the path to the directory containing `macos`
|
||||
and `win32` (for update packages, not installer packages).
|
||||
1. `cross_origin_renderer_url`: URL to a static HTML page hosting code to help display
|
||||
encrypted file attachments. This MUST be hosted on a completely separate domain to
|
||||
anything else since it is used to isolate the privileges of file attachments to this
|
||||
@@ -127,6 +116,7 @@ To run as a desktop app:
|
||||
```
|
||||
npm install
|
||||
npm install electron
|
||||
npm run build
|
||||
node_modules/.bin/electron .
|
||||
```
|
||||
|
||||
@@ -144,6 +134,7 @@ The only platform that can build packages for all three platforms is macOS:
|
||||
```
|
||||
brew install wine --without-x11
|
||||
brew install mono
|
||||
brew install gnu-tar
|
||||
npm install
|
||||
npm run build:electron
|
||||
```
|
||||
@@ -163,10 +154,11 @@ Many thanks to @aviraldg for the initial work on the electron integration.
|
||||
Other options for running as a desktop app:
|
||||
* https://github.com/krisak/vector-electron-desktop
|
||||
* @asdf:matrix.org points out that you can use nativefier and it just works(tm)
|
||||
```
|
||||
sudo npm install nativefier -g
|
||||
nativefier https://riot.im/app/
|
||||
```
|
||||
|
||||
```
|
||||
sudo npm install nativefier -g
|
||||
nativefier https://riot.im/app/
|
||||
```
|
||||
|
||||
Development
|
||||
===========
|
||||
@@ -253,10 +245,10 @@ Finally, build and start Riot itself:
|
||||
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 Riot.
|
||||
|
||||
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.
|
||||
When you make changes to `matrix-react-sdk` or `matrix-js-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 Riot skin, you will need to rebuild
|
||||
the skin's index by running, `npm run reskindex`.
|
||||
|
||||
@@ -8,64 +8,6 @@
|
||||
"roomDirectory": {
|
||||
"servers": [
|
||||
"matrix.org"
|
||||
],
|
||||
"serverConfig": {
|
||||
"matrix.org": {
|
||||
"networks": [
|
||||
"_matrix",
|
||||
"gitter",
|
||||
"irc:freenode",
|
||||
"irc:mozilla",
|
||||
"irc:snoonet",
|
||||
"irc:oftc"
|
||||
]
|
||||
}
|
||||
},
|
||||
"networks": {
|
||||
"gitter": {
|
||||
"protocol": "gitter",
|
||||
"portalRoomPattern": "#gitter_.*:matrix.org",
|
||||
"name": "Gitter",
|
||||
"icon": "//gitter.im/favicon.ico",
|
||||
"example": "org/community",
|
||||
"nativePattern": "[^\\s]+/[^\\s]+$"
|
||||
},
|
||||
"irc:freenode": {
|
||||
"protocol": "irc",
|
||||
"domain": "chat.freenode.net",
|
||||
"portalRoomPattern": "#freenode_.*:matrix.org",
|
||||
"name": "Freenode",
|
||||
"icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
||||
"example": "#channel",
|
||||
"nativePattern": "^#[^\\s]+$"
|
||||
},
|
||||
"irc:mozilla": {
|
||||
"protocol": "irc",
|
||||
"domain": "irc.mozilla.org",
|
||||
"portalRoomPattern": "#mozilla_.*:matrix.org",
|
||||
"name": "Mozilla",
|
||||
"icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
||||
"example": "#channel",
|
||||
"nativePattern": "^#[^\\s]+$"
|
||||
},
|
||||
"irc:snoonet": {
|
||||
"protocol": "irc",
|
||||
"domain": "ipv6-irc.snoonet.org",
|
||||
"portalRoomPattern": "#_snoonet_.*:matrix.org",
|
||||
"name": "Snoonet",
|
||||
"icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
||||
"example": "#channel",
|
||||
"nativePattern": "^#[^\\s]+$"
|
||||
},
|
||||
"irc:oftc": {
|
||||
"protocol": "irc",
|
||||
"domain": "irc.oftc.net",
|
||||
"portalRoomPattern": "#_oftc_.*:matrix.org",
|
||||
"name": "OFTC",
|
||||
"icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
||||
"example": "#channel",
|
||||
"nativePattern": "^#[^\\s]+$"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 21 KiB |
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"update_base_url": "https://riot.im/download/desktop/",
|
||||
"update_base_url": "https://riot.im/download/desktop/update/",
|
||||
"default_hs_url": "https://matrix.org",
|
||||
"default_is_url": "https://vector.im",
|
||||
"brand": "Riot",
|
||||
|
||||
@@ -148,6 +148,8 @@ process.on('uncaughtException', function (error) {
|
||||
|
||||
electron.ipcMain.on('install_update', installUpdate);
|
||||
|
||||
electron.app.commandLine.appendSwitch('--enable-usermedia-screen-capturing');
|
||||
|
||||
electron.app.on('ready', () => {
|
||||
if (vectorConfig.update_base_url) {
|
||||
console.log("Starting auto update with base URL: " + vectorConfig.update_base_url);
|
||||
|
||||
@@ -3,7 +3,12 @@ const spawn = require('child_process').spawn;
|
||||
const app = require('electron').app;
|
||||
|
||||
function run_update_exe(args, done) {
|
||||
// Invokes Squirrel's Update.exe which will do things for us like create shortcuts
|
||||
// Note that there's an Update.exe in the app-x.x.x directory and one in the parent
|
||||
// directory: we need to run the one in the parent directory, because it discovers
|
||||
// information about the app by inspecting the directory it's run from.
|
||||
const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
|
||||
console.log('Spawning `%s` with args `%s`', updateExe, args);
|
||||
spawn(updateExe, args, {
|
||||
detached: true
|
||||
}).on('close', done);
|
||||
|
||||
@@ -72,11 +72,7 @@ const template = [
|
||||
role: 'togglefullscreen'
|
||||
},
|
||||
{
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: process.platform == 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
||||
click: function(item, focusedWindow) {
|
||||
if (focusedWindow) focusedWindow.toggleDevTools();
|
||||
}
|
||||
role: 'toggledevtools'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
33
package.json
33
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "riot-web",
|
||||
"productName": "Riot",
|
||||
"main": "electron/src/electron-main.js",
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.6",
|
||||
"description": "A feature-rich client for Matrix.org",
|
||||
"author": "Vector Creations Ltd.",
|
||||
"repository": {
|
||||
@@ -27,26 +27,22 @@
|
||||
"matrix-react-parent": "matrix-react-sdk",
|
||||
"scripts": {
|
||||
"reskindex": "reskindex -h src/header",
|
||||
"build:res": "cpx \"{src/skins/vector/fonts,src/skins/vector/img}/**\" webapp/ && cpx \"{res/media,res/vector-icons}/**\" webapp/",
|
||||
"build:config": "cpx config.json webapp/",
|
||||
"build:emojione": "cpx \"node_modules/emojione/assets/svg/*\" webapp/emojione/svg/",
|
||||
"build:res": "node scripts/copy-res.js",
|
||||
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
|
||||
"build:css": "mkdirp build && catw \"src/skins/vector/css/**/*.css\" -o build/components.css --no-watch",
|
||||
"build:compile": "babel --source-maps -d lib src",
|
||||
"build:bundle": "NODE_ENV=production webpack -p --progress",
|
||||
"build:bundle:dev": "webpack --optimize-occurence-order --progress",
|
||||
"build:electron": "npm run clean && npm run build && build -wml --ia32 --x64",
|
||||
"build": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle",
|
||||
"build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle:dev",
|
||||
"build": "node scripts/babelcheck.js && npm run build:res && npm run build:css && npm run build:bundle",
|
||||
"build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:css && npm run build:bundle:dev",
|
||||
"dist": "scripts/package.sh",
|
||||
"start:res": "parallelshell \"cpx -w \\\"{src/skins/vector/fonts,src/skins/vector/img}/**\\\" webapp/\" \"cpx -w \\\"{res/media,res/vector-icons}/**\\\" webapp/\"",
|
||||
"start:config": "cpx -w config.json webapp/",
|
||||
"start:emojione": "cpx \"node_modules/emojione/assets/svg/*\" webapp/emojione/svg/ -w",
|
||||
"start:res": "node scripts/copy-res.js -w",
|
||||
"start:js": "webpack-dev-server -w --progress",
|
||||
"start:js:prod": "NODE_ENV=production webpack-dev-server -w --progress",
|
||||
"start:skins:css": "mkdirp build && catw \"src/skins/vector/css/**/*.css\" -o build/components.css",
|
||||
"start": "node scripts/babelcheck.js && parallelshell \"npm run start:emojione\" \"npm run start:res\" \"npm run start:config\" \"npm run start:js\" \"npm run start:skins:css\"",
|
||||
"start:prod": "parallelshell \"npm run start:emojione\" \"npm run start:js:prod\" \"npm run start:skins:css\"",
|
||||
"start:css": "mkdirp build && catw \"src/skins/vector/css/**/*.css\" -o build/components.css",
|
||||
"start": "node scripts/babelcheck.js && parallelshell \"npm run start:res\" \"npm run start:js\" \"npm run start:css\"",
|
||||
"start:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\" \"npm run start:css\"",
|
||||
"clean": "rimraf build lib webapp electron/dist",
|
||||
"prepublish": "npm run build:compile",
|
||||
"test": "karma start --single-run=true --autoWatch=false --browsers PhantomJS --colors=false",
|
||||
@@ -66,8 +62,8 @@
|
||||
"gfm.css": "^1.1.1",
|
||||
"highlight.js": "^9.0.0",
|
||||
"linkifyjs": "^2.1.3",
|
||||
"matrix-js-sdk": "0.7.1",
|
||||
"matrix-react-sdk": "0.8.1",
|
||||
"matrix-js-sdk": "0.7.4",
|
||||
"matrix-react-sdk": "0.8.5",
|
||||
"modernizr": "^3.1.0",
|
||||
"q": "^1.4.1",
|
||||
"react": "^15.4.0",
|
||||
@@ -95,9 +91,11 @@
|
||||
"babel-preset-react": "^6.16.0",
|
||||
"babel-preset-stage-2": "^6.17.0",
|
||||
"catw": "^1.0.1",
|
||||
"chokidar": "^1.6.1",
|
||||
"cpx": "^1.3.2",
|
||||
"css-raw-loader": "^0.1.1",
|
||||
"electron-builder": "^10.4.1",
|
||||
"electron-builder": "^11.2.4",
|
||||
"electron-builder-squirrel-windows": "^11.2.1",
|
||||
"emojione": "^2.2.3",
|
||||
"expect": "^1.16.0",
|
||||
"fs-extra": "^0.30.0",
|
||||
@@ -111,6 +109,7 @@
|
||||
"karma-phantomjs-launcher": "^1.0.0",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^1.7.0",
|
||||
"minimist": "^1.2.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mocha": "^2.4.5",
|
||||
"parallelshell": "^1.2.0",
|
||||
@@ -123,12 +122,12 @@
|
||||
"webpack-dev-server": "^1.16.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"olm": "https://matrix.org/packages/npm/olm/olm-2.0.0.tgz"
|
||||
"olm": "https://matrix.org/packages/npm/olm/olm-2.1.0.tgz"
|
||||
},
|
||||
"build": {
|
||||
"appId": "im.riot.app",
|
||||
"category": "Network",
|
||||
"electronVersion": "1.4.11",
|
||||
"electronVersion": "1.4.14",
|
||||
"//asar=false": "https://github.com/electron-userland/electron-builder/issues/675",
|
||||
"asar": false,
|
||||
"dereference": true,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 102 KiB |
81
scripts/copy-res.js
Executable file
81
scripts/copy-res.js
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// copies the resources into the webapp directory.
|
||||
//
|
||||
|
||||
// cpx includes globbed parts of the filename in the destination, but excludes
|
||||
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
|
||||
// "dest/b/...".
|
||||
const COPY_LIST = [
|
||||
["res/{media,vector-icons}/**", "webapp"],
|
||||
["src/skins/vector/{fonts,img}/**", "webapp"],
|
||||
["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
|
||||
["./config.json", "webapp", {directwatch: 1}],
|
||||
];
|
||||
|
||||
const parseArgs = require('minimist');
|
||||
const Cpx = require('cpx');
|
||||
const chokidar = require('chokidar');
|
||||
|
||||
const argv = parseArgs(
|
||||
process.argv.slice(2), {}
|
||||
);
|
||||
|
||||
var watch = argv.w;
|
||||
var verbose = argv.v;
|
||||
|
||||
function errCheck(err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function next(i, err) {
|
||||
errCheck(err);
|
||||
|
||||
if (i >= COPY_LIST.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ent = COPY_LIST[i];
|
||||
const source = ent[0];
|
||||
const dest = ent[1];
|
||||
const opts = ent[2] || {};
|
||||
|
||||
const cpx = new Cpx.Cpx(source, dest);
|
||||
|
||||
if (verbose) {
|
||||
cpx.on("copy", (event) => {
|
||||
console.log(`Copied: ${event.srcPath} --> ${event.dstPath}`);
|
||||
});
|
||||
cpx.on("remove", (event) => {
|
||||
console.log(`Removed: ${event.path}`);
|
||||
});
|
||||
}
|
||||
|
||||
const cb = (err) => {next(i+1, err)};
|
||||
|
||||
if (watch) {
|
||||
if (opts.directwatch) {
|
||||
// cpx -w creates a watcher for the parent of any files specified,
|
||||
// which in the case of config.json is '.', which inevitably takes
|
||||
// ages to crawl. So we create our own watcher on the files
|
||||
// instead.
|
||||
const copy = () => {cpx.copy(errCheck)};
|
||||
chokidar.watch(source)
|
||||
.on('add', copy)
|
||||
.on('change', copy)
|
||||
.on('ready', cb)
|
||||
.on('error', errCheck);
|
||||
} else {
|
||||
cpx.on('watch-ready', cb);
|
||||
cpx.on("watch-error", cb);
|
||||
cpx.watch();
|
||||
}
|
||||
} else {
|
||||
cpx.copy(cb);
|
||||
}
|
||||
}
|
||||
|
||||
next(0);
|
||||
@@ -73,12 +73,12 @@ projdir=`pwd`
|
||||
builddir=`mktemp -d 2>/dev/null || mktemp -d -t 'buildtmp'`
|
||||
pushd "$builddir"
|
||||
|
||||
# Figure out what version we're building
|
||||
vername=`jq -r .version package.json`
|
||||
|
||||
git clone "$projdir" .
|
||||
git checkout "$version"
|
||||
|
||||
# Figure out what version we're building
|
||||
vername=`jq -r .version package.json`
|
||||
|
||||
if [ -n "$conffile" ]; then
|
||||
popd
|
||||
cp "$conffile" "$builddir/"
|
||||
@@ -113,7 +113,7 @@ echo "$vername" > "$pubdir/update/macos/latest"
|
||||
|
||||
mkdir -p "$pubdir/update/win32/ia32/"
|
||||
cp $distdir/win-ia32/*.nupkg "$pubdir/update/win32/ia32/"
|
||||
cp $distdir/win-ia32/RELEASES "$pubdir/install/win32/ia32/"
|
||||
cp $distdir/win-ia32/RELEASES "$pubdir/update/win32/ia32/"
|
||||
|
||||
mkdir -p "$pubdir/update/win32/x64/"
|
||||
cp $distdir/win/*.nupkg "$pubdir/update/win32/x64/"
|
||||
|
||||
@@ -19,7 +19,8 @@ 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
|
||||
# we may be using dev branches of js-sdk and react-sdk, in which case we need to build them
|
||||
(cd node_modules/matrix-js-sdk && npm run build)
|
||||
(cd node_modules/matrix-react-sdk && npm run build)
|
||||
|
||||
# run the mocha tests
|
||||
|
||||
@@ -80,7 +80,7 @@ cp "$tmpdir/150.png" "res/vector-icons/mstile-150x150.png"
|
||||
cp "$tmpdir/310.png" "res/vector-icons/mstile-310x310.png"
|
||||
cp "$tmpdir/310x150.png" "res/vector-icons/mstile-310x150.png"
|
||||
|
||||
convert "$tmpdir/16.png" "$tmpdir/32.png" "$tmpdir/64.png" "$tmpdir/128.png" "res/vector-icons/favicon.ico"
|
||||
convert "$tmpdir/16.png" "$tmpdir/32.png" "$tmpdir/64.png" "$tmpdir/128.png" "$tmpdir/256.png" "res/vector-icons/favicon.ico"
|
||||
|
||||
cp "res/vector-icons/favicon.ico" "electron/build/icon.ico"
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ def download_file(url):
|
||||
local_filename = url.split('/')[-1]
|
||||
r = requests.get(url, stream=True)
|
||||
with open(local_filename, 'wb') as f:
|
||||
for chunk in r.iter_content(chunk_size=1024):
|
||||
for chunk in r.iter_content(chunk_size=1024):
|
||||
if chunk: # filter out keep-alive new chunks
|
||||
f.write(chunk)
|
||||
return local_filename
|
||||
@@ -107,21 +107,40 @@ def on_receive_jenkins_poke():
|
||||
)
|
||||
|
||||
print("Retrieving .tar.gz file: %s" % tar_gz_url)
|
||||
|
||||
# we rely on the fact that flask only serves one request at a time to
|
||||
# ensure that we do not overwrite a tarball from a concurrent request.
|
||||
filename = download_file(tar_gz_url)
|
||||
print("Downloaded file: %s" % filename)
|
||||
|
||||
try:
|
||||
# we extract into a directory based on the build number. This avoids the
|
||||
# problem of multiple builds building the same git version and thus having
|
||||
# the same tarball name. That would lead to two potential problems:
|
||||
# (a) sometimes jenkins serves corrupted artifacts; we would replace
|
||||
# a good deploy with a bad one
|
||||
# (b) we'll be overwriting the live deployment, which means people might
|
||||
# see half-written files.
|
||||
build_dir = os.path.join(arg_extract_path, "%s-#%s" % (job_name, build_num))
|
||||
if os.path.exists(build_dir):
|
||||
abort(400, "Not deploying. We have previously deployed this build.")
|
||||
return
|
||||
os.mkdir(build_dir)
|
||||
|
||||
untar_to(filename, build_dir)
|
||||
print("Extracted to: %s" % build_dir)
|
||||
finally:
|
||||
if arg_should_clean:
|
||||
os.remove(filename)
|
||||
|
||||
name_str = filename.replace(".tar.gz", "")
|
||||
untar_to(filename, arg_extract_path)
|
||||
|
||||
extracted_dir = os.path.join(arg_extract_path, name_str)
|
||||
|
||||
if arg_should_clean:
|
||||
os.remove(filename)
|
||||
|
||||
create_symlink(source=extracted_dir, linkname=arg_symlink)
|
||||
extracted_dir = os.path.join(build_dir, name_str)
|
||||
|
||||
if arg_config_location:
|
||||
create_symlink(source=arg_config_location, linkname=os.path.join(extracted_dir, 'config.json'))
|
||||
|
||||
create_symlink(source=extracted_dir, linkname=arg_symlink)
|
||||
|
||||
return jsonify({})
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -45,10 +45,8 @@ module.exports = React.createClass({
|
||||
available or experimental in your current browser.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
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>
|
||||
<p>
|
||||
With your current browser, the look and feel of the application may
|
||||
|
||||
@@ -31,6 +31,8 @@ var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix');
|
||||
var sanitizeHtml = require('sanitize-html');
|
||||
var q = require('q');
|
||||
|
||||
import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils';
|
||||
|
||||
linkifyMatrix(linkify);
|
||||
|
||||
module.exports = React.createClass({
|
||||
@@ -42,9 +44,7 @@ module.exports = React.createClass({
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
config: {
|
||||
networks: [],
|
||||
},
|
||||
config: {},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -52,36 +52,26 @@ module.exports = React.createClass({
|
||||
return {
|
||||
publicRooms: [],
|
||||
loading: true,
|
||||
network: null,
|
||||
protocolsLoading: true,
|
||||
instanceId: null,
|
||||
includeAll: false,
|
||||
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;
|
||||
|
||||
this.setState({protocolsLoading: true});
|
||||
MatrixClientPeg.get().getThirdpartyProtocols().done((response) => {
|
||||
this.protocols = response;
|
||||
this.setState({protocolsLoading: false});
|
||||
}, (err) => {
|
||||
this.setState({protocolsLoading: false});
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
// Guests currently aren't allowed to use this API, so
|
||||
// ignore this as otherwise this error is literally the
|
||||
@@ -131,6 +121,11 @@ module.exports = React.createClass({
|
||||
if (my_server != MatrixClientPeg.getHomeServerName()) {
|
||||
opts.server = my_server;
|
||||
}
|
||||
if (this.state.instanceId) {
|
||||
opts.third_party_instance_id = this.state.instanceId;
|
||||
} else if (this.state.includeAll) {
|
||||
opts.include_all_networks = true;
|
||||
}
|
||||
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) => {
|
||||
@@ -231,7 +226,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
onOptionChange: function(server, network) {
|
||||
onOptionChange: function(server, instanceId, includeAll) {
|
||||
// clear next batch so we don't try to load more rooms
|
||||
this.nextBatch = null;
|
||||
this.setState({
|
||||
@@ -240,7 +235,8 @@ module.exports = React.createClass({
|
||||
// to clear the list anyway.
|
||||
publicRooms: [],
|
||||
roomServer: server,
|
||||
network: network,
|
||||
instanceId: instanceId,
|
||||
includeAll: includeAll,
|
||||
}, this.refreshRoomList);
|
||||
// We also refresh the room list each time even though this
|
||||
// filtering is client-side. It hopefully won't be client side
|
||||
@@ -271,7 +267,7 @@ module.exports = React.createClass({
|
||||
this.filterTimeout = setTimeout(() => {
|
||||
this.filterTimeout = null;
|
||||
this.refreshRoomList();
|
||||
}, 300);
|
||||
}, 700);
|
||||
},
|
||||
|
||||
onFilterClear: function() {
|
||||
@@ -286,14 +282,19 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
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') {
|
||||
// If we don't have a particular instance id selected, just show that rooms alias
|
||||
if (!this.state.instanceId) {
|
||||
// If the user specified an alias without a domain, add on whichever server is selected
|
||||
// in the dropdown
|
||||
if (alias.indexOf(':') == -1) {
|
||||
alias = alias + ':' + this.state.roomServer;
|
||||
}
|
||||
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);
|
||||
// This is a 3rd party protocol. Let's see if we can join it
|
||||
const protocolName = protocolNameForInstanceId(this.protocols, this.state.instanceId);
|
||||
const instance = instanceForInstanceId(this.protocols, this.state.instanceId);
|
||||
const fields = protocolName ? this._getFieldsForThirdPartyLocation(alias, this.protocols[protocolName], instance) : null;
|
||||
if (!fields) {
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
@@ -302,8 +303,7 @@ module.exports = React.createClass({
|
||||
});
|
||||
return;
|
||||
}
|
||||
const protocol = this._protocolForThirdPartyNetwork(this.state.network);
|
||||
MatrixClientPeg.get().getThirdpartyLocation(protocol, fields).done((resp) => {
|
||||
MatrixClientPeg.get().getThirdpartyLocation(protocolName, fields).done((resp) => {
|
||||
if (resp.length > 0 && resp[0].alias) {
|
||||
this.showRoomAlias(resp[0].alias);
|
||||
} else {
|
||||
@@ -372,13 +372,7 @@ module.exports = React.createClass({
|
||||
|
||||
if (!this.state.publicRooms) return [];
|
||||
|
||||
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 rooms = this.state.publicRooms;
|
||||
var rows = [];
|
||||
var self = this;
|
||||
var guestRead, guestJoin, perms;
|
||||
@@ -440,119 +434,46 @@ module.exports = React.createClass({
|
||||
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) {
|
||||
_stringLooksLikeId: function(s, field_type) {
|
||||
let pat = /^#[^\s]+:[^\s]/;
|
||||
if (
|
||||
network && network != '_matrix' &&
|
||||
this.nativePatterns[network]
|
||||
) {
|
||||
pat = this.nativePatterns[network];
|
||||
if (field_type && field_type.regexp) {
|
||||
pat = new RegExp(field_type.regexp);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matched_instance === undefined) return null;
|
||||
|
||||
// now make an object with the fields specified by that protocol. We
|
||||
_getFieldsForThirdPartyLocation: function(userInput, protocol, instance) {
|
||||
// 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 requiredFields = protocol.location_fields;
|
||||
if (!requiredFields) return null;
|
||||
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];
|
||||
for (let i = 0; i < requiredFields.length - 1; ++i) {
|
||||
const thisField = requiredFields[i];
|
||||
if (instance.fields[thisField] === undefined) return null;
|
||||
fields[thisField] = instance.fields[thisField];
|
||||
}
|
||||
fields[required_fields[required_fields.length - 1]] = user_input;
|
||||
fields[requiredFields[requiredFields.length - 1]] = userInput;
|
||||
return fields;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
||||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
|
||||
if (this.state.protocolsLoading) {
|
||||
return (
|
||||
<div className="mx_RoomDirectory">
|
||||
<SimpleRoomHeader title="Directory" />
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let content;
|
||||
if (this.state.loading) {
|
||||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
content = <div className="mx_RoomDirectory">
|
||||
<Loader />
|
||||
</div>;
|
||||
@@ -583,26 +504,35 @@ module.exports = React.createClass({
|
||||
</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)
|
||||
const protocolName = protocolNameForInstanceId(this.protocols, this.state.instanceId);
|
||||
let instance_expected_field_type;
|
||||
if (
|
||||
protocolName &&
|
||||
this.protocols &&
|
||||
this.protocols[protocolName] &&
|
||||
this.protocols[protocolName].location_fields.length > 0 &&
|
||||
this.protocols[protocolName].field_types
|
||||
) {
|
||||
placeholder = this.props.config.networks[this.state.network].example;
|
||||
const last_field = this.protocols[protocolName].location_fields.slice(-1)[0];
|
||||
instance_expected_field_type = this.protocols[protocolName].field_types[last_field];
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
let placeholder = 'Search for a room';
|
||||
if (!this.state.instanceId) {
|
||||
placeholder = '#example:' + this.state.roomServer;
|
||||
} else if (instance_expected_field_type) {
|
||||
placeholder = instance_expected_field_type.placeholder;
|
||||
}
|
||||
|
||||
let showJoinButton = this._stringLooksLikeId(this.state.filterString, instance_expected_field_type);
|
||||
if (protocolName) {
|
||||
const instance = instanceForInstanceId(this.protocols, this.state.instanceId);
|
||||
if (this._getFieldsForThirdPartyLocation(this.state.filterString, this.protocols[protocolName], instance) === null) {
|
||||
showJoinButton = false;
|
||||
}
|
||||
}
|
||||
|
||||
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
||||
const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown');
|
||||
const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
|
||||
return (
|
||||
@@ -615,7 +545,7 @@ module.exports = React.createClass({
|
||||
onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
|
||||
placeholder={placeholder} showJoinButton={showJoinButton}
|
||||
/>
|
||||
<NetworkDropdown config={this.props.config} onOptionChange={this.onOptionChange} />
|
||||
<NetworkDropdown config={this.props.config} protocols={this.protocols} onOptionChange={this.onOptionChange} />
|
||||
</div>
|
||||
{content}
|
||||
</div>
|
||||
|
||||
@@ -16,6 +16,9 @@ limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
||||
import {instanceForInstanceId} from '../../../utils/DirectoryUtils';
|
||||
|
||||
const DEFAULT_ICON_URL = "img/network-matrix.svg";
|
||||
|
||||
export default class NetworkDropdown extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -35,20 +38,11 @@ export default class NetworkDropdown extends React.Component {
|
||||
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,
|
||||
selectedInstance: null,
|
||||
includeAllNetworks: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -58,7 +52,7 @@ export default class NetworkDropdown extends React.Component {
|
||||
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);
|
||||
this.props.onOptionChange(this.state.selectedServer, this.state.selectedInstance, this.state.includeAllNetworks);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@@ -98,13 +92,14 @@ export default class NetworkDropdown extends React.Component {
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
onMenuOptionClick(server, network, ev) {
|
||||
onMenuOptionClick(server, instance, includeAll) {
|
||||
this.setState({
|
||||
expanded: false,
|
||||
selectedServer: server,
|
||||
selectedNetwork: network,
|
||||
selectedInstanceId: instance ? instance.instance_id : null,
|
||||
includeAll: includeAll,
|
||||
});
|
||||
this.props.onOptionChange(server, network);
|
||||
this.props.onOptionChange(server, instance ? instance.instance_id : null, includeAll);
|
||||
}
|
||||
|
||||
onInputKeyUp(e) {
|
||||
@@ -144,11 +139,22 @@ export default class NetworkDropdown extends React.Component {
|
||||
servers.unshift(MatrixClientPeg.getHomeServerName());
|
||||
}
|
||||
|
||||
// For our own HS, we can use the instance_ids given in the third party protocols
|
||||
// response to get the server to filter the room list by network for us.
|
||||
// We can't get thirdparty protocols for remote server yet though, so for those
|
||||
// we can only show the default room list.
|
||||
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));
|
||||
options.push(this._makeMenuOption(server, null, true));
|
||||
if (server == MatrixClientPeg.getHomeServerName()) {
|
||||
options.push(this._makeMenuOption(server, null, false));
|
||||
if (this.props.protocols) {
|
||||
for (const proto of Object.keys(this.props.protocols)) {
|
||||
if (!this.props.protocols[proto].instances) continue;
|
||||
for (const instance of this.props.protocols[proto].instances) {
|
||||
if (!instance.instance_id) continue;
|
||||
options.push(this._makeMenuOption(server, instance, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,50 +162,36 @@ export default class NetworkDropdown extends React.Component {
|
||||
return options;
|
||||
}
|
||||
|
||||
_makeMenuOption(server, network, wire_onclick) {
|
||||
if (wire_onclick === undefined) wire_onclick = true;
|
||||
_makeMenuOption(server, instance, includeAll, handleClicks) {
|
||||
if (handleClicks === undefined) handleClicks = true;
|
||||
|
||||
let icon;
|
||||
let name;
|
||||
let span_class;
|
||||
let key;
|
||||
|
||||
if (network === null) {
|
||||
if (!instance && includeAll) {
|
||||
key = server;
|
||||
name = server;
|
||||
span_class = 'mx_NetworkDropdown_menu_all';
|
||||
} else if (network == '_matrix') {
|
||||
} else if (!instance) {
|
||||
key = server + '_all';
|
||||
name = 'Matrix';
|
||||
icon = <img src="img/network-matrix.svg" width="16" height="16" />;
|
||||
icon = <img src="img/network-matrix.svg" />;
|
||||
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" />;
|
||||
}
|
||||
|
||||
key = server + '_inst_' + instance.instance_id;
|
||||
icon = <img src={instance.icon || DEFAULT_ICON_URL} />;
|
||||
name = instance.desc;
|
||||
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;
|
||||
}
|
||||
const click_handler = handleClicks ? this.onMenuOptionClick.bind(this, server, instance, includeAll) : null;
|
||||
|
||||
return <div key={key} className="mx_NetworkDropdown_networkoption" onClick={click_handler}>
|
||||
{icon}
|
||||
<span className={span_class}>{name}</span>
|
||||
</div>;
|
||||
<span className="mx_NetworkDropdown_menu_network">{name}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -216,8 +208,9 @@ export default class NetworkDropdown extends React.Component {
|
||||
placeholder="matrix.org" // 'matrix.org' as an example of an HS name
|
||||
/>
|
||||
} else {
|
||||
const instance = instanceForInstanceId(this.props.protocols, this.state.selectedInstanceId);
|
||||
current_value = this._makeMenuOption(
|
||||
this.state.selectedServer, this.state.selectedNetwork, false
|
||||
this.state.selectedServer, instance, this.state.includeAll, false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -233,12 +226,12 @@ export default class NetworkDropdown extends React.Component {
|
||||
|
||||
NetworkDropdown.propTypes = {
|
||||
onOptionChange: React.PropTypes.func.isRequired,
|
||||
protocols: React.PropTypes.object,
|
||||
// The room directory config. May have a 'servers' key that is a list of server names to include in the dropdown
|
||||
config: React.PropTypes.object,
|
||||
};
|
||||
|
||||
NetworkDropdown.defaultProps = {
|
||||
config: {
|
||||
networks: [],
|
||||
}
|
||||
protocols: {},
|
||||
config: {},
|
||||
};
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ limitations under the License.
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.mx_UserSettings_addThreepid {
|
||||
.mx_UserSettings_threepidButton {
|
||||
display: table-cell;
|
||||
padding-left: 0.5em;
|
||||
position: relative;
|
||||
|
||||
23
src/utils/DirectoryUtils.js
Normal file
23
src/utils/DirectoryUtils.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// Find a protocol 'instance' with a given instance_id
|
||||
// in the supplied protocols dict
|
||||
export function instanceForInstanceId(protocols, instance_id) {
|
||||
if (!instance_id) return null;
|
||||
for (const proto of Object.keys(protocols)) {
|
||||
if (!protocols[proto].instances && protocols[proto].instances instanceof Array) continue;
|
||||
for (const instance of protocols[proto].instances) {
|
||||
if (instance.instance_id == instance_id) return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// given an instance_id, return the name of the protocol for
|
||||
// that instance ID in the supplied protocols dict
|
||||
export function protocolNameForInstanceId(protocols, instance_id) {
|
||||
if (!instance_id) return null;
|
||||
for (const proto of Object.keys(protocols)) {
|
||||
if (!protocols[proto].instances && protocols[proto].instances instanceof Array) continue;
|
||||
for (const instance of protocols[proto].instances) {
|
||||
if (instance.instance_id == instance_id) return proto;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,11 +136,20 @@ var onNewScreen = function(screen) {
|
||||
// click back to the client having registered.
|
||||
// It's up to us to recognise if we're loaded with
|
||||
// this URL and tell MatrixClient to resume registration.
|
||||
//
|
||||
// If we're in electron, we should never pass through a file:// URL otherwise
|
||||
// the identity server will try to 302 the browser to it, which breaks horribly.
|
||||
// so in that instance, hardcode to use riot.im/app for now instead.
|
||||
var makeRegistrationUrl = function() {
|
||||
return window.location.protocol + '//' +
|
||||
window.location.host +
|
||||
window.location.pathname +
|
||||
'#/register';
|
||||
if (window.location.protocol === "file:") {
|
||||
return 'https://riot.im/app/#/register';
|
||||
}
|
||||
else {
|
||||
return window.location.protocol + '//' +
|
||||
window.location.host +
|
||||
window.location.pathname +
|
||||
'#/register';
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', onHashChange);
|
||||
|
||||
41
src/vector/olm-loader.js
Normal file
41
src/vector/olm-loader.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/* a very thin shim for loading olm.js: just sets the global OLM_OPTIONS and
|
||||
* requires the actual olm.js library.
|
||||
*
|
||||
* olm.js reads global.OLM_OPTIONS and defines global.Olm. The latter is fine for us,
|
||||
* but we need to prepare the former.
|
||||
*
|
||||
* We can't use webpack's definePlugin to do this, because we tell webpack not
|
||||
* to parse olm.js. We also can't put this code in index.js, because olm and
|
||||
* index.js are loaded in parallel, and we need to make sure OLM_OPTIONS is set
|
||||
* before olm.js is loaded.
|
||||
*/
|
||||
|
||||
/* total_memory must be a power of two, and at least twice the stack.
|
||||
*
|
||||
* We don't need a lot of stack, but we do need about 128K of heap to encrypt a
|
||||
* 64K event (enough to store the ciphertext and the plaintext, bearing in mind
|
||||
* that the plaintext can only be 48K because base64). We also have about 36K
|
||||
* of statics. So let's have 256K of memory.
|
||||
*/
|
||||
global.OLM_OPTIONS = {
|
||||
TOTAL_STACK: 64*1024,
|
||||
TOTAL_MEMORY: 256*1024,
|
||||
};
|
||||
|
||||
require('olm/olm.js');
|
||||
@@ -127,4 +127,8 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
getDefaultDeviceDisplayName() {
|
||||
return "Riot Desktop on " + platformFriendlyName();
|
||||
}
|
||||
|
||||
screenCaptureErrorString() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,4 +196,12 @@ export default class WebPlatform extends VectorBasePlatform {
|
||||
return app_name + " via " + ua.getBrowser().name +
|
||||
" on " + ua.getOS().name;
|
||||
}
|
||||
|
||||
screenCaptureErrorString() {
|
||||
// it won't work at all if you're not on HTTPS so whine whine whine
|
||||
if (!global.window || global.window.location.protocol !== "https:") {
|
||||
return "You need to be using HTTPS to place a screen-sharing call.";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ describe('joining a room', function () {
|
||||
httpBackend.when('POST', '/filter').respond(200, { filter_id: 'fid' });
|
||||
httpBackend.when('GET', '/sync').respond(200, {});
|
||||
httpBackend.when('POST', '/publicRooms').respond(200, {chunk: []});
|
||||
httpBackend.when('GET', '/thirdparty/protocols').respond(200, {});
|
||||
httpBackend.when('GET', '/directory/room/'+encodeURIComponent(ROOM_ALIAS)).respond(200, { room_id: ROOM_ID });
|
||||
|
||||
// start with a logged-in client
|
||||
@@ -132,6 +133,12 @@ describe('joining a room', function () {
|
||||
httpBackend.when('POST', '/join/'+encodeURIComponent(ROOM_ALIAS))
|
||||
.respond(200, {room_id: ROOM_ID});
|
||||
return httpBackend.flush();
|
||||
}).then(() => {
|
||||
// wait for the join request to be made
|
||||
return q.delay(1);
|
||||
}).then(() => {
|
||||
// flush it through
|
||||
return httpBackend.flush();
|
||||
}).then(() => {
|
||||
httpBackend.verifyNoOutstandingExpectation();
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ module.exports = {
|
||||
// (we should probably make js-sdk load it asynchronously at some
|
||||
// point, so that it doesn't block the pageload, but that is a separate
|
||||
// problem)
|
||||
"olm": "olm/olm.js",
|
||||
"olm": "./src/vector/olm-loader.js",
|
||||
},
|
||||
module: {
|
||||
preLoaders: [
|
||||
|
||||
Reference in New Issue
Block a user