diff --git a/.gitignore b/.gitignore index 86baa127..cba50a69 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ npm-debug.log electron/dist electron/pub +/config.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 659a3742..a2ed3149 100644 --- a/CHANGELOG.md +++ b/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) ========================================================================================== [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.7-rc.3...v0.9.7) diff --git a/electron/package.json b/electron/package.json index 0fff99f5..69ea9a28 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,7 +1,7 @@ { "name": "riot-web", "main": "src/electron-main.js", - "version": "0.0.0", + "version": "0.9.8", "description": "A feature-rich client for Matrix.org", "author": "Vector Creations Ltd.", "dependencies": { diff --git a/electron/src/electron-main.js b/electron/src/electron-main.js index 8dd5e813..32e305d8 100644 --- a/electron/src/electron-main.js +++ b/electron/src/electron-main.js @@ -173,6 +173,7 @@ const shouldQuit = electron.app.makeSingleInstance((commandLine, workingDirector }); if (shouldQuit) { + console.log("Other instance detected: exiting"); electron.app.quit() } @@ -213,9 +214,12 @@ electron.app.on('ready', () => { brand: vectorConfig.brand || 'Riot' }); - mainWindow.once('ready-to-show', () => { - mainWindow.show(); - }); + if (!process.argv.includes('--hidden')) { + mainWindow.once('ready-to-show', () => { + mainWindow.show(); + }); + } + mainWindow.on('closed', () => { mainWindow = null; }); diff --git a/package.json b/package.json index 548c95d2..d0161610 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "riot-web", "productName": "Riot", "main": "electron/src/electron-main.js", - "version": "0.9.7", + "version": "0.9.8", "description": "A feature-rich client for Matrix.org", "author": "Vector Creations Ltd.", "repository": { @@ -30,18 +30,18 @@ "build:res": "node scripts/copy-res.js", "build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js", "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: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:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle:dev", + "build": "npm run build:res && npm run build:bundle", + "build:dev": "npm run build:res && npm run build:bundle:dev", "dist": "scripts/package.sh", "install:electron": "install-app-deps", "electron": "npm run install:electron && electron .", "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:prod": "NODE_ENV=production webpack-dev-server -w --progress", - "start": "node scripts/babelcheck.js && parallelshell \"npm run start:res\" \"npm run start:js\"", + "start:js:prod": "cross-env NODE_ENV=production webpack-dev-server -w --progress", + "start": "parallelshell \"npm run start:res\" \"npm run start:js\"", "start:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\"", "lint": "eslint src/", "lintall": "eslint src/ test/", @@ -58,21 +58,21 @@ "draft-js": "^0.8.1", "extract-text-webpack-plugin": "^0.9.1", "favico.js": "^0.3.10", - "filesize": "^3.1.2", + "filesize": "3.5.6", "flux": "~2.0.3", - "gemini-scrollbar": "matrix-org/gemini-scrollbar#b302279", "gfm.css": "^1.1.1", "highlight.js": "^9.0.0", "linkifyjs": "^2.1.3", "matrix-js-sdk": "matrix-org/matrix-js-sdk#develop", "matrix-react-sdk": "matrix-org/matrix-react-sdk#develop", "modernizr": "^3.1.0", + "pako": "^1.0.5", "q": "^1.4.1", "react": "^15.4.0", "react-dnd": "^2.1.4", "react-dnd-html5-backend": "^2.1.2", "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", "ua-parser-js": "^0.7.10", "url": "^0.11.0" @@ -95,6 +95,7 @@ "babel-preset-stage-2": "^6.17.0", "chokidar": "^1.6.1", "cpx": "^1.3.2", + "cross-env": "^4.0.0", "css-raw-loader": "^0.1.1", "electron-builder": "^11.2.4", "electron-builder-squirrel-windows": "^11.2.1", @@ -140,7 +141,7 @@ "build": { "appId": "im.riot.app", "category": "Network", - "electronVersion": "1.4.14", + "electronVersion": "1.6.2", "//asar=false": "https://github.com/electron-userland/electron-builder/issues/675", "asar": false, "dereference": true, diff --git a/scripts/babelcheck.js b/scripts/babelcheck.js deleted file mode 100644 index 89f5cac5..00000000 --- a/scripts/babelcheck.js +++ /dev/null @@ -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); - } -}); diff --git a/scripts/copy-res.js b/scripts/copy-res.js index 826d9a96..4702d5cf 100755 --- a/scripts/copy-res.js +++ b/scripts/copy-res.js @@ -10,6 +10,7 @@ const COPY_LIST = [ ["res/{media,vector-icons}/**", "webapp"], ["src/skins/vector/{fonts,img}/**", "webapp"], ["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"], + ["node_modules/emojione/assets/png/*", "webapp/emojione/png/"], ["./config.json", "webapp", {directwatch: 1}], ]; diff --git a/scripts/rageshake.go b/scripts/rageshake.go deleted file mode 100644 index a150eab7..00000000 --- a/scripts/rageshake.go +++ /dev/null @@ -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)) -} diff --git a/src/component-index.js b/src/component-index.js index 2b67aa15..4bf0b0f9 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -40,6 +40,8 @@ import structures$RoomDirectory from './components/structures/RoomDirectory'; structures$RoomDirectory && (module.exports.components['structures.RoomDirectory'] = structures$RoomDirectory); import structures$RoomSubList from './components/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'; structures$SearchBox && (module.exports.components['structures.SearchBox'] = structures$SearchBox); import structures$ViewSource from './components/structures/ViewSource'; diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index a9df37a8..2d97313a 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -19,9 +19,11 @@ limitations under the License. var React = require('react'); var DragDropContext = require('react-dnd').DragDropContext; var HTML5Backend = require('react-dnd-html5-backend'); +var KeyCode = require('matrix-react-sdk/lib/KeyCode'); var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); + var VectorConferenceHandler = require('../../VectorConferenceHandler'); var CallHandler = require("matrix-react-sdk/lib/CallHandler"); @@ -40,6 +42,10 @@ var LeftPanel = React.createClass({ }; }, + componentWillMount: function() { + this.focusedElement = null; + }, + componentDidMount: function() { 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) { // 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 @@ -120,7 +211,8 @@ var LeftPanel = React.createClass({ } return ( -