Merge package.json, match version in electron/package.json
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
commit
a09f890619
53 changed files with 1046 additions and 484 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -13,3 +13,4 @@
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
electron/dist
|
electron/dist
|
||||||
electron/pub
|
electron/pub
|
||||||
|
/config.json
|
||||||
|
|
119
CHANGELOG.md
119
CHANGELOG.md
|
@ -1,3 +1,122 @@
|
||||||
|
Changes in [0.9.8](https://github.com/vector-im/riot-web/releases/tag/v0.9.8) (2017-04-12)
|
||||||
|
==========================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8-rc.3...v0.9.8)
|
||||||
|
|
||||||
|
* No changes
|
||||||
|
|
||||||
|
Changes in [0.9.8-rc.3](https://github.com/vector-im/riot-web/releases/tag/v0.9.8-rc.3) (2017-04-11)
|
||||||
|
====================================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8-rc.2...v0.9.8-rc.3)
|
||||||
|
|
||||||
|
* Make the clear cache button work on desktop
|
||||||
|
[\#3598](https://github.com/vector-im/riot-web/pull/3598)
|
||||||
|
|
||||||
|
Changes in [0.9.8-rc.2](https://github.com/vector-im/riot-web/releases/tag/v0.9.8-rc.2) (2017-04-10)
|
||||||
|
====================================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8-rc.1...v0.9.8-rc.2)
|
||||||
|
|
||||||
|
* Redacted events bg: black lozenge -> torn paper
|
||||||
|
[\#3596](https://github.com/vector-im/riot-web/pull/3596)
|
||||||
|
* Add 'app' parameter to rageshake report
|
||||||
|
[\#3594](https://github.com/vector-im/riot-web/pull/3594)
|
||||||
|
|
||||||
|
Changes in [0.9.8-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.8-rc.1) (2017-04-07)
|
||||||
|
====================================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.7...v0.9.8-rc.1)
|
||||||
|
|
||||||
|
* Add support for indexeddb sync in webworker
|
||||||
|
[\#3578](https://github.com/vector-im/riot-web/pull/3578)
|
||||||
|
* Add CSS to make Emote sender cursor : pointer
|
||||||
|
[\#3574](https://github.com/vector-im/riot-web/pull/3574)
|
||||||
|
* Remove rageshake server
|
||||||
|
[\#3565](https://github.com/vector-im/riot-web/pull/3565)
|
||||||
|
* Adjust CSS for matrix-org/matrix-react-sdk#789
|
||||||
|
[\#3566](https://github.com/vector-im/riot-web/pull/3566)
|
||||||
|
* Fix tests to reflect recent changes
|
||||||
|
[\#3537](https://github.com/vector-im/riot-web/pull/3537)
|
||||||
|
* Do not assume getTs will return comparable integer
|
||||||
|
[\#3536](https://github.com/vector-im/riot-web/pull/3536)
|
||||||
|
* Rename ReactPerf to Perf
|
||||||
|
[\#3535](https://github.com/vector-im/riot-web/pull/3535)
|
||||||
|
* Don't show phone number as target for email notifs
|
||||||
|
[\#3530](https://github.com/vector-im/riot-web/pull/3530)
|
||||||
|
* Fix people section again
|
||||||
|
[\#3458](https://github.com/vector-im/riot-web/pull/3458)
|
||||||
|
* dark theme invert inconsistent across browsers
|
||||||
|
[\#3479](https://github.com/vector-im/riot-web/pull/3479)
|
||||||
|
* CSS for adding phone number in UserSettings
|
||||||
|
[\#3451](https://github.com/vector-im/riot-web/pull/3451)
|
||||||
|
* Support for phone number registration/signin, mk2
|
||||||
|
[\#3426](https://github.com/vector-im/riot-web/pull/3426)
|
||||||
|
* Confirm redactions with a dialog
|
||||||
|
[\#3470](https://github.com/vector-im/riot-web/pull/3470)
|
||||||
|
* Better CSS for redactions
|
||||||
|
[\#3453](https://github.com/vector-im/riot-web/pull/3453)
|
||||||
|
* Fix the people section
|
||||||
|
[\#3448](https://github.com/vector-im/riot-web/pull/3448)
|
||||||
|
* Merge the two RoomTile context menus into one
|
||||||
|
[\#3395](https://github.com/vector-im/riot-web/pull/3395)
|
||||||
|
* Refactor screen set after login
|
||||||
|
[\#3385](https://github.com/vector-im/riot-web/pull/3385)
|
||||||
|
* CSS for redacted EventTiles
|
||||||
|
[\#3379](https://github.com/vector-im/riot-web/pull/3379)
|
||||||
|
* Height:100% for welcome pages on Safari
|
||||||
|
[\#3340](https://github.com/vector-im/riot-web/pull/3340)
|
||||||
|
* `view_room` dispatch from `onClick` RoomTile
|
||||||
|
[\#3376](https://github.com/vector-im/riot-web/pull/3376)
|
||||||
|
* Hide statusAreaBox_line entirely when inCall
|
||||||
|
[\#3350](https://github.com/vector-im/riot-web/pull/3350)
|
||||||
|
* Set padding-bottom: 0px for .mx_Dialog spinner
|
||||||
|
[\#3351](https://github.com/vector-im/riot-web/pull/3351)
|
||||||
|
* Support InteractiveAuth based registration
|
||||||
|
[\#3333](https://github.com/vector-im/riot-web/pull/3333)
|
||||||
|
* Expose notification option for username/MXID
|
||||||
|
[\#3334](https://github.com/vector-im/riot-web/pull/3334)
|
||||||
|
* Float the toggle in the top right of MELS
|
||||||
|
[\#3190](https://github.com/vector-im/riot-web/pull/3190)
|
||||||
|
* More aggressive rageshake log culling
|
||||||
|
[\#3311](https://github.com/vector-im/riot-web/pull/3311)
|
||||||
|
* Don't overflow directory network options
|
||||||
|
[\#3282](https://github.com/vector-im/riot-web/pull/3282)
|
||||||
|
* CSS for ban / kick reason prompt
|
||||||
|
[\#3250](https://github.com/vector-im/riot-web/pull/3250)
|
||||||
|
* Allow forgetting rooms you're banned from
|
||||||
|
[\#3246](https://github.com/vector-im/riot-web/pull/3246)
|
||||||
|
* Fix icon paths in manifest
|
||||||
|
[\#3245](https://github.com/vector-im/riot-web/pull/3245)
|
||||||
|
* Fix broken tests caused by adding IndexedDB support
|
||||||
|
[\#3242](https://github.com/vector-im/riot-web/pull/3242)
|
||||||
|
* CSS for un-ban button in RoomSettings
|
||||||
|
[\#3227](https://github.com/vector-im/riot-web/pull/3227)
|
||||||
|
* Remove z-index property on avatar initials
|
||||||
|
[\#3239](https://github.com/vector-im/riot-web/pull/3239)
|
||||||
|
* Reposition certain icons in the status bar
|
||||||
|
[\#3233](https://github.com/vector-im/riot-web/pull/3233)
|
||||||
|
* CSS for kick/ban confirmation dialog
|
||||||
|
[\#3224](https://github.com/vector-im/riot-web/pull/3224)
|
||||||
|
* Style for split-out interactive auth
|
||||||
|
[\#3217](https://github.com/vector-im/riot-web/pull/3217)
|
||||||
|
* Use the teamToken threaded through from react sdk
|
||||||
|
[\#3196](https://github.com/vector-im/riot-web/pull/3196)
|
||||||
|
* rageshake: Add file server with basic auth
|
||||||
|
[\#3169](https://github.com/vector-im/riot-web/pull/3169)
|
||||||
|
* Fix bug with home icon not appearing when logged in as team member
|
||||||
|
[\#3162](https://github.com/vector-im/riot-web/pull/3162)
|
||||||
|
* Add ISSUE_TEMPLATE
|
||||||
|
[\#2836](https://github.com/vector-im/riot-web/pull/2836)
|
||||||
|
* Store bug reports in separate directories
|
||||||
|
[\#3150](https://github.com/vector-im/riot-web/pull/3150)
|
||||||
|
* Quick and dirty support for custom welcome pages.
|
||||||
|
[\#2575](https://github.com/vector-im/riot-web/pull/2575)
|
||||||
|
* RTS Welcome Pages
|
||||||
|
[\#3103](https://github.com/vector-im/riot-web/pull/3103)
|
||||||
|
* rageshake: Abide by Go standards
|
||||||
|
[\#3149](https://github.com/vector-im/riot-web/pull/3149)
|
||||||
|
* Bug report server script
|
||||||
|
[\#3072](https://github.com/vector-im/riot-web/pull/3072)
|
||||||
|
* Bump olm version
|
||||||
|
[\#3125](https://github.com/vector-im/riot-web/pull/3125)
|
||||||
|
|
||||||
Changes in [0.9.7](https://github.com/vector-im/riot-web/releases/tag/v0.9.7) (2017-02-04)
|
Changes in [0.9.7](https://github.com/vector-im/riot-web/releases/tag/v0.9.7) (2017-02-04)
|
||||||
==========================================================================================
|
==========================================================================================
|
||||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.7-rc.3...v0.9.7)
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.7-rc.3...v0.9.7)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "riot-web",
|
"name": "riot-web",
|
||||||
"main": "src/electron-main.js",
|
"main": "src/electron-main.js",
|
||||||
"version": "0.0.0",
|
"version": "0.9.8",
|
||||||
"description": "A feature-rich client for Matrix.org",
|
"description": "A feature-rich client for Matrix.org",
|
||||||
"author": "Vector Creations Ltd.",
|
"author": "Vector Creations Ltd.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -173,6 +173,7 @@ const shouldQuit = electron.app.makeSingleInstance((commandLine, workingDirector
|
||||||
});
|
});
|
||||||
|
|
||||||
if (shouldQuit) {
|
if (shouldQuit) {
|
||||||
|
console.log("Other instance detected: exiting");
|
||||||
electron.app.quit()
|
electron.app.quit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,9 +214,12 @@ electron.app.on('ready', () => {
|
||||||
brand: vectorConfig.brand || 'Riot'
|
brand: vectorConfig.brand || 'Riot'
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.once('ready-to-show', () => {
|
if (!process.argv.includes('--hidden')) {
|
||||||
mainWindow.show();
|
mainWindow.once('ready-to-show', () => {
|
||||||
});
|
mainWindow.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mainWindow.on('closed', () => {
|
mainWindow.on('closed', () => {
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
});
|
});
|
||||||
|
|
21
package.json
21
package.json
|
@ -2,7 +2,7 @@
|
||||||
"name": "riot-web",
|
"name": "riot-web",
|
||||||
"productName": "Riot",
|
"productName": "Riot",
|
||||||
"main": "electron/src/electron-main.js",
|
"main": "electron/src/electron-main.js",
|
||||||
"version": "0.9.7",
|
"version": "0.9.8",
|
||||||
"description": "A feature-rich client for Matrix.org",
|
"description": "A feature-rich client for Matrix.org",
|
||||||
"author": "Vector Creations Ltd.",
|
"author": "Vector Creations Ltd.",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -30,18 +30,18 @@
|
||||||
"build:res": "node scripts/copy-res.js",
|
"build:res": "node scripts/copy-res.js",
|
||||||
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
|
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
|
||||||
"build:compile": "babel --source-maps -d lib src",
|
"build:compile": "babel --source-maps -d lib src",
|
||||||
"build:bundle": "NODE_ENV=production webpack -p --progress",
|
"build:bundle": "cross-env NODE_ENV=production webpack -p --progress",
|
||||||
"build:bundle:dev": "webpack --optimize-occurence-order --progress",
|
"build:bundle:dev": "webpack --optimize-occurence-order --progress",
|
||||||
"build:electron": "npm run clean && npm run build && npm run install:electron && build -wml --ia32 --x64",
|
"build:electron": "npm run clean && npm run build && npm run install:electron && build -wml --ia32 --x64",
|
||||||
"build": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle",
|
"build": "npm run build:res && npm run build:bundle",
|
||||||
"build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle:dev",
|
"build:dev": "npm run build:res && npm run build:bundle:dev",
|
||||||
"dist": "scripts/package.sh",
|
"dist": "scripts/package.sh",
|
||||||
"install:electron": "install-app-deps",
|
"install:electron": "install-app-deps",
|
||||||
"electron": "npm run install:electron && electron .",
|
"electron": "npm run install:electron && electron .",
|
||||||
"start:res": "node scripts/copy-res.js -w",
|
"start:res": "node scripts/copy-res.js -w",
|
||||||
"start:js": "webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress",
|
"start:js": "webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress",
|
||||||
"start:js:prod": "NODE_ENV=production webpack-dev-server -w --progress",
|
"start:js:prod": "cross-env NODE_ENV=production webpack-dev-server -w --progress",
|
||||||
"start": "node scripts/babelcheck.js && parallelshell \"npm run start:res\" \"npm run start:js\"",
|
"start": "parallelshell \"npm run start:res\" \"npm run start:js\"",
|
||||||
"start:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\"",
|
"start:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\"",
|
||||||
"lint": "eslint src/",
|
"lint": "eslint src/",
|
||||||
"lintall": "eslint src/ test/",
|
"lintall": "eslint src/ test/",
|
||||||
|
@ -58,21 +58,21 @@
|
||||||
"draft-js": "^0.8.1",
|
"draft-js": "^0.8.1",
|
||||||
"extract-text-webpack-plugin": "^0.9.1",
|
"extract-text-webpack-plugin": "^0.9.1",
|
||||||
"favico.js": "^0.3.10",
|
"favico.js": "^0.3.10",
|
||||||
"filesize": "^3.1.2",
|
"filesize": "3.5.6",
|
||||||
"flux": "~2.0.3",
|
"flux": "~2.0.3",
|
||||||
"gemini-scrollbar": "matrix-org/gemini-scrollbar#b302279",
|
|
||||||
"gfm.css": "^1.1.1",
|
"gfm.css": "^1.1.1",
|
||||||
"highlight.js": "^9.0.0",
|
"highlight.js": "^9.0.0",
|
||||||
"linkifyjs": "^2.1.3",
|
"linkifyjs": "^2.1.3",
|
||||||
"matrix-js-sdk": "matrix-org/matrix-js-sdk#develop",
|
"matrix-js-sdk": "matrix-org/matrix-js-sdk#develop",
|
||||||
"matrix-react-sdk": "matrix-org/matrix-react-sdk#develop",
|
"matrix-react-sdk": "matrix-org/matrix-react-sdk#develop",
|
||||||
"modernizr": "^3.1.0",
|
"modernizr": "^3.1.0",
|
||||||
|
"pako": "^1.0.5",
|
||||||
"q": "^1.4.1",
|
"q": "^1.4.1",
|
||||||
"react": "^15.4.0",
|
"react": "^15.4.0",
|
||||||
"react-dnd": "^2.1.4",
|
"react-dnd": "^2.1.4",
|
||||||
"react-dnd-html5-backend": "^2.1.2",
|
"react-dnd-html5-backend": "^2.1.2",
|
||||||
"react-dom": "^15.4.0",
|
"react-dom": "^15.4.0",
|
||||||
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
|
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#39d858c",
|
||||||
"sanitize-html": "^1.11.1",
|
"sanitize-html": "^1.11.1",
|
||||||
"ua-parser-js": "^0.7.10",
|
"ua-parser-js": "^0.7.10",
|
||||||
"url": "^0.11.0"
|
"url": "^0.11.0"
|
||||||
|
@ -95,6 +95,7 @@
|
||||||
"babel-preset-stage-2": "^6.17.0",
|
"babel-preset-stage-2": "^6.17.0",
|
||||||
"chokidar": "^1.6.1",
|
"chokidar": "^1.6.1",
|
||||||
"cpx": "^1.3.2",
|
"cpx": "^1.3.2",
|
||||||
|
"cross-env": "^4.0.0",
|
||||||
"css-raw-loader": "^0.1.1",
|
"css-raw-loader": "^0.1.1",
|
||||||
"electron-builder": "^11.2.4",
|
"electron-builder": "^11.2.4",
|
||||||
"electron-builder-squirrel-windows": "^11.2.1",
|
"electron-builder-squirrel-windows": "^11.2.1",
|
||||||
|
@ -140,7 +141,7 @@
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "im.riot.app",
|
"appId": "im.riot.app",
|
||||||
"category": "Network",
|
"category": "Network",
|
||||||
"electronVersion": "1.4.14",
|
"electronVersion": "1.6.2",
|
||||||
"//asar=false": "https://github.com/electron-userland/electron-builder/issues/675",
|
"//asar=false": "https://github.com/electron-userland/electron-builder/issues/675",
|
||||||
"asar": false,
|
"asar": false,
|
||||||
"dereference": true,
|
"dereference": true,
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
var exec = require('child_process').exec;
|
|
||||||
|
|
||||||
// Makes sure the babel executable in the path is babel 6 (or greater), not
|
|
||||||
// babel 5, which it is if you upgrade from an older version of react-sdk and
|
|
||||||
// run 'npm install' since the package has changed to babel-cli, so 'babel'
|
|
||||||
// remains installed and the executable in node_modules/.bin remains as babel
|
|
||||||
// 5.
|
|
||||||
|
|
||||||
// This script is duplicated from matrix-react-sdk because it can't reliably
|
|
||||||
// be pulled in from react-sdk while npm install is failing, as it will do
|
|
||||||
// if the environment is in the erroneous state this script checks for.
|
|
||||||
|
|
||||||
exec("babel -V", function (error, stdout, stderr) {
|
|
||||||
if ((error && error.code) || parseInt(stdout.substr(0,1), 10) < 6) {
|
|
||||||
console.log("\033[31m\033[1m"+
|
|
||||||
'*****************************************\n'+
|
|
||||||
'* vector-web has moved to babel 6 *\n'+
|
|
||||||
'* Please "rm -rf node_modules && npm i" *\n'+
|
|
||||||
'* then restore links as appropriate *\n'+
|
|
||||||
'*****************************************\n'+
|
|
||||||
"\033[91m");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -10,6 +10,7 @@ const COPY_LIST = [
|
||||||
["res/{media,vector-icons}/**", "webapp"],
|
["res/{media,vector-icons}/**", "webapp"],
|
||||||
["src/skins/vector/{fonts,img}/**", "webapp"],
|
["src/skins/vector/{fonts,img}/**", "webapp"],
|
||||||
["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
|
["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
|
||||||
|
["node_modules/emojione/assets/png/*", "webapp/emojione/png/"],
|
||||||
["./config.json", "webapp", {directwatch: 1}],
|
["./config.json", "webapp", {directwatch: 1}],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,146 +0,0 @@
|
||||||
// Run a web server capable of dumping bug reports sent by Riot.
|
|
||||||
// Requires Go 1.5+
|
|
||||||
// Usage: BUGS_USER=user BUGS_PASS=password go run rageshake.go PORT
|
|
||||||
// Example: BUGS_USER=alice BUGS_PASS=secret go run rageshake.go 8080
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"crypto/subtle"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var maxPayloadSize = 1024 * 1024 * 55 // 55 MB
|
|
||||||
|
|
||||||
type LogEntry struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Lines string `json:"lines"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Payload struct {
|
|
||||||
Text string `json:"text"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
UserAgent string `json:"user_agent"`
|
|
||||||
Logs []LogEntry `json:"logs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func respond(code int, w http.ResponseWriter) {
|
|
||||||
w.WriteHeader(code)
|
|
||||||
w.Write([]byte("{}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func gzipAndSave(data []byte, dirname, fpath string) error {
|
|
||||||
_ = os.MkdirAll(filepath.Join("bugs", dirname), os.ModePerm)
|
|
||||||
fpath = filepath.Join("bugs", dirname, fpath)
|
|
||||||
|
|
||||||
if _, err := os.Stat(fpath); err == nil {
|
|
||||||
return fmt.Errorf("file already exists") // the user can just retry
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
gz := gzip.NewWriter(&b)
|
|
||||||
if _, err := gz.Write(data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := gz.Flush(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := gz.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := ioutil.WriteFile(fpath, b.Bytes(), 0644); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func basicAuth(handler http.Handler, username, password, realm string) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
user, pass, ok := r.BasicAuth() // pull creds from the request
|
|
||||||
|
|
||||||
// check user and pass securely
|
|
||||||
if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
|
|
||||||
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
|
|
||||||
w.WriteHeader(401)
|
|
||||||
w.Write([]byte("Unauthorised.\n"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/api/submit", func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
if req.Method != "POST" && req.Method != "OPTIONS" {
|
|
||||||
respond(405, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Set CORS
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
||||||
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
|
|
||||||
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
|
|
||||||
if req.Method == "OPTIONS" {
|
|
||||||
respond(200, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if length, err := strconv.Atoi(req.Header.Get("Content-Length")); err != nil || length > maxPayloadSize {
|
|
||||||
respond(413, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var p Payload
|
|
||||||
if err := json.NewDecoder(req.Body).Decode(&p); err != nil {
|
|
||||||
respond(400, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Dump bug report to disk as form:
|
|
||||||
// "bugreport-20170115-112233.log.gz" => user text, version, user agent, # logs
|
|
||||||
// "bugreport-20170115-112233-0.log.gz" => most recent log
|
|
||||||
// "bugreport-20170115-112233-1.log.gz" => ...
|
|
||||||
// "bugreport-20170115-112233-N.log.gz" => oldest log
|
|
||||||
t := time.Now().UTC()
|
|
||||||
prefix := t.Format("2006-01-02/150405")
|
|
||||||
summary := fmt.Sprintf(
|
|
||||||
"%s\n\nNumber of logs: %d\nVersion: %s\nUser-Agent: %s\n", p.Text, len(p.Logs), p.Version, p.UserAgent,
|
|
||||||
)
|
|
||||||
if err := gzipAndSave([]byte(summary), prefix, "details.log.gz"); err != nil {
|
|
||||||
respond(500, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i, log := range p.Logs {
|
|
||||||
if err := gzipAndSave([]byte(log.Lines), prefix, fmt.Sprintf("logs-%d.log.gz", i)); err != nil {
|
|
||||||
respond(500, w)
|
|
||||||
return // TODO: Rollback?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
respond(200, w)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Make sure bugs directory exists
|
|
||||||
_ = os.Mkdir("bugs", os.ModePerm)
|
|
||||||
|
|
||||||
// serve files under "bugs"
|
|
||||||
fs := http.FileServer(http.Dir("bugs"))
|
|
||||||
fs = http.StripPrefix("/api/listing/", fs)
|
|
||||||
|
|
||||||
// set auth if env vars exist
|
|
||||||
usr := os.Getenv("BUGS_USER")
|
|
||||||
pass := os.Getenv("BUGS_PASS")
|
|
||||||
if usr == "" || pass == "" {
|
|
||||||
fmt.Println("BUGS_USER and BUGS_PASS env vars not found. No authentication is running for /api/listing")
|
|
||||||
} else {
|
|
||||||
fs = basicAuth(fs, usr, pass, "Riot bug reports")
|
|
||||||
}
|
|
||||||
http.Handle("/api/listing/", fs)
|
|
||||||
|
|
||||||
port := os.Args[1]
|
|
||||||
log.Fatal(http.ListenAndServe(":"+port, nil))
|
|
||||||
}
|
|
|
@ -40,6 +40,8 @@ import structures$RoomDirectory from './components/structures/RoomDirectory';
|
||||||
structures$RoomDirectory && (module.exports.components['structures.RoomDirectory'] = structures$RoomDirectory);
|
structures$RoomDirectory && (module.exports.components['structures.RoomDirectory'] = structures$RoomDirectory);
|
||||||
import structures$RoomSubList from './components/structures/RoomSubList';
|
import structures$RoomSubList from './components/structures/RoomSubList';
|
||||||
structures$RoomSubList && (module.exports.components['structures.RoomSubList'] = structures$RoomSubList);
|
structures$RoomSubList && (module.exports.components['structures.RoomSubList'] = structures$RoomSubList);
|
||||||
|
import structures$RoomSubListHeader from './components/structures/RoomSubListHeader';
|
||||||
|
structures$RoomSubListHeader && (module.exports.components['structures.RoomSubListHeader'] = structures$RoomSubListHeader);
|
||||||
import structures$SearchBox from './components/structures/SearchBox';
|
import structures$SearchBox from './components/structures/SearchBox';
|
||||||
structures$SearchBox && (module.exports.components['structures.SearchBox'] = structures$SearchBox);
|
structures$SearchBox && (module.exports.components['structures.SearchBox'] = structures$SearchBox);
|
||||||
import structures$ViewSource from './components/structures/ViewSource';
|
import structures$ViewSource from './components/structures/ViewSource';
|
||||||
|
|
|
@ -19,9 +19,11 @@ limitations under the License.
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var DragDropContext = require('react-dnd').DragDropContext;
|
var DragDropContext = require('react-dnd').DragDropContext;
|
||||||
var HTML5Backend = require('react-dnd-html5-backend');
|
var HTML5Backend = require('react-dnd-html5-backend');
|
||||||
|
var KeyCode = require('matrix-react-sdk/lib/KeyCode');
|
||||||
var sdk = require('matrix-react-sdk')
|
var sdk = require('matrix-react-sdk')
|
||||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||||
|
|
||||||
|
|
||||||
var VectorConferenceHandler = require('../../VectorConferenceHandler');
|
var VectorConferenceHandler = require('../../VectorConferenceHandler');
|
||||||
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
|
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
|
||||||
|
|
||||||
|
@ -40,6 +42,10 @@ var LeftPanel = React.createClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentWillMount: function() {
|
||||||
|
this.focusedElement = null;
|
||||||
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
},
|
},
|
||||||
|
@ -62,6 +68,91 @@ var LeftPanel = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onFocus: function(ev) {
|
||||||
|
this.focusedElement = ev.target;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onBlur: function(ev) {
|
||||||
|
this.focusedElement = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onKeyDown: function(ev) {
|
||||||
|
if (!this.focusedElement) return;
|
||||||
|
let handled = false;
|
||||||
|
|
||||||
|
switch (ev.keyCode) {
|
||||||
|
case KeyCode.UP:
|
||||||
|
this._onMoveFocus(true);
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
case KeyCode.DOWN:
|
||||||
|
this._onMoveFocus(false);
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onMoveFocus: function(up) {
|
||||||
|
var element = this.focusedElement;
|
||||||
|
|
||||||
|
// unclear why this isn't needed
|
||||||
|
// var descending = (up == this.focusDirection) ? this.focusDescending : !this.focusDescending;
|
||||||
|
// this.focusDirection = up;
|
||||||
|
|
||||||
|
var descending = false; // are we currently descending or ascending through the DOM tree?
|
||||||
|
var classes;
|
||||||
|
|
||||||
|
do {
|
||||||
|
var child = up ? element.lastElementChild : element.firstElementChild;
|
||||||
|
var sibling = up ? element.previousElementSibling : element.nextElementSibling;
|
||||||
|
|
||||||
|
if (descending) {
|
||||||
|
if (child) {
|
||||||
|
element = child;
|
||||||
|
}
|
||||||
|
else if (sibling) {
|
||||||
|
element = sibling;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
descending = false;
|
||||||
|
element = element.parentElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (sibling) {
|
||||||
|
element = sibling;
|
||||||
|
descending = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
element = element.parentElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
classes = element.classList;
|
||||||
|
if (classes.contains("mx_LeftPanel")) { // we hit the top
|
||||||
|
element = up ? element.lastElementChild : element.firstElementChild;
|
||||||
|
descending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while(element && !(
|
||||||
|
classes.contains("mx_RoomTile") ||
|
||||||
|
classes.contains("mx_SearchBox_search") ||
|
||||||
|
classes.contains("mx_RoomSubList_ellipsis")));
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
element.focus();
|
||||||
|
this.focusedElement = element;
|
||||||
|
this.focusedDescending = descending;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_recheckCallElement: function(selectedRoomId) {
|
_recheckCallElement: function(selectedRoomId) {
|
||||||
// if we aren't viewing a room with an ongoing call, but there is an
|
// if we aren't viewing a room with an ongoing call, but there is an
|
||||||
// active call, show the call element - we need to do this to make
|
// active call, show the call element - we need to do this to make
|
||||||
|
@ -120,7 +211,8 @@ var LeftPanel = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={classes} style={{ opacity: this.props.opacity }}>
|
<aside className={classes} style={{ opacity: this.props.opacity }}
|
||||||
|
onKeyDown={ this._onKeyDown } onFocus={ this._onFocus } onBlur={ this._onBlur }>
|
||||||
<SearchBox collapsed={ this.props.collapsed } onSearch={ this.onSearch } />
|
<SearchBox collapsed={ this.props.collapsed } onSearch={ this.onSearch } />
|
||||||
{ collapseButton }
|
{ collapseButton }
|
||||||
{ callPreview }
|
{ callPreview }
|
||||||
|
|
|
@ -23,7 +23,6 @@ var ContentRepo = require("matrix-js-sdk").ContentRepo;
|
||||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
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 dis = require('matrix-react-sdk/lib/dispatcher');
|
||||||
var GeminiScrollbar = require('react-gemini-scrollbar');
|
|
||||||
|
|
||||||
var linkify = require('linkifyjs');
|
var linkify = require('linkifyjs');
|
||||||
var linkifyString = require('linkifyjs/string');
|
var linkifyString = require('linkifyjs/string');
|
||||||
|
@ -162,7 +161,7 @@ module.exports = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failed to get public room list",
|
title: "Failed to get public room list",
|
||||||
description: "The server may be unavailable or overloaded",
|
description: ((err && err.message) ? err.message : "The server may be unavailable or overloaded"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -210,8 +209,8 @@ module.exports = React.createClass({
|
||||||
this.refreshRoomList();
|
this.refreshRoomList();
|
||||||
console.error("Failed to " + step + ": " + err);
|
console.error("Failed to " + step + ": " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to " + step,
|
||||||
description: "Failed to " + step,
|
description: ((err && err.message) ? err.message : "The server may be unavailable or overloaded"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -460,6 +459,17 @@ module.exports = React.createClass({
|
||||||
return fields;
|
return fields;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called by the parent component when PageUp/Down/etc is pressed.
|
||||||
|
*
|
||||||
|
* We pass it down to the scroll panel.
|
||||||
|
*/
|
||||||
|
handleScrollKey: function(ev) {
|
||||||
|
if (this.scrollPanel) {
|
||||||
|
this.scrollPanel.handleScrollKey(ev);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
const Loader = sdk.getComponent("elements.Spinner");
|
||||||
|
@ -538,7 +548,7 @@ module.exports = React.createClass({
|
||||||
const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
|
const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomDirectory">
|
<div className="mx_RoomDirectory">
|
||||||
<SimpleRoomHeader title="Directory" />
|
<SimpleRoomHeader title="Directory" icon="img/icons-directory.svg"/>
|
||||||
<div className="mx_RoomDirectory_list">
|
<div className="mx_RoomDirectory_list">
|
||||||
<div className="mx_RoomDirectory_listheader">
|
<div className="mx_RoomDirectory_listheader">
|
||||||
<DirectorySearchBox
|
<DirectorySearchBox
|
||||||
|
|
|
@ -27,8 +27,11 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||||
var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
|
var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
|
||||||
var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
|
var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
|
||||||
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
|
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
|
||||||
|
var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher');
|
||||||
|
var RoomSubListHeader = require('./RoomSubListHeader.js');
|
||||||
|
import Modal from 'matrix-react-sdk/lib/Modal';
|
||||||
|
|
||||||
// turn this on for drop & drag console debugging galore
|
// turn this on for drag & drop console debugging galore
|
||||||
var debug = false;
|
var debug = false;
|
||||||
|
|
||||||
const TRUNCATE_AT = 10;
|
const TRUNCATE_AT = 10;
|
||||||
|
@ -71,14 +74,12 @@ var RoomSubList = React.createClass({
|
||||||
|
|
||||||
order: React.PropTypes.string.isRequired,
|
order: React.PropTypes.string.isRequired,
|
||||||
|
|
||||||
// undefined if no room is selected (eg we are showing settings)
|
|
||||||
selectedRoom: React.PropTypes.string,
|
|
||||||
|
|
||||||
startAsHidden: React.PropTypes.bool,
|
startAsHidden: React.PropTypes.bool,
|
||||||
showSpinner: React.PropTypes.bool, // true to show a spinner if 0 elements when expanded
|
showSpinner: React.PropTypes.bool, // true to show a spinner if 0 elements when expanded
|
||||||
collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed?
|
collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed?
|
||||||
onHeaderClick: React.PropTypes.func,
|
onHeaderClick: React.PropTypes.func,
|
||||||
alwaysShowHeader: React.PropTypes.bool,
|
alwaysShowHeader: React.PropTypes.bool,
|
||||||
|
selectedRoom: React.PropTypes.string,
|
||||||
incomingCall: React.PropTypes.object,
|
incomingCall: React.PropTypes.object,
|
||||||
onShowMoreRooms: React.PropTypes.func,
|
onShowMoreRooms: React.PropTypes.func,
|
||||||
searchFilter: React.PropTypes.string,
|
searchFilter: React.PropTypes.string,
|
||||||
|
@ -100,13 +101,31 @@ var RoomSubList = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
|
constantTimeDispatcher.register("RoomSubList.sort", this.props.tagName, this.onSort);
|
||||||
|
constantTimeDispatcher.register("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh);
|
||||||
this.sortList(this.applySearchFilter(this.props.list, this.props.searchFilter), this.props.order);
|
this.sortList(this.applySearchFilter(this.props.list, this.props.searchFilter), this.props.order);
|
||||||
|
this._fixUndefinedOrder(this.props.list);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
constantTimeDispatcher.unregister("RoomSubList.sort", this.props.tagName, this.onSort);
|
||||||
|
constantTimeDispatcher.unregister("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillReceiveProps: function(newProps) {
|
componentWillReceiveProps: function(newProps) {
|
||||||
// order the room list appropriately before we re-render
|
// order the room list appropriately before we re-render
|
||||||
//if (debug) console.log("received new props, list = " + newProps.list);
|
//if (debug) console.log("received new props, list = " + newProps.list);
|
||||||
this.sortList(this.applySearchFilter(newProps.list, newProps.searchFilter), newProps.order);
|
this.sortList(this.applySearchFilter(newProps.list, newProps.searchFilter), newProps.order);
|
||||||
|
this._fixUndefinedOrder(newProps.list);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSort: function() {
|
||||||
|
this.sortList(this.applySearchFilter(this.props.list, this.props.searchFilter), this.props.order);
|
||||||
|
// we deliberately don't waste time trying to fix undefined ordering here
|
||||||
|
},
|
||||||
|
|
||||||
|
onRefresh: function() {
|
||||||
|
this.forceUpdate();
|
||||||
},
|
},
|
||||||
|
|
||||||
applySearchFilter: function(list, filter) {
|
applySearchFilter: function(list, filter) {
|
||||||
|
@ -119,7 +138,7 @@ var RoomSubList = React.createClass({
|
||||||
// The header is collapsable if it is hidden or not stuck
|
// The header is collapsable if it is hidden or not stuck
|
||||||
// The dataset elements are added in the RoomList _initAndPositionStickyHeaders method
|
// The dataset elements are added in the RoomList _initAndPositionStickyHeaders method
|
||||||
isCollapsableOnClick: function() {
|
isCollapsableOnClick: function() {
|
||||||
var stuck = this.refs.header.dataset.stuck;
|
var stuck = this.refs.header.refs.header.dataset.stuck;
|
||||||
if (this.state.hidden || stuck === undefined || stuck === "none") {
|
if (this.state.hidden || stuck === undefined || stuck === "none") {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,14 +161,15 @@ var RoomSubList = React.createClass({
|
||||||
this.props.onHeaderClick(isHidden);
|
this.props.onHeaderClick(isHidden);
|
||||||
} else {
|
} else {
|
||||||
// The header is stuck, so the click is to be interpreted as a scroll to the header
|
// 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);
|
this.props.onHeaderClick(this.state.hidden, this.refs.header.refs.header.dataset.originalPosition);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomTileClick(roomId) {
|
onRoomTileClick(roomId, ev) {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: roomId,
|
room_id: roomId,
|
||||||
|
clear_search: (ev && (ev.keyCode == 13 || ev.keyCode == 32)),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -211,9 +231,6 @@ var RoomSubList = React.createClass({
|
||||||
if (order === "manual") comparator = this.manualComparator;
|
if (order === "manual") comparator = this.manualComparator;
|
||||||
if (order === "recent") comparator = this.recentsComparator;
|
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);
|
//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) });
|
this.setState({ sortedList: list.sort(comparator) });
|
||||||
},
|
},
|
||||||
|
@ -248,10 +265,9 @@ var RoomSubList = React.createClass({
|
||||||
|
|
||||||
if (badges) {
|
if (badges) {
|
||||||
result[0] += notificationCount;
|
result[0] += notificationCount;
|
||||||
if (highlight) {
|
|
||||||
result[1] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result[1] |= highlight;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, [0, false]);
|
}, [0, false]);
|
||||||
|
@ -359,7 +375,6 @@ var RoomSubList = React.createClass({
|
||||||
var self = this;
|
var self = this;
|
||||||
var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile");
|
var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile");
|
||||||
return this.state.sortedList.map(function(room) {
|
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?
|
// XXX: is it evil to pass in self as a prop to RoomTile?
|
||||||
return (
|
return (
|
||||||
<DNDRoomTile
|
<DNDRoomTile
|
||||||
|
@ -367,9 +382,7 @@ var RoomSubList = React.createClass({
|
||||||
roomSubList={ self }
|
roomSubList={ self }
|
||||||
key={ room.roomId }
|
key={ room.roomId }
|
||||||
collapsed={ self.props.collapsed || false}
|
collapsed={ self.props.collapsed || false}
|
||||||
selected={ selected }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
unread={ Unread.doesRoomHaveUnreadMessages(room) }
|
|
||||||
highlight={ room.getUnreadNotificationCount('highlight') > 0 || self.props.label === 'Invites' }
|
|
||||||
isInvite={ self.props.label === 'Invites' }
|
isInvite={ self.props.label === 'Invites' }
|
||||||
refreshSubList={ self._updateSubListCount }
|
refreshSubList={ self._updateSubListCount }
|
||||||
incomingCall={ null }
|
incomingCall={ null }
|
||||||
|
@ -379,70 +392,6 @@ var RoomSubList = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_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.props.list.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 }/>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tabindex = this.props.searchFilter === "" ? "0" : "-1";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mx_RoomSubList_labelContainer" title={ title } ref="header">
|
|
||||||
<AccessibleButton onClick={ this.onClick } className="mx_RoomSubList_label" tabIndex={tabindex}>
|
|
||||||
{ this.props.collapsed ? '' : this.props.label }
|
|
||||||
<div className="mx_RoomSubList_roomCount">{ roomCount }</div>
|
|
||||||
<div className={chevronClasses}></div>
|
|
||||||
{ badge }
|
|
||||||
{ incomingCall }
|
|
||||||
</AccessibleButton>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
_createOverflowTile: function(overflowCount, totalCount) {
|
_createOverflowTile: function(overflowCount, totalCount) {
|
||||||
var content = <div className="mx_RoomSubList_chevronDown"></div>;
|
var content = <div className="mx_RoomSubList_chevronDown"></div>;
|
||||||
|
|
||||||
|
@ -498,7 +447,7 @@ var RoomSubList = React.createClass({
|
||||||
// gets triggered and another list is passed in. Doing it one at a time means that
|
// 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
|
// 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
|
// 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
|
// is run with historical room tag data, after that there should only be one undefined
|
||||||
// in the list at a time anyway.
|
// in the list at a time anyway.
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
if (list[i].tags[self.props.tagName] && list[i].tags[self.props.tagName].order === undefined) {
|
if (list[i].tags[self.props.tagName] && list[i].tags[self.props.tagName].order === undefined) {
|
||||||
|
@ -508,8 +457,8 @@ var RoomSubList = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to add tag " + self.props.tagName + " to room" + err);
|
console.error("Failed to add tag " + self.props.tagName + " to room" + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to add tag " + self.props.tagName + " to room",
|
||||||
description: "Failed to add tag " + self.props.tagName + " to room",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
@ -532,6 +481,16 @@ var RoomSubList = React.createClass({
|
||||||
target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>;
|
target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var roomCount = this.props.list.length > 0 ? this.props.list.length : '';
|
||||||
|
|
||||||
|
var isIncomingCallRoom;
|
||||||
|
if (this.props.incomingCall) {
|
||||||
|
// Check if the incoming call is for this section
|
||||||
|
isIncomingCallRoom = this.props.list.find(room=>{
|
||||||
|
return this.props.incomingCall.roomId === room.roomId;
|
||||||
|
}) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.state.sortedList.length > 0 || this.props.editable) {
|
if (this.state.sortedList.length > 0 || this.props.editable) {
|
||||||
var subList;
|
var subList;
|
||||||
var classes = "mx_RoomSubList";
|
var classes = "mx_RoomSubList";
|
||||||
|
@ -550,7 +509,19 @@ var RoomSubList = React.createClass({
|
||||||
|
|
||||||
return connectDropTarget(
|
return connectDropTarget(
|
||||||
<div>
|
<div>
|
||||||
{ this._getHeaderJsx() }
|
<RoomSubListHeader
|
||||||
|
ref='header'
|
||||||
|
label={ this.props.label }
|
||||||
|
tagName={ this.props.tagName }
|
||||||
|
roomCount={ roomCount }
|
||||||
|
collapsed={ this.props.collapsed }
|
||||||
|
hidden={ this.state.hidden }
|
||||||
|
incomingCall={ this.props.incomingCall }
|
||||||
|
isIncomingCallRoom={ isIncomingCallRoom }
|
||||||
|
roomNotificationCount={ this.roomNotificationCount() }
|
||||||
|
onClick={ this.onClick }
|
||||||
|
onHeaderClick={ this.props.onHeaderClick }
|
||||||
|
/>
|
||||||
{ subList }
|
{ subList }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -559,7 +530,20 @@ var RoomSubList = React.createClass({
|
||||||
var Loader = sdk.getComponent("elements.Spinner");
|
var Loader = sdk.getComponent("elements.Spinner");
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomSubList">
|
<div className="mx_RoomSubList">
|
||||||
{ this.props.alwaysShowHeader ? this._getHeaderJsx() : undefined }
|
{ this.props.alwaysShowHeader ?
|
||||||
|
<RoomSubListHeader
|
||||||
|
ref='header'
|
||||||
|
label={ this.props.label }
|
||||||
|
tagName={ this.props.tagName }
|
||||||
|
roomCount={ roomCount }
|
||||||
|
collapsed={ this.props.collapsed }
|
||||||
|
hidden={ this.state.hidden }
|
||||||
|
isIncomingCallRoom={ isIncomingCallRoom }
|
||||||
|
roomNotificationCount={ this.roomNotificationCount() }
|
||||||
|
onClick={ this.onClick }
|
||||||
|
onHeaderClick={ this.props.onHeaderClick }
|
||||||
|
/>
|
||||||
|
: undefined }
|
||||||
{ (this.props.showSpinner && !this.state.hidden) ? <Loader /> : undefined }
|
{ (this.props.showSpinner && !this.state.hidden) ? <Loader /> : undefined }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
121
src/components/structures/RoomSubListHeader.js
Normal file
121
src/components/structures/RoomSubListHeader.js
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 Vector Creations 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 ReactDOM = require('react-dom');
|
||||||
|
var classNames = require('classnames');
|
||||||
|
var sdk = require('matrix-react-sdk')
|
||||||
|
var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
|
||||||
|
var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
|
||||||
|
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
|
||||||
|
var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher');
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'RoomSubListHeader',
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
label: React.PropTypes.string.isRequired,
|
||||||
|
tagName: React.PropTypes.string,
|
||||||
|
roomCount: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.string,
|
||||||
|
React.PropTypes.number
|
||||||
|
]),
|
||||||
|
collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed?
|
||||||
|
incomingCall: React.PropTypes.object,
|
||||||
|
isIncomingCallRoom: React.PropTypes.bool,
|
||||||
|
roomNotificationCount: React.PropTypes.array,
|
||||||
|
hidden: React.PropTypes.bool,
|
||||||
|
onClick: React.PropTypes.func,
|
||||||
|
onHeaderClick: React.PropTypes.func,
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
onHeaderClick: function() {}, // NOP
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillMount: function() {
|
||||||
|
// constantTimeDispatcher.register("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
// constantTimeDispatcher.unregister("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh);
|
||||||
|
},
|
||||||
|
|
||||||
|
// onRefresh: function() {
|
||||||
|
// this.forceUpdate();
|
||||||
|
// },
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||||
|
|
||||||
|
var subListNotifications = this.props.roomNotificationCount;
|
||||||
|
var subListNotifCount = subListNotifications[0];
|
||||||
|
var subListNotifHighlight = subListNotifications[1];
|
||||||
|
|
||||||
|
var chevronClasses = classNames({
|
||||||
|
'mx_RoomSubList_chevron': true,
|
||||||
|
'mx_RoomSubList_chevronRight': this.props.hidden,
|
||||||
|
'mx_RoomSubList_chevronDown': !this.props.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>;
|
||||||
|
}
|
||||||
|
else if (subListNotifHighlight) {
|
||||||
|
badge = <div className={badgeClasses}>!</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When collapsed, allow a long hover on the header to show user
|
||||||
|
// the full tag name and room count
|
||||||
|
var title;
|
||||||
|
var roomCount = this.props.roomCount;
|
||||||
|
if (this.props.collapsed) {
|
||||||
|
title = this.props.label;
|
||||||
|
if (roomCount !== '') {
|
||||||
|
title += " [" + roomCount + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var incomingCall;
|
||||||
|
if (this.props.isIncomingCallRoom) {
|
||||||
|
var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
|
||||||
|
incomingCall = <IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={ this.props.incomingCall }/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx_RoomSubList_labelContainer" title={ title } ref="header">
|
||||||
|
<AccessibleButton onClick={ this.props.onClick } className="mx_RoomSubList_label" tabIndex="0">
|
||||||
|
{ this.props.collapsed ? '' : this.props.label }
|
||||||
|
<div className="mx_RoomSubList_roomCount">{ roomCount }</div>
|
||||||
|
<div className={chevronClasses}></div>
|
||||||
|
{ badge }
|
||||||
|
</AccessibleButton>
|
||||||
|
{ incomingCall }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
@ -21,6 +21,7 @@ var sdk = require('matrix-react-sdk')
|
||||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||||
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');
|
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');
|
||||||
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
|
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
|
||||||
|
var KeyCode = require('matrix-react-sdk/lib/KeyCode');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'SearchBox',
|
displayName: 'SearchBox',
|
||||||
|
@ -38,25 +39,23 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
|
document.addEventListener('keydown', this._onKeyDown);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
|
document.removeEventListener('keydown', this._onKeyDown);
|
||||||
},
|
},
|
||||||
|
|
||||||
onAction: function(payload) {
|
onAction: function(payload) {
|
||||||
// Disabling this as I find it really really annoying, and was used to the
|
|
||||||
// previous behaviour - see https://github.com/vector-im/riot-web/issues/3348
|
|
||||||
/*
|
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
// Clear up the text field when a room is selected.
|
// Clear up the text field when a room is selected.
|
||||||
case 'view_room':
|
case 'view_room':
|
||||||
if (this.refs.search) {
|
if (payload.clear_search && this.refs.search) {
|
||||||
this._clearSearch();
|
this._clearSearch();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onChange: function() {
|
onChange: function() {
|
||||||
|
@ -90,6 +89,38 @@ module.exports = React.createClass({
|
||||||
this.onChange();
|
this.onChange();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onKeyDown: function(ev) {
|
||||||
|
let handled = false;
|
||||||
|
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||||
|
let ctrlCmdOnly;
|
||||||
|
if (isMac) {
|
||||||
|
ctrlCmdOnly = ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
|
||||||
|
} else {
|
||||||
|
ctrlCmdOnly = ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ev.keyCode) {
|
||||||
|
case KeyCode.ESCAPE:
|
||||||
|
this._clearSearch();
|
||||||
|
dis.dispatch({action: 'focus_composer'});
|
||||||
|
break;
|
||||||
|
case KeyCode.KEY_K:
|
||||||
|
if (ctrlCmdOnly) {
|
||||||
|
if (this.refs.search) {
|
||||||
|
this.refs.search.focus();
|
||||||
|
this.refs.search.select();
|
||||||
|
}
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var TintableSvg = sdk.getComponent('elements.TintableSvg');
|
var TintableSvg = sdk.getComponent('elements.TintableSvg');
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ module.exports = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failed to remove tag " + tagNameOff + " from room",
|
title: "Failed to remove tag " + tagNameOff + " from room",
|
||||||
description: err.toString()
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ module.exports = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failed to add tag " + tagNameOn + " to room",
|
title: "Failed to add tag " + tagNameOn + " to room",
|
||||||
description: err.toString()
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ module.exports = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failed to set Direct Message status of room",
|
title: "Failed to set Direct Message status of room",
|
||||||
description: err.toString()
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -187,8 +187,8 @@ module.exports = React.createClass({
|
||||||
var errCode = err.errcode || "unknown error code";
|
var errCode = err.errcode || "unknown error code";
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: `Failed to forget room (${errCode})`,
|
||||||
description: `Failed to forget room (${errCode})`
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sdk from 'matrix-react-sdk';
|
import sdk from 'matrix-react-sdk';
|
||||||
import rageshake from '../../../vector/rageshake';
|
import SdkConfig from 'matrix-react-sdk/lib/SdkConfig';
|
||||||
|
|
||||||
export default class BugReportDialog extends React.Component {
|
export default class BugReportDialog extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
|
@ -26,11 +26,18 @@ export default class BugReportDialog extends React.Component {
|
||||||
busy: false,
|
busy: false,
|
||||||
err: null,
|
err: null,
|
||||||
text: "",
|
text: "",
|
||||||
|
progress: null,
|
||||||
};
|
};
|
||||||
|
this._unmounted = false;
|
||||||
this._onSubmit = this._onSubmit.bind(this);
|
this._onSubmit = this._onSubmit.bind(this);
|
||||||
this._onCancel = this._onCancel.bind(this);
|
this._onCancel = this._onCancel.bind(this);
|
||||||
this._onTextChange = this._onTextChange.bind(this);
|
this._onTextChange = this._onTextChange.bind(this);
|
||||||
this._onSendLogsChange = this._onSendLogsChange.bind(this);
|
this._onSendLogsChange = this._onSendLogsChange.bind(this);
|
||||||
|
this._sendProgressCallback = this._sendProgressCallback.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._unmounted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCancel(ev) {
|
_onCancel(ev) {
|
||||||
|
@ -46,12 +53,27 @@ export default class BugReportDialog extends React.Component {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({ busy: true, err: null });
|
this.setState({ busy: true, progress: null, err: null });
|
||||||
rageshake.sendBugReport(userText, sendLogs).then(() => {
|
this._sendProgressCallback("Loading bug report module");
|
||||||
this.setState({ busy: false });
|
|
||||||
this.props.onFinished(false);
|
require(['../../../vector/submit-rageshake'], (s) => {
|
||||||
}, (err) => {
|
s(SdkConfig.get().bug_report_endpoint_url, {
|
||||||
this.setState({ busy: false, err: `Failed: ${err.message}` });
|
userText: userText,
|
||||||
|
sendLogs: sendLogs,
|
||||||
|
progressCallback: this._sendProgressCallback,
|
||||||
|
}).then(() => {
|
||||||
|
if (!this._unmounted) {
|
||||||
|
this.setState({ busy: false, progress: null });
|
||||||
|
this.props.onFinished(false);
|
||||||
|
}
|
||||||
|
}, (err) => {
|
||||||
|
if (!this._unmounted) {
|
||||||
|
this.setState({
|
||||||
|
busy: false, progress: null,
|
||||||
|
err: `Failed to send report: ${err.message}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +85,13 @@ export default class BugReportDialog extends React.Component {
|
||||||
this.setState({ sendLogs: ev.target.checked });
|
this.setState({ sendLogs: ev.target.checked });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_sendProgressCallback(progress) {
|
||||||
|
if (this._unmounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({progress: progress});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
const Loader = sdk.getComponent("elements.Spinner");
|
||||||
|
|
||||||
|
@ -73,8 +102,6 @@ export default class BugReportDialog extends React.Component {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const okLabel = this.state.busy ? <Loader /> : 'Send';
|
|
||||||
|
|
||||||
let cancelButton = null;
|
let cancelButton = null;
|
||||||
if (!this.state.busy) {
|
if (!this.state.busy) {
|
||||||
cancelButton = <button onClick={this._onCancel}>
|
cancelButton = <button onClick={this._onCancel}>
|
||||||
|
@ -82,6 +109,16 @@ export default class BugReportDialog extends React.Component {
|
||||||
</button>;
|
</button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let progress = null;
|
||||||
|
if (this.state.busy) {
|
||||||
|
progress = (
|
||||||
|
<div className="progress">
|
||||||
|
<Loader />
|
||||||
|
{this.state.progress} ...
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_BugReportDialog">
|
<div className="mx_BugReportDialog">
|
||||||
<div className="mx_Dialog_title">
|
<div className="mx_Dialog_title">
|
||||||
|
@ -104,6 +141,7 @@ export default class BugReportDialog extends React.Component {
|
||||||
<input type="checkbox" checked={this.state.sendLogs}
|
<input type="checkbox" checked={this.state.sendLogs}
|
||||||
onChange={this._onSendLogsChange} id="mx_BugReportDialog_logs"/>
|
onChange={this._onSendLogsChange} id="mx_BugReportDialog_logs"/>
|
||||||
<label htmlFor="mx_BugReportDialog_logs">Send logs</label>
|
<label htmlFor="mx_BugReportDialog_logs">Send logs</label>
|
||||||
|
{progress}
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
|
@ -111,8 +149,9 @@ export default class BugReportDialog extends React.Component {
|
||||||
className="mx_Dialog_primary danger"
|
className="mx_Dialog_primary danger"
|
||||||
onClick={this._onSubmit}
|
onClick={this._onSubmit}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
|
disabled={this.state.busy}
|
||||||
>
|
>
|
||||||
{okLabel}
|
Send
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{cancelButton}
|
{cancelButton}
|
||||||
|
|
|
@ -176,7 +176,7 @@ module.exports = React.createClass({
|
||||||
{ this.getName() }
|
{ this.getName() }
|
||||||
</div>
|
</div>
|
||||||
{ eventMeta }
|
{ eventMeta }
|
||||||
<a className="mx_ImageView_link" href={ this.props.src } target="_blank" rel="noopener">
|
<a className="mx_ImageView_link" href={ this.props.src } download={ this.props.name } target="_blank" rel="noopener">
|
||||||
<div className="mx_ImageView_download">
|
<div className="mx_ImageView_download">
|
||||||
Download this file<br/>
|
Download this file<br/>
|
||||||
<span className="mx_ImageView_size">{ size_res }</span>
|
<span className="mx_ImageView_size">{ size_res }</span>
|
||||||
|
|
|
@ -18,6 +18,9 @@ limitations under the License.
|
||||||
|
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
|
|
||||||
|
const i = [1, 2, 3, 4, 5][Math.floor(Math.random() * 5)];
|
||||||
|
const DEFAULT_LOGO_URI = "img/logos/riot-logo-" + i + ".svg";
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'VectorLoginHeader',
|
displayName: 'VectorLoginHeader',
|
||||||
statics: {
|
statics: {
|
||||||
|
@ -30,7 +33,7 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div className="mx_Login_logo">
|
<div className="mx_Login_logo">
|
||||||
<img src={this.props.icon || "img/logo.png"} alt="Riot"/>
|
<img src={this.props.icon || DEFAULT_LOGO_URI} alt="Riot"/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
var date = new Date(this.props.ts);
|
var date = new Date(this.props.ts);
|
||||||
return (
|
return (
|
||||||
<span className="mx_MessageTimestamp">
|
<span className="mx_MessageTimestamp" title={ DateUtils.formatDate(date) }>
|
||||||
{ DateUtils.formatTime(date) }
|
{ DateUtils.formatTime(date) }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
|
@ -90,8 +90,8 @@ var roomTileSource = {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to set direct chat tag " + err);
|
console.error("Failed to set direct chat tag " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to set direct chat tag",
|
||||||
description: "Failed to set direct chat tag",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -115,8 +115,8 @@ var roomTileSource = {
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to remove tag " + prevTag + " from room: " + err);
|
console.error("Failed to remove tag " + prevTag + " from room: " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to remove tag " + prevTag + " from room",
|
||||||
description: "Failed to remove tag " + prevTag + " from room",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -137,8 +137,8 @@ var roomTileSource = {
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to add tag " + newTag + " to room: " + err);
|
console.error("Failed to add tag " + newTag + " to room: " + err);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to add tag " + newTag + " to room",
|
||||||
description: "Failed to add tag " + newTag + " to room",
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,20 +22,12 @@ module.exports = React.createClass({
|
||||||
displayName: 'RoomDropTarget',
|
displayName: 'RoomDropTarget',
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
if (this.props.placeholder) {
|
return (
|
||||||
return (
|
<div className="mx_RoomDropTarget">
|
||||||
<div className="mx_RoomDropTarget mx_RoomDropTarget_placeholder">
|
<div className="mx_RoomDropTarget_label">
|
||||||
|
{ this.props.label }
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
else {
|
|
||||||
return (
|
|
||||||
<div className="mx_RoomDropTarget">
|
|
||||||
<div className="mx_RoomDropTarget_label">
|
|
||||||
{ this.props.label }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -240,8 +240,8 @@ module.exports = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to change settings: " + error);
|
console.error("Failed to change settings: " + error);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to change settings",
|
||||||
description: "Failed to change settings",
|
description: ((error && error.message) ? error.message : "Operation failed"),
|
||||||
onFinished: self._refreshFromServer
|
onFinished: self._refreshFromServer
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -310,8 +310,8 @@ module.exports = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Can't update user notification settings: " + error);
|
console.error("Can't update user notification settings: " + error);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Can't update user notification settings",
|
||||||
description: "Can't update user notification settings",
|
description: ((error && error.message) ? error.message : "Operation failed"),
|
||||||
onFinished: self._refreshFromServer
|
onFinished: self._refreshFromServer
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -352,8 +352,8 @@ module.exports = React.createClass({
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
console.error("Failed to update keywords: " + error);
|
console.error("Failed to update keywords: " + error);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Error",
|
title: "Failed to update keywords",
|
||||||
description: "Failed to update keywords",
|
description: ((error && error.message) ? error.message : "Operation failed"),
|
||||||
onFinished: self._refreshFromServer
|
onFinished: self._refreshFromServer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ input[type=text].error, input[type=password].error {
|
||||||
border: 1px solid $warning-color;
|
border: 1px solid $warning-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=text]:focus, textarea:focus {
|
input[type=text]:focus, input[type=password]:focus, textarea:focus {
|
||||||
border: 1px solid $accent-color;
|
border: 1px solid $accent-color;
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
@ -225,6 +225,10 @@ textarea {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_Dialog button:focus, .mx_Dialog input[type="submit"]:focus {
|
||||||
|
filter: brightness($focus-brightness);
|
||||||
|
}
|
||||||
|
|
||||||
.mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary {
|
.mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary {
|
||||||
color: $accent-fg-color;
|
color: $accent-fg-color;
|
||||||
background-color: $accent-color;
|
background-color: $accent-color;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
@import "./matrix-react-sdk/views/dialogs/_EncryptedEventDialog.scss";
|
@import "./matrix-react-sdk/views/dialogs/_EncryptedEventDialog.scss";
|
||||||
@import "./matrix-react-sdk/views/dialogs/_SetDisplayNameDialog.scss";
|
@import "./matrix-react-sdk/views/dialogs/_SetDisplayNameDialog.scss";
|
||||||
@import "./matrix-react-sdk/views/dialogs/_UnknownDeviceDialog.scss";
|
@import "./matrix-react-sdk/views/dialogs/_UnknownDeviceDialog.scss";
|
||||||
|
@import "./matrix-react-sdk/views/elements/_AccessibleButton.scss";
|
||||||
@import "./matrix-react-sdk/views/elements/_AddressSelector.scss";
|
@import "./matrix-react-sdk/views/elements/_AddressSelector.scss";
|
||||||
@import "./matrix-react-sdk/views/elements/_AddressTile.scss";
|
@import "./matrix-react-sdk/views/elements/_AddressTile.scss";
|
||||||
@import "./matrix-react-sdk/views/elements/_DirectorySearchBox.scss";
|
@import "./matrix-react-sdk/views/elements/_DirectorySearchBox.scss";
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
@import "./matrix-react-sdk/views/elements/_RichText.scss";
|
@import "./matrix-react-sdk/views/elements/_RichText.scss";
|
||||||
@import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss";
|
@import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss";
|
||||||
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
|
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
|
||||||
|
@import "./matrix-react-sdk/views/messages/_MEmoteBody.scss";
|
||||||
@import "./matrix-react-sdk/views/messages/_MImageBody.scss";
|
@import "./matrix-react-sdk/views/messages/_MImageBody.scss";
|
||||||
@import "./matrix-react-sdk/views/messages/_MNoticeBody.scss";
|
@import "./matrix-react-sdk/views/messages/_MNoticeBody.scss";
|
||||||
@import "./matrix-react-sdk/views/messages/_MTextBody.scss";
|
@import "./matrix-react-sdk/views/messages/_MTextBody.scss";
|
||||||
|
|
|
@ -160,7 +160,8 @@ hr.mx_RoomView_myReadMarker {
|
||||||
border-bottom: solid 1px $accent-color;
|
border-bottom: solid 1px $accent-color;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 5px;
|
top: -1px;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_statusArea {
|
.mx_RoomView_statusArea {
|
||||||
|
@ -171,7 +172,7 @@ hr.mx_RoomView_myReadMarker {
|
||||||
|
|
||||||
max-height: 0px;
|
max-height: 0px;
|
||||||
background-color: $primary-bg-color;
|
background-color: $primary-bg-color;
|
||||||
z-index: 1000;
|
z-index: 5;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
-webkit-transition: all .2s ease-out;
|
-webkit-transition: all .2s ease-out;
|
||||||
|
@ -259,4 +260,4 @@ hr.mx_RoomView_myReadMarker {
|
||||||
|
|
||||||
.mx_RoomView_ongoingConfCallNotification a {
|
.mx_RoomView_ongoingConfCallNotification a {
|
||||||
color: $accent-fg-color ! important;
|
color: $accent-fg-color ! important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,15 @@ limitations under the License.
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_UserSettings_phoneSection {
|
||||||
|
display:table;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_UserSettings_phoneCountry {
|
||||||
|
width: 70px;
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
input.mx_UserSettings_phoneNumberField {
|
input.mx_UserSettings_phoneNumberField {
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
width: 172px;
|
width: 172px;
|
||||||
|
@ -213,3 +222,9 @@ input.mx_UserSettings_phoneNumberField {
|
||||||
.mx_UserSettings_avatarPicker_edit > input {
|
.mx_UserSettings_avatarPicker_edit > input {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_UserSettings_advanced_spoiler {
|
||||||
|
cursor: pointer;
|
||||||
|
color: $accent-color;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
|
@ -42,7 +42,8 @@ limitations under the License.
|
||||||
|
|
||||||
.mx_Login_logo {
|
.mx_Login_logo {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 195px;
|
height: 150px;
|
||||||
|
margin-bottom: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_logo img {
|
.mx_Login_logo img {
|
||||||
|
@ -66,10 +67,6 @@ limitations under the License.
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_username {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_Login_fieldLabel {
|
.mx_Login_fieldLabel {
|
||||||
margin-top: -10px;
|
margin-top: -10px;
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
|
@ -167,16 +164,82 @@ limitations under the License.
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_phoneSection {
|
.mx_Login_type_container {
|
||||||
display: table;
|
display: flex;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_type_label {
|
||||||
|
flex-grow: 1;
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_type_dropdown {
|
||||||
|
width: 125px;
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_field_group {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_field_prefix {
|
||||||
|
height: 33px;
|
||||||
|
padding: 0px 5px;
|
||||||
|
line-height: 33px;
|
||||||
|
|
||||||
|
background-color: #eee;
|
||||||
|
border: 1px solid #c7c7c7;
|
||||||
|
border-right: 0px;
|
||||||
|
border-radius: 3px 0px 0px 3px;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_field_suffix {
|
||||||
|
height: 33px;
|
||||||
|
padding: 0px 5px;
|
||||||
|
line-height: 33px;
|
||||||
|
|
||||||
|
background-color: #eee;
|
||||||
|
border: 1px solid #c7c7c7;
|
||||||
|
border-left: 0px;
|
||||||
|
border-radius: 0px 3px 3px 0px;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_username {
|
||||||
|
flex-shrink: 1;
|
||||||
|
min-width: 0px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_field_has_prefix {
|
||||||
|
border-top-left-radius: 0px;
|
||||||
|
border-bottom-left-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_field_has_suffix {
|
||||||
|
border-top-right-radius: 0px;
|
||||||
|
border-bottom-right-radius: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_phoneCountry {
|
.mx_Login_phoneCountry {
|
||||||
display: table-cell;
|
margin-bottom: 14px;
|
||||||
width: 70px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_phoneNumberField {
|
.mx_Login_phoneCountry .mx_Dropdown_option {
|
||||||
width: 210px;
|
/*
|
||||||
margin-left: 3px;
|
To match height of mx_Login_field
|
||||||
|
33px + 2px border from mx_Dropdown_option = 35px
|
||||||
|
*/
|
||||||
|
height: 33px;
|
||||||
|
line-height: 33px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_phoneCountry .mx_Dropdown_option img {
|
||||||
|
margin: 4px;
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 Vector Creations 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_AccessibleButton:focus {
|
||||||
|
outline: 0;
|
||||||
|
filter: brightness($focus-brightness);
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,15 @@ limitations under the License.
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_Dropdown_input:focus {
|
||||||
|
border-color: $accent-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable dropdown highlight on focus */
|
||||||
|
.mx_Dropdown_input.mx_AccessibleButton:focus {
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_Dropdown_arrow {
|
.mx_Dropdown_arrow {
|
||||||
border-color: $primary-fg-color transparent transparent;
|
border-color: $primary-fg-color transparent transparent;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
|
@ -74,7 +83,7 @@ input.mx_Dropdown_option, input.mx_Dropdown_option:focus {
|
||||||
border: 1px solid $accent-color;
|
border: 1px solid $accent-color;
|
||||||
background-color: $primary-bg-color;
|
background-color: $primary-bg-color;
|
||||||
max-height: 200px;
|
max-height: 200px;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Dropdown_menu .mx_Dropdown_option_highlight {
|
.mx_Dropdown_menu .mx_Dropdown_option_highlight {
|
||||||
|
|
|
@ -20,6 +20,7 @@ limitations under the License.
|
||||||
|
|
||||||
.mx_TextualEvent.mx_MemberEventListSummary_summary {
|
.mx_TextualEvent.mx_MemberEventListSummary_summary {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MemberEventListSummary_avatars {
|
.mx_MemberEventListSummary_avatars {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 Vector Creations 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_MEmoteBody_sender {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
|
@ -133,10 +133,18 @@ limitations under the License.
|
||||||
.mx_EventTile_redacted .mx_EventTile_line .mx_UnknownBody {
|
.mx_EventTile_redacted .mx_EventTile_line .mx_UnknownBody {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 300px;
|
height: 36px;
|
||||||
height: 24px;
|
background-image: $event-redacted-img;
|
||||||
border-radius: 4px;
|
background-repeat: no-repeat;
|
||||||
background-color: black;
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile.mx_EventTile_redacted .mx_EventTile_line {
|
||||||
|
/*
|
||||||
|
Prevent changing colour of the background because
|
||||||
|
$event-redacted-img matches $primary-bg-color
|
||||||
|
*/
|
||||||
|
background-color: initial !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_highlight,
|
.mx_EventTile_highlight,
|
||||||
|
@ -210,8 +218,8 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_EventTile_continuation .mx_EventTile_readAvatars,
|
.mx_EventTile_continuation .mx_EventTile_readAvatars,
|
||||||
.mx_EventTile_info .mx_EventTile_readAvatars
|
.mx_EventTile_info .mx_EventTile_readAvatars,
|
||||||
{
|
.mx_EventTile_emote .mx_EventTile_readAvatars {
|
||||||
top: 7px;
|
top: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,6 +331,14 @@ limitations under the License.
|
||||||
font-family: inherit ! important;
|
font-family: inherit ! important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Make h1 and h2 the same size as h3. */
|
||||||
|
.mx_EventTile_content .markdown-body h1,
|
||||||
|
.mx_EventTile_content .markdown-body h2
|
||||||
|
{
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_EventTile_content .markdown-body a {
|
.mx_EventTile_content .markdown-body a {
|
||||||
color: $accent-color;
|
color: $accent-color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ limitations under the License.
|
||||||
margin-left: -2px;
|
margin-left: -2px;
|
||||||
order: 1;
|
order: 1;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomHeader_spinner {
|
.mx_RoomHeader_spinner {
|
||||||
|
@ -95,6 +96,12 @@ limitations under the License.
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_RoomHeader_simpleHeader .mx_RoomHeader_icon {
|
||||||
|
margin-left: 14px;
|
||||||
|
margin-right: 24px;
|
||||||
|
vertical-align: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_RoomHeader_name {
|
.mx_RoomHeader_name {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -156,7 +156,7 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomTile:focus {
|
.mx_RoomTile:focus {
|
||||||
outline: 0;
|
filter: none ! important;
|
||||||
background-color: $roomtile-focused-bg-color;
|
background-color: $roomtile-focused-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,15 @@ limitations under the License.
|
||||||
.mx_TopUnreadMessagesBar {
|
.mx_TopUnreadMessagesBar {
|
||||||
margin: auto; /* centre horizontally */
|
margin: auto; /* centre horizontally */
|
||||||
max-width: 960px;
|
max-width: 960px;
|
||||||
padding-top: 5px;
|
padding-top: 10px;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px solid $primary-hairline-color;
|
border-bottom: 1px solid $primary-hairline-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_TopUnreadMessagesBar_scrollUp {
|
.mx_TopUnreadMessagesBar_scrollUp {
|
||||||
display: inline;
|
display: inline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_TopUnreadMessagesBar_scrollUp img {
|
.mx_TopUnreadMessagesBar_scrollUp img {
|
||||||
|
|
|
@ -15,6 +15,8 @@ $accent-color: #76CFA6;
|
||||||
|
|
||||||
$selection-fg-color: $primary-bg-color;
|
$selection-fg-color: $primary-bg-color;
|
||||||
|
|
||||||
|
$focus-brightness: 125%;
|
||||||
|
|
||||||
// red warning colour
|
// red warning colour
|
||||||
$warning-color: #ff0064;
|
$warning-color: #ff0064;
|
||||||
|
|
||||||
|
@ -93,6 +95,9 @@ $event-encrypting-color: #abddbc;
|
||||||
$event-sending-color: #ddd;
|
$event-sending-color: #ddd;
|
||||||
$event-notsent-color: #f44;
|
$event-notsent-color: #f44;
|
||||||
|
|
||||||
|
// event redaction
|
||||||
|
$event-redacted-img: url('../../img/redacted.jpg');
|
||||||
|
|
||||||
// event timestamp
|
// event timestamp
|
||||||
$event-timestamp-color: #acacac;
|
$event-timestamp-color: #acacac;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ $accent-color: #76CFA6;
|
||||||
|
|
||||||
$selection-fg-color: $primary-fg-color;
|
$selection-fg-color: $primary-fg-color;
|
||||||
|
|
||||||
|
$focus-brightness: 200%;
|
||||||
|
|
||||||
// red warning colour
|
// red warning colour
|
||||||
$warning-color: #ff0064;
|
$warning-color: #ff0064;
|
||||||
|
|
||||||
|
@ -93,6 +95,9 @@ $event-encrypting-color: rgba(171, 221, 188, 0.4);
|
||||||
$event-sending-color: #888;
|
$event-sending-color: #888;
|
||||||
$event-notsent-color: #f44;
|
$event-notsent-color: #f44;
|
||||||
|
|
||||||
|
// event redaction
|
||||||
|
$event-redacted-img: url('../../img/redacted-dark.jpg');
|
||||||
|
|
||||||
// event timestamp
|
// event timestamp
|
||||||
$event-timestamp-color: #acacac;
|
$event-timestamp-color: #acacac;
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,17 @@ limitations under the License.
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
color: $primary-fg-color;
|
color: $primary-fg-color;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_RoomDirectory .mx_RoomHeader_simpleHeader {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_RoomDirectory_list {
|
.mx_RoomDirectory_list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
|
|
|
@ -33,11 +33,6 @@ limitations under the License.
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomDropTarget_placeholder {
|
|
||||||
padding-top: 1px;
|
|
||||||
padding-bottom: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_RoomDropTarget_label {
|
.mx_RoomDropTarget_label {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<svg width="25px" height="25px" viewBox="0 0 25 25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
<svg width="25px" height="25px" viewBox="0 0 25 25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: sketchtool 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
|
||||||
<title>E34C64ED-EBD7-49B6-BDD9-CB729162705A</title>
|
<title>icons_directory</title>
|
||||||
<desc>Created with sketchtool.</desc>
|
<desc>Created with Sketch.</desc>
|
||||||
<defs>
|
<defs></defs>
|
||||||
<rect id="path-1" x="6" y="10" width="13" height="8" rx="1"></rect>
|
|
||||||
<mask id="mask-2" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="13" height="8" fill="white">
|
|
||||||
<use xlink:href="#path-1"></use>
|
|
||||||
</mask>
|
|
||||||
</defs>
|
|
||||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
<g id="Room-list-Copy-3" transform="translate(-58.000000, -726.000000)">
|
<g id="Left-panel" transform="translate(-83.000000, -726.000000)">
|
||||||
<g id="icons_directory" transform="translate(58.000000, 726.000000)">
|
<g id="icons_directory">
|
||||||
<path d="M12.5,25 C19.4035594,25 25,19.4035594 25,12.5 C25,5.59644063 19.4035594,0 12.5,0 C5.59644063,0 0,5.59644063 0,12.5 C0,19.4035594 5.59644063,25 12.5,25 Z" id="Oval-1-Copy-7" fill="#76CFA6"></path>
|
<g transform="translate(83.000000, 726.000000)">
|
||||||
<use id="Rectangle-9" stroke="#FFFFFF" mask="url(#mask-2)" stroke-width="2" opacity="0.8" xlink:href="#path-1"></use>
|
<path d="M12.5,25 C19.4035594,25 25,19.4035594 25,12.5 C25,5.59644063 19.4035594,0 12.5,0 C5.59644063,0 0,5.59644063 0,12.5 C0,19.4035594 5.59644063,25 12.5,25 Z" id="Oval-1-Copy-7" fill="#76CFA6"></path>
|
||||||
<path d="M6,9 L6,6.99895656 C6,6.44724809 6.45097518,6 6.99077797,6 L11.009222,6 C11.5564136,6 12,6.44386482 12,7 L12,8 L17.9970707,8 C18.5509732,8 19,8.45318604 19,9 L19,9 L6,9 Z" id="Path-Copy" fill="#FFFFFF" opacity="0.6"></path>
|
<g id="Lines" transform="translate(6.000000, 7.000000)" stroke="#FFFFFF" stroke-linecap="round">
|
||||||
|
<path d="M4,5.5 L9,5.5" id="Line"></path>
|
||||||
|
<path d="M4,1.5 L13,1.5" id="Line-Copy-4"></path>
|
||||||
|
<path d="M0,1.5 L2,1.5" id="Line" opacity="0.6"></path>
|
||||||
|
<path d="M0,5.5 L2,5.5" id="Line" opacity="0.6"></path>
|
||||||
|
<path d="M4,9.5 L11,9.5" id="Line-Copy-6"></path>
|
||||||
|
<path d="M0,9.5 L2,9.5" id="Line-Copy-3" opacity="0.6"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
BIN
src/skins/vector/img/redacted-dark.jpg
Normal file
BIN
src/skins/vector/img/redacted-dark.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
src/skins/vector/img/redacted.jpg
Normal file
BIN
src/skins/vector/img/redacted.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
21
src/skins/vector/img/scrollto.svg
Normal file
21
src/skins/vector/img/scrollto.svg
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>Slice 1</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="scrollup">
|
||||||
|
<g id="02-Chat" transform="translate(12.000000, 12.000000) scale(-1, 1) rotate(-180.000000) translate(-12.000000, -12.000000) ">
|
||||||
|
<g id="02_7-Chat-new-messages">
|
||||||
|
<g id="icon_newmessages">
|
||||||
|
<circle id="Oval-1909" fill-opacity="0.5" fill="#454545" fill-rule="nonzero" cx="12" cy="12" r="12"></circle>
|
||||||
|
<circle id="Oval" stroke="#FFFFFF" cx="12" cy="12" r="7"></circle>
|
||||||
|
<circle id="Oval" stroke="#FFFFFF" cx="12" cy="12" r="4"></circle>
|
||||||
|
<circle id="Oval" fill="#FFFFFF" cx="12" cy="12" r="1"></circle>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -37,8 +37,19 @@
|
||||||
<body style="height: 100%;">
|
<body style="height: 100%;">
|
||||||
<section id="matrixchat" style="height: 100%;"></section>
|
<section id="matrixchat" style="height: 100%;"></section>
|
||||||
<noscript>Sorry, Riot requires JavaScript to be enabled.</noscript>
|
<noscript>Sorry, Riot requires JavaScript to be enabled.</noscript>
|
||||||
<% for (var i=0; i < htmlWebpackPlugin.files.js.length; i++) {%>
|
<% for (var i=0; i < htmlWebpackPlugin.files.js.length; i++) {
|
||||||
<script src="<%= htmlWebpackPlugin.files.js[i] %>"></script>
|
// Not a particularly graceful way of not putting the indexeddb worker script
|
||||||
|
// into the main page
|
||||||
|
if (_.endsWith(htmlWebpackPlugin.files.js[i], 'indexeddb-worker.js')) {
|
||||||
|
%>
|
||||||
|
<script>
|
||||||
|
window.vector_indexeddb_worker_script = '<%= htmlWebpackPlugin.files.js[i] %>';
|
||||||
|
</script>
|
||||||
|
<%
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
%>
|
||||||
|
<script src="<%= htmlWebpackPlugin.files.js[i] %>"></script>
|
||||||
<% } %>
|
<% } %>
|
||||||
<img src="img/warning.svg" width="24" height="23" style="visibility: hidden; position: absolute; top: 0px; left: 0px;"/>
|
<img src="img/warning.svg" width="24" height="23" style="visibility: hidden; position: absolute; top: 0px; left: 0px;"/>
|
||||||
<audio id="messageAudio">
|
<audio id="messageAudio">
|
||||||
|
|
|
@ -68,11 +68,15 @@ import url from 'url';
|
||||||
import {parseQs, parseQsFromFragment} from './url_utils';
|
import {parseQs, parseQsFromFragment} from './url_utils';
|
||||||
import Platform from './platform';
|
import Platform from './platform';
|
||||||
|
|
||||||
|
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
||||||
|
|
||||||
var lastLocationHashSet = null;
|
var lastLocationHashSet = null;
|
||||||
|
|
||||||
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
|
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
|
||||||
CallHandler.setConferenceHandler(VectorConferenceHandler);
|
CallHandler.setConferenceHandler(VectorConferenceHandler);
|
||||||
|
|
||||||
|
MatrixClientPeg.setIndexedDbWorkerScript(window.vector_indexeddb_worker_script);
|
||||||
|
|
||||||
function checkBrowserFeatures(featureList) {
|
function checkBrowserFeatures(featureList) {
|
||||||
if (!window.Modernizr) {
|
if (!window.Modernizr) {
|
||||||
console.error("Cannot check features - Modernizr global is missing.");
|
console.error("Cannot check features - Modernizr global is missing.");
|
||||||
|
@ -255,11 +259,15 @@ async function loadApp() {
|
||||||
let configError;
|
let configError;
|
||||||
try {
|
try {
|
||||||
configJson = await getConfig();
|
configJson = await getConfig();
|
||||||
rageshake.setBugReportEndpoint(configJson.bug_report_endpoint_url);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
configError = e;
|
configError = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser')) {
|
||||||
|
console.log('User has previously accepted risks in using an unsupported browser');
|
||||||
|
validBrowser = true;
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Vector starting at "+window.location);
|
console.log("Vector starting at "+window.location);
|
||||||
if (configError) {
|
if (configError) {
|
||||||
window.matrixChat = ReactDOM.render(<div className="error">
|
window.matrixChat = ReactDOM.render(<div className="error">
|
||||||
|
@ -291,6 +299,7 @@ async function loadApp() {
|
||||||
var CompatibilityPage = sdk.getComponent("structures.CompatibilityPage");
|
var CompatibilityPage = sdk.getComponent("structures.CompatibilityPage");
|
||||||
window.matrixChat = ReactDOM.render(
|
window.matrixChat = ReactDOM.render(
|
||||||
<CompatibilityPage onAccept={function() {
|
<CompatibilityPage onAccept={function() {
|
||||||
|
if (window.localStorage) window.localStorage.setItem('mx_accepts_unsupported_browser', true);
|
||||||
validBrowser = true;
|
validBrowser = true;
|
||||||
console.log("User accepts the compatibility risks.");
|
console.log("User accepts the compatibility risks.");
|
||||||
loadApp();
|
loadApp();
|
||||||
|
|
21
src/vector/indexedbd-worker.js
Normal file
21
src/vector/indexedbd-worker.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 Vector Creations 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 {IndexedDBStoreWorker} from 'matrix-js-sdk/lib/indexeddb-worker.js';
|
||||||
|
|
||||||
|
const remoteWorker = new IndexedDBStoreWorker(postMessage);
|
||||||
|
|
||||||
|
onmessage = remoteWorker.onMessage;
|
|
@ -24,12 +24,12 @@ import q from 'q';
|
||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
const remote = electron.remote;
|
const remote = electron.remote;
|
||||||
|
|
||||||
electron.remote.autoUpdater.on('update-downloaded', onUpdateDownloaded);
|
remote.autoUpdater.on('update-downloaded', onUpdateDownloaded);
|
||||||
|
|
||||||
function onUpdateDownloaded(ev, releaseNotes, ver, date, updateURL) {
|
function onUpdateDownloaded(ev, releaseNotes, ver, date, updateURL) {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'new_version',
|
action: 'new_version',
|
||||||
currentVersion: electron.remote.app.getVersion(),
|
currentVersion: remote.app.getVersion(),
|
||||||
newVersion: ver,
|
newVersion: ver,
|
||||||
releaseNotes: releaseNotes,
|
releaseNotes: releaseNotes,
|
||||||
});
|
});
|
||||||
|
@ -68,7 +68,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||||
try {
|
try {
|
||||||
remote.app.setBadgeCount(count);
|
remote.app.setBadgeCount(count);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to set notification count", e);
|
console.error('Failed to set notification count', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,13 +81,24 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
displayNotification(title: string, msg: string, avatarUrl: string, room: Object): Notification {
|
displayNotification(title: string, msg: string, avatarUrl: string, room: Object): Notification {
|
||||||
|
|
||||||
|
// GNOME notification spec parses HTML tags for styling...
|
||||||
|
// Electron Docs state all supported linux notification systems follow this markup spec
|
||||||
|
// https://github.com/electron/electron/blob/master/docs/tutorial/desktop-environment-integration.md#linux
|
||||||
|
// maybe we should pass basic styling (italics, bold, underline) through from MD
|
||||||
|
// we only have to strip out < and > as the spec doesn't include anything about things like &
|
||||||
|
// so we shouldn't assume that all implementations will treat those properly. Very basic tag parsing is done.
|
||||||
|
if (window.process.platform === 'linux') {
|
||||||
|
msg = msg.replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
// Notifications in Electron use the HTML5 notification API
|
// Notifications in Electron use the HTML5 notification API
|
||||||
const notification = new global.Notification(
|
const notification = new global.Notification(
|
||||||
title,
|
title,
|
||||||
{
|
{
|
||||||
body: msg,
|
body: msg,
|
||||||
icon: avatarUrl,
|
icon: avatarUrl,
|
||||||
tag: "vector",
|
tag: 'vector',
|
||||||
silent: true, // we play our own sounds
|
silent: true, // we play our own sounds
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -95,13 +106,14 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||||
notification.onclick = function() {
|
notification.onclick = function() {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: room.roomId
|
room_id: room.roomId,
|
||||||
});
|
});
|
||||||
global.focus();
|
global.focus();
|
||||||
const currentWin = electron.remote.getCurrentWindow();
|
const win = remote.getCurrentWindow();
|
||||||
currentWin.show();
|
|
||||||
currentWin.restore();
|
if (win.isMinimized()) win.restore();
|
||||||
currentWin.focus();
|
else if (!win.isVisible()) win.show();
|
||||||
|
else win.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
return notification;
|
return notification;
|
||||||
|
@ -112,7 +124,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAppVersion() {
|
getAppVersion() {
|
||||||
return q(electron.remote.app.getVersion());
|
return q(remote.app.getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
pollForUpdate() {
|
pollForUpdate() {
|
||||||
|
@ -129,7 +141,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultDeviceDisplayName() {
|
getDefaultDeviceDisplayName() {
|
||||||
return "Riot Desktop on " + platformFriendlyName();
|
return 'Riot Desktop on ' + platformFriendlyName();
|
||||||
}
|
}
|
||||||
|
|
||||||
screenCaptureErrorString() {
|
screenCaptureErrorString() {
|
||||||
|
@ -139,4 +151,8 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||||
requestNotificationPermission() : Promise {
|
requestNotificationPermission() : Promise {
|
||||||
return q('granted');
|
return q('granted');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reload() {
|
||||||
|
remote.getCurrentWebContents().reload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,4 +206,10 @@ export default class WebPlatform extends VectorBasePlatform {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reload() {
|
||||||
|
// forceReload=false since we don't really need new HTML/JS files
|
||||||
|
// we just need to restart the JS runtime.
|
||||||
|
window.location.reload(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
|
|
||||||
import request from "browser-request";
|
|
||||||
import q from "q";
|
import q from "q";
|
||||||
|
|
||||||
// This module contains all the code needed to log the console, persist it to
|
// This module contains all the code needed to log the console, persist it to
|
||||||
|
@ -205,9 +203,6 @@ class IndexedDBLogStore {
|
||||||
}
|
}
|
||||||
let txn = this.db.transaction(["logs", "logslastmod"], "readwrite");
|
let txn = this.db.transaction(["logs", "logslastmod"], "readwrite");
|
||||||
let objStore = txn.objectStore("logs");
|
let objStore = txn.objectStore("logs");
|
||||||
objStore.add(this._generateLogEntry(lines));
|
|
||||||
let lastModStore = txn.objectStore("logslastmod");
|
|
||||||
lastModStore.put(this._generateLastModifiedTime());
|
|
||||||
txn.oncomplete = (event) => {
|
txn.oncomplete = (event) => {
|
||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
|
@ -219,6 +214,9 @@ class IndexedDBLogStore {
|
||||||
new Error("Failed to write logs: " + event.target.errorCode)
|
new Error("Failed to write logs: " + event.target.errorCode)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
objStore.add(this._generateLogEntry(lines));
|
||||||
|
let lastModStore = txn.objectStore("logslastmod");
|
||||||
|
lastModStore.put(this._generateLastModifiedTime());
|
||||||
});
|
});
|
||||||
return this.flushPromise;
|
return this.flushPromise;
|
||||||
}
|
}
|
||||||
|
@ -396,7 +394,6 @@ function selectQuery(store, keyRange, resultMapper) {
|
||||||
let store = null;
|
let store = null;
|
||||||
let logger = null;
|
let logger = null;
|
||||||
let initPromise = null;
|
let initPromise = null;
|
||||||
let bugReportEndpoint = null;
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -430,80 +427,29 @@ module.exports = {
|
||||||
await store.consume();
|
await store.consume();
|
||||||
},
|
},
|
||||||
|
|
||||||
setBugReportEndpoint: function(url) {
|
|
||||||
bugReportEndpoint = url;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a bug report.
|
* Get a recent snapshot of the logs, ready for attaching to a bug report
|
||||||
* @param {string} userText Any additional user input.
|
*
|
||||||
* @param {boolean} sendLogs True to send logs
|
* @return {Array<{lines: string, id, string}>} list of log data
|
||||||
* @return {Promise} Resolved when the bug report is sent.
|
|
||||||
*/
|
*/
|
||||||
sendBugReport: async function(userText, sendLogs) {
|
getLogsForReport: async function() {
|
||||||
if (!logger) {
|
if (!logger) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"No console logger, did you forget to call init()?"
|
"No console logger, did you forget to call init()?"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!bugReportEndpoint) {
|
|
||||||
throw new Error("No bug report endpoint has been set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
let version = "UNKNOWN";
|
|
||||||
try {
|
|
||||||
version = await PlatformPeg.get().getAppVersion();
|
|
||||||
}
|
|
||||||
catch (err) {} // PlatformPeg already logs this.
|
|
||||||
|
|
||||||
let userAgent = "UNKNOWN";
|
|
||||||
if (window.navigator && window.navigator.userAgent) {
|
|
||||||
userAgent = window.navigator.userAgent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If in incognito mode, store is null, but we still want bug report
|
// If in incognito mode, store is null, but we still want bug report
|
||||||
// sending to work going off the in-memory console logs.
|
// sending to work going off the in-memory console logs.
|
||||||
console.log("Sending bug report.");
|
if (store) {
|
||||||
let logs = [];
|
// flush most recent logs
|
||||||
if (sendLogs) {
|
await store.flush();
|
||||||
if (store) {
|
return await store.consume();
|
||||||
// flush most recent logs
|
|
||||||
await store.flush();
|
|
||||||
logs = await store.consume();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logs.push({
|
|
||||||
lines: logger.flush(true),
|
|
||||||
id: "-",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
await q.Promise((resolve, reject) => {
|
return [{
|
||||||
request({
|
lines: logger.flush(true),
|
||||||
method: "POST",
|
id: "-",
|
||||||
url: bugReportEndpoint,
|
}];
|
||||||
body: {
|
}
|
||||||
logs: logs,
|
},
|
||||||
text: (
|
|
||||||
userText || "User did not supply any additional text."
|
|
||||||
),
|
|
||||||
version: version,
|
|
||||||
user_agent: userAgent,
|
|
||||||
},
|
|
||||||
json: true,
|
|
||||||
timeout: 5 * 60 * 1000,
|
|
||||||
}, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (res.status < 200 || res.status >= 400) {
|
|
||||||
reject(new Error(`HTTP ${res.status}`));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
124
src/vector/submit-rageshake.js
Normal file
124
src/vector/submit-rageshake.js
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 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 pako from 'pako';
|
||||||
|
import q from "q";
|
||||||
|
|
||||||
|
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
||||||
|
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
|
||||||
|
|
||||||
|
import rageshake from './rageshake'
|
||||||
|
|
||||||
|
|
||||||
|
// polyfill textencoder if necessary
|
||||||
|
import * as TextEncodingUtf8 from 'text-encoding-utf-8';
|
||||||
|
let TextEncoder = window.TextEncoder;
|
||||||
|
if (!TextEncoder) {
|
||||||
|
TextEncoder = TextEncodingUtf8.TextEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a bug report.
|
||||||
|
*
|
||||||
|
* @param {string} bugReportEndpoint HTTP url to send the report to
|
||||||
|
*
|
||||||
|
* @param {object} opts optional dictionary of options
|
||||||
|
*
|
||||||
|
* @param {string} opts.userText Any additional user input.
|
||||||
|
*
|
||||||
|
* @param {boolean} opts.sendLogs True to send logs
|
||||||
|
*
|
||||||
|
* @param {function(string)} opts.progressCallback Callback to call with progress updates
|
||||||
|
*
|
||||||
|
* @return {Promise} Resolved when the bug report is sent.
|
||||||
|
*/
|
||||||
|
export default async function sendBugReport(bugReportEndpoint, opts) {
|
||||||
|
if (!bugReportEndpoint) {
|
||||||
|
throw new Error("No bug report endpoint has been set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = opts || {};
|
||||||
|
const progressCallback = opts.progressCallback || (() => {});
|
||||||
|
|
||||||
|
progressCallback("Collecting app version information");
|
||||||
|
let version = "UNKNOWN";
|
||||||
|
try {
|
||||||
|
version = await PlatformPeg.get().getAppVersion();
|
||||||
|
}
|
||||||
|
catch (err) {} // PlatformPeg already logs this.
|
||||||
|
|
||||||
|
let userAgent = "UNKNOWN";
|
||||||
|
if (window.navigator && window.navigator.userAgent) {
|
||||||
|
userAgent = window.navigator.userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
|
console.log("Sending bug report.");
|
||||||
|
|
||||||
|
const body = new FormData();
|
||||||
|
body.append('text', opts.userText || "User did not supply any additional text.");
|
||||||
|
body.append('app', 'riot-web');
|
||||||
|
body.append('version', version);
|
||||||
|
body.append('user_agent', userAgent);
|
||||||
|
|
||||||
|
if (client) {
|
||||||
|
body.append('user_id', client.credentials.userId);
|
||||||
|
body.append('device_id', client.deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.sendLogs) {
|
||||||
|
progressCallback("Collecting logs");
|
||||||
|
const logs = await rageshake.getLogsForReport();
|
||||||
|
for (let entry of logs) {
|
||||||
|
// encode as UTF-8
|
||||||
|
const buf = new TextEncoder().encode(entry.lines);
|
||||||
|
|
||||||
|
// compress
|
||||||
|
const compressed = pako.gzip(buf);
|
||||||
|
|
||||||
|
body.append('compressed-log', new Blob([compressed]), entry.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progressCallback("Uploading report");
|
||||||
|
await _submitReport(bugReportEndpoint, body, progressCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _submitReport(endpoint, body, progressCallback) {
|
||||||
|
const deferred = q.defer();
|
||||||
|
|
||||||
|
const req = new XMLHttpRequest();
|
||||||
|
req.open("POST", endpoint);
|
||||||
|
req.timeout = 5 * 60 * 1000;
|
||||||
|
req.onreadystatechange = function() {
|
||||||
|
if (req.readyState === XMLHttpRequest.LOADING) {
|
||||||
|
progressCallback("Waiting for response from server");
|
||||||
|
} else if (req.readyState === XMLHttpRequest.DONE) {
|
||||||
|
on_done();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
req.send(body);
|
||||||
|
return deferred.promise;
|
||||||
|
|
||||||
|
function on_done() {
|
||||||
|
if (req.status < 200 || req.status >= 400) {
|
||||||
|
deferred.reject(new Error(`HTTP ${req.status}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,14 +72,13 @@ describe('joining a room', function () {
|
||||||
var ROOM_ALIAS = '#alias:localhost';
|
var ROOM_ALIAS = '#alias:localhost';
|
||||||
var ROOM_ID = '!id:localhost';
|
var ROOM_ID = '!id:localhost';
|
||||||
|
|
||||||
httpBackend.when('PUT', '/presence/'+encodeURIComponent(USER_ID)+'/status')
|
|
||||||
.respond(200, {});
|
|
||||||
httpBackend.when('GET', '/pushrules').respond(200, {});
|
httpBackend.when('GET', '/pushrules').respond(200, {});
|
||||||
httpBackend.when('POST', '/filter').respond(200, { filter_id: 'fid' });
|
httpBackend.when('POST', '/filter').respond(200, { filter_id: 'fid' });
|
||||||
httpBackend.when('GET', '/sync').respond(200, {});
|
httpBackend.when('GET', '/sync').respond(200, {});
|
||||||
httpBackend.when('POST', '/publicRooms').respond(200, {chunk: []});
|
|
||||||
httpBackend.when('GET', '/thirdparty/protocols').respond(200, {});
|
// note that we deliberately do *not* set an expectation for a
|
||||||
httpBackend.when('GET', '/directory/room/'+encodeURIComponent(ROOM_ALIAS)).respond(200, { room_id: ROOM_ID });
|
// presence update - setting one makes the first httpBackend.flush
|
||||||
|
// return before the first /sync arrives.
|
||||||
|
|
||||||
// start with a logged-in client
|
// start with a logged-in client
|
||||||
localStorage.setItem("mx_hs_url", HS_URL );
|
localStorage.setItem("mx_hs_url", HS_URL );
|
||||||
|
@ -94,9 +93,18 @@ describe('joining a room', function () {
|
||||||
matrixChat._setPage(PageTypes.RoomDirectory);
|
matrixChat._setPage(PageTypes.RoomDirectory);
|
||||||
|
|
||||||
var roomView;
|
var roomView;
|
||||||
|
|
||||||
// wait for /sync to happen
|
// wait for /sync to happen
|
||||||
return q.delay(1).then(() => {
|
return q.delay(1).then(() => {
|
||||||
return httpBackend.flush();
|
return httpBackend.flush();
|
||||||
|
}).then(() => {
|
||||||
|
// wait for the directory requests
|
||||||
|
httpBackend.when('POST', '/publicRooms').respond(200, {chunk: []});
|
||||||
|
httpBackend.when('GET', '/thirdparty/protocols').respond(200, {});
|
||||||
|
return q.all([
|
||||||
|
httpBackend.flush('/publicRooms'),
|
||||||
|
httpBackend.flush('/thirdparty/protocols'),
|
||||||
|
]);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
var roomDir = ReactTestUtils.findRenderedComponentWithType(
|
var roomDir = ReactTestUtils.findRenderedComponentWithType(
|
||||||
matrixChat, RoomDirectory);
|
matrixChat, RoomDirectory);
|
||||||
|
@ -110,6 +118,7 @@ describe('joining a room', function () {
|
||||||
|
|
||||||
// that should create a roomview which will start a peek; wait
|
// that should create a roomview which will start a peek; wait
|
||||||
// for the peek.
|
// for the peek.
|
||||||
|
httpBackend.when('GET', '/directory/room/'+encodeURIComponent(ROOM_ALIAS)).respond(200, { room_id: ROOM_ID });
|
||||||
httpBackend.when('GET', '/rooms/'+encodeURIComponent(ROOM_ID)+"/initialSync")
|
httpBackend.when('GET', '/rooms/'+encodeURIComponent(ROOM_ID)+"/initialSync")
|
||||||
.respond(401, {errcode: 'M_GUEST_ACCESS_FORBIDDEN'});
|
.respond(401, {errcode: 'M_GUEST_ACCESS_FORBIDDEN'});
|
||||||
return httpBackend.flush();
|
return httpBackend.flush();
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
var webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
var ExtractTextPlugin = require("extract-text-webpack-plugin");
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
"bundle": "./src/vector/index.js",
|
"bundle": "./src/vector/index.js",
|
||||||
|
"indexeddb-worker": "./src/vector/indexedbd-worker.js",
|
||||||
|
|
||||||
// We ship olm.js as a separate lump of javascript. This makes it get
|
// We ship olm.js as a separate lump of javascript. This makes it get
|
||||||
// loaded via a separate <script/> tag in index.html (which loads it
|
// loaded via a separate <script/> tag in index.html (which loads it
|
||||||
|
@ -18,11 +19,11 @@ module.exports = {
|
||||||
|
|
||||||
// CSS themes
|
// CSS themes
|
||||||
"theme-light": "./src/skins/vector/css/themes/light.scss",
|
"theme-light": "./src/skins/vector/css/themes/light.scss",
|
||||||
"theme-dark": "./src/skins/vector/css/themes/dark.scss"
|
"theme-dark": "./src/skins/vector/css/themes/dark.scss",
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
preLoaders: [
|
preLoaders: [
|
||||||
{ test: /\.js$/, loader: "source-map-loader" }
|
{ test: /\.js$/, loader: "source-map-loader" },
|
||||||
],
|
],
|
||||||
loaders: [
|
loaders: [
|
||||||
{ test: /\.json$/, loader: "json" },
|
{ test: /\.json$/, loader: "json" },
|
||||||
|
@ -37,9 +38,7 @@ module.exports = {
|
||||||
// would also drag in the imgs and fonts that our CSS refers to
|
// would also drag in the imgs and fonts that our CSS refers to
|
||||||
// as webpack inputs.)
|
// as webpack inputs.)
|
||||||
// 3. ExtractTextPlugin turns that string into a separate asset.
|
// 3. ExtractTextPlugin turns that string into a separate asset.
|
||||||
loader: ExtractTextPlugin.extract(
|
loader: ExtractTextPlugin.extract("css-raw-loader!postcss-loader?config=postcss.config.js"),
|
||||||
"css-raw-loader!postcss-loader?config=postcss.config.js"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// this works similarly to the scss case, without postcss.
|
// this works similarly to the scss case, without postcss.
|
||||||
|
@ -48,15 +47,18 @@ module.exports = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
noParse: [
|
noParse: [
|
||||||
|
// for cross platform compatibility use [\\\/] as the path separator
|
||||||
|
// this ensures that the regex trips on both Windows and *nix
|
||||||
|
|
||||||
// don't parse the languages within highlight.js. They cause stack
|
// don't parse the languages within highlight.js. They cause stack
|
||||||
// overflows (https://github.com/webpack/webpack/issues/1721), and
|
// overflows (https://github.com/webpack/webpack/issues/1721), and
|
||||||
// there is no need for webpack to parse them - they can just be
|
// there is no need for webpack to parse them - they can just be
|
||||||
// included as-is.
|
// included as-is.
|
||||||
/highlight\.js\/lib\/languages/,
|
/highlight\.js[\\\/]lib[\\\/]languages/,
|
||||||
|
|
||||||
// olm takes ages for webpack to process, and it's already heavily
|
// olm takes ages for webpack to process, and it's already heavily
|
||||||
// optimised, so there is little to gain by us uglifying it.
|
// optimised, so there is little to gain by us uglifying it.
|
||||||
/olm\/(javascript\/)?olm\.js$/,
|
/olm[\\\/](javascript[\\\/])?olm\.js$/,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
|
@ -82,7 +84,7 @@ module.exports = {
|
||||||
// various levels of '.' and '..'
|
// various levels of '.' and '..'
|
||||||
// Also, sometimes the resource path is absolute.
|
// Also, sometimes the resource path is absolute.
|
||||||
return path.relative(process.cwd(), info.resourcePath).replace(/^[\/\.]*/, '');
|
return path.relative(process.cwd(), info.resourcePath).replace(/^[\/\.]*/, '');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
@ -105,16 +107,13 @@ module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': {
|
'process.env': {
|
||||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
|
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new ExtractTextPlugin(
|
new ExtractTextPlugin("bundles/[hash]/[name].css", {
|
||||||
"bundles/[hash]/[name].css",
|
allChunks: true,
|
||||||
{
|
}),
|
||||||
allChunks: true
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: './src/vector/index.html',
|
template: './src/vector/index.html',
|
||||||
|
|
Loading…
Reference in a new issue