Compare commits
14 Commits
dbkr/left_
...
v0.9.9-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5326faa0b8 | ||
|
|
7f2fa09d4c | ||
|
|
b6435502fc | ||
|
|
1701ea43a4 | ||
|
|
141aafd18e | ||
|
|
8aed52ece9 | ||
|
|
ce5a7ba48a | ||
|
|
95647fb7a1 | ||
|
|
d0c0eeac0a | ||
|
|
f25612198e | ||
|
|
ca6d9063fd | ||
|
|
eec0c274d2 | ||
|
|
b5a5b472c4 | ||
|
|
9747836a4d |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,4 +12,3 @@
|
||||
npm-debug.log
|
||||
electron/dist
|
||||
electron/pub
|
||||
/config.json
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,3 +1,17 @@
|
||||
Changes in [0.9.9-rc.2](https://github.com/vector-im/riot-web/releases/tag/v0.9.9-rc.2) (2017-04-24)
|
||||
====================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.9-rc.1...v0.9.9-rc.2)
|
||||
|
||||
* Fix bug where links to Riot would fail to open.
|
||||
|
||||
|
||||
Changes in [0.9.9-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.9-rc.1) (2017-04-21)
|
||||
====================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.8...v0.9.9-rc.1)
|
||||
|
||||
* Update js-sdk and matrix-react-sdk to fix registration without a captcha (https://github.com/vector-im/riot-web/issues/3621)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@@ -171,7 +171,6 @@ const shouldQuit = electron.app.makeSingleInstance((commandLine, workingDirector
|
||||
});
|
||||
|
||||
if (shouldQuit) {
|
||||
console.log("Other instance detected: exiting");
|
||||
electron.app.quit()
|
||||
}
|
||||
|
||||
@@ -202,12 +201,9 @@ electron.app.on('ready', () => {
|
||||
brand: vectorConfig.brand || 'Riot'
|
||||
});
|
||||
|
||||
if (!process.argv.includes('--hidden')) {
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
}
|
||||
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
15
package.json
15
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "riot-web",
|
||||
"productName": "Riot",
|
||||
"main": "electron/src/electron-main.js",
|
||||
"version": "0.9.8",
|
||||
"version": "0.9.9-rc.2",
|
||||
"description": "A feature-rich client for Matrix.org",
|
||||
"author": "Vector Creations Ltd.",
|
||||
"repository": {
|
||||
@@ -30,7 +30,7 @@
|
||||
"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": "cross-env NODE_ENV=production webpack -p --progress",
|
||||
"build:bundle": "NODE_ENV=production webpack -p --progress",
|
||||
"build:bundle:dev": "webpack --optimize-occurence-order --progress",
|
||||
"build:electron": "npm run clean && npm run build && build -wml --ia32 --x64",
|
||||
"build": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle",
|
||||
@@ -38,7 +38,7 @@
|
||||
"dist": "scripts/package.sh",
|
||||
"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": "cross-env NODE_ENV=production webpack-dev-server -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:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\"",
|
||||
"lint": "eslint src/",
|
||||
@@ -58,19 +58,19 @@
|
||||
"favico.js": "^0.3.10",
|
||||
"filesize": "^3.1.2",
|
||||
"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",
|
||||
"matrix-js-sdk": "0.7.7-rc.1",
|
||||
"matrix-react-sdk": "0.8.8-rc.2",
|
||||
"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#39d858c",
|
||||
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
|
||||
"sanitize-html": "^1.11.1",
|
||||
"ua-parser-js": "^0.7.10",
|
||||
"url": "^0.11.0"
|
||||
@@ -93,7 +93,6 @@
|
||||
"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",
|
||||
|
||||
@@ -10,7 +10,6 @@ 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}],
|
||||
];
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@ 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';
|
||||
|
||||
@@ -14,15 +14,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import sdk from 'matrix-react-sdk';
|
||||
import dis from 'matrix-react-sdk/lib/dispatcher';
|
||||
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
|
||||
import Velocity from 'velocity-vector';
|
||||
import 'velocity-vector/velocity.ui';
|
||||
'use strict';
|
||||
|
||||
const CALLOUT_ANIM_DURATION = 1000;
|
||||
var React = require('react');
|
||||
var ReactDOM = require('react-dom');
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'BottomLeftMenu',
|
||||
@@ -42,18 +40,6 @@ module.exports = React.createClass({
|
||||
});
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this._dispatcherRef = dis.register(this.onAction);
|
||||
this._peopleButton = null;
|
||||
this._directoryButton = null;
|
||||
this._createRoomButton = null;
|
||||
this._lastCallouts = {};
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
dis.unregister(this._dispatcherRef);
|
||||
},
|
||||
|
||||
// Room events
|
||||
onDirectoryClick: function() {
|
||||
dis.dispatch({ action: 'view_room_directory' });
|
||||
@@ -118,30 +104,6 @@ module.exports = React.createClass({
|
||||
this.setState({ settingsHover: false });
|
||||
},
|
||||
|
||||
onAction: function(payload) {
|
||||
let calloutElement;
|
||||
switch (payload.action) {
|
||||
// Incoming instruction: dance!
|
||||
case 'callout_start_chat':
|
||||
calloutElement = this._peopleButton;
|
||||
break;
|
||||
case 'callout_room_directory':
|
||||
calloutElement = this._directoryButton;
|
||||
break;
|
||||
case 'callout_create_room':
|
||||
calloutElement = this._createRoomButton;
|
||||
break;
|
||||
}
|
||||
if (calloutElement) {
|
||||
const lastCallout = this._lastCallouts[payload.action];
|
||||
const now = Date.now();
|
||||
if (lastCallout == undefined || lastCallout < now - CALLOUT_ANIM_DURATION) {
|
||||
this._lastCallouts[payload.action] = now;
|
||||
Velocity(ReactDOM.findDOMNode(calloutElement), "callout.bounce", CALLOUT_ANIM_DURATION);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Get the label/tooltip to show
|
||||
getLabel: function(label, show) {
|
||||
if (show) {
|
||||
@@ -150,18 +112,6 @@ module.exports = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
_collectPeopleButton: function(e) {
|
||||
this._peopleButton = e;
|
||||
},
|
||||
|
||||
_collectDirectoryButton: function(e) {
|
||||
this._directoryButton = e;
|
||||
},
|
||||
|
||||
_collectCreateRoomButton: function(e) {
|
||||
this._createRoomButton = e;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var TintableSvg = sdk.getComponent('elements.TintableSvg');
|
||||
|
||||
@@ -180,15 +130,15 @@ module.exports = React.createClass({
|
||||
<div className="mx_BottomLeftMenu_options">
|
||||
{ homeButton }
|
||||
<AccessibleButton className="mx_BottomLeftMenu_people" onClick={ this.onPeopleClick } onMouseEnter={ this.onPeopleMouseEnter } onMouseLeave={ this.onPeopleMouseLeave } >
|
||||
<TintableSvg ref={this._collectPeopleButton} src="img/icons-people.svg" width="25" height="25" />
|
||||
<TintableSvg src="img/icons-people.svg" width="25" height="25" />
|
||||
{ this.getLabel("Start chat", this.state.peopleHover) }
|
||||
</AccessibleButton>
|
||||
<AccessibleButton className="mx_BottomLeftMenu_directory" onClick={ this.onDirectoryClick } onMouseEnter={ this.onDirectoryMouseEnter } onMouseLeave={ this.onDirectoryMouseLeave } >
|
||||
<TintableSvg ref={this._collectDirectoryButton} src="img/icons-directory.svg" width="25" height="25"/>
|
||||
<TintableSvg src="img/icons-directory.svg" width="25" height="25"/>
|
||||
{ this.getLabel("Room directory", this.state.directoryHover) }
|
||||
</AccessibleButton>
|
||||
<AccessibleButton className="mx_BottomLeftMenu_createRoom" onClick={ this.onRoomsClick } onMouseEnter={ this.onRoomsMouseEnter } onMouseLeave={ this.onRoomsMouseLeave } >
|
||||
<TintableSvg ref={this._collectCreateRoomButton} src="img/icons-create-room.svg" width="25" height="25" />
|
||||
<TintableSvg src="img/icons-create-room.svg" width="25" height="25" />
|
||||
{ this.getLabel("Create new room", this.state.roomsHover) }
|
||||
</AccessibleButton>
|
||||
<AccessibleButton className="mx_BottomLeftMenu_settings" onClick={ this.onSettingsClick } onMouseEnter={ this.onSettingsMouseEnter } onMouseLeave={ this.onSettingsMouseLeave } >
|
||||
|
||||
@@ -19,11 +19,9 @@ 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");
|
||||
|
||||
@@ -42,10 +40,6 @@ var LeftPanel = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.focusedElement = null;
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
},
|
||||
@@ -68,91 +62,6 @@ 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
|
||||
@@ -211,8 +120,7 @@ var LeftPanel = React.createClass({
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className={classes} style={{ opacity: this.props.opacity }}
|
||||
onKeyDown={ this._onKeyDown } onFocus={ this._onFocus } onBlur={ this._onBlur }>
|
||||
<aside className={classes} style={{ opacity: this.props.opacity }}>
|
||||
<SearchBox collapsed={ this.props.collapsed } onSearch={ this.onSearch } />
|
||||
{ collapseButton }
|
||||
{ callPreview }
|
||||
|
||||
@@ -23,6 +23,7 @@ var ContentRepo = require("matrix-js-sdk").ContentRepo;
|
||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
||||
var sdk = require('matrix-react-sdk');
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
var GeminiScrollbar = require('react-gemini-scrollbar');
|
||||
|
||||
var linkify = require('linkifyjs');
|
||||
var linkifyString = require('linkifyjs/string');
|
||||
@@ -161,7 +162,7 @@ module.exports = React.createClass({
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to get public room list",
|
||||
description: ((err && err.message) ? err.message : "The server may be unavailable or overloaded"),
|
||||
description: "The server may be unavailable or overloaded",
|
||||
});
|
||||
});
|
||||
},
|
||||
@@ -209,8 +210,8 @@ module.exports = React.createClass({
|
||||
this.refreshRoomList();
|
||||
console.error("Failed to " + step + ": " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to " + step,
|
||||
description: ((err && err.message) ? err.message : "The server may be unavailable or overloaded"),
|
||||
title: "Error",
|
||||
description: "Failed to " + step,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -459,17 +460,6 @@ module.exports = React.createClass({
|
||||
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() {
|
||||
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
||||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
|
||||
@@ -27,10 +27,8 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
|
||||
var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
|
||||
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
|
||||
var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher');
|
||||
var RoomSubListHeader = require('./RoomSubListHeader.js');
|
||||
|
||||
// turn this on for drag & drop console debugging galore
|
||||
// turn this on for drop & drag console debugging galore
|
||||
var debug = false;
|
||||
|
||||
const TRUNCATE_AT = 10;
|
||||
@@ -73,16 +71,17 @@ var RoomSubList = React.createClass({
|
||||
|
||||
order: React.PropTypes.string.isRequired,
|
||||
|
||||
// undefined if no room is selected (eg we are showing settings)
|
||||
selectedRoom: React.PropTypes.string,
|
||||
|
||||
startAsHidden: React.PropTypes.bool,
|
||||
showSpinner: React.PropTypes.bool, // true to show a spinner if 0 elements when expanded
|
||||
collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed?
|
||||
onHeaderClick: React.PropTypes.func,
|
||||
alwaysShowHeader: React.PropTypes.bool,
|
||||
selectedRoom: React.PropTypes.string,
|
||||
incomingCall: React.PropTypes.object,
|
||||
onShowMoreRooms: React.PropTypes.func,
|
||||
searchFilter: React.PropTypes.string,
|
||||
emptyContent: React.PropTypes.node, // content shown if the list is empty
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@@ -101,31 +100,13 @@ var RoomSubList = React.createClass({
|
||||
},
|
||||
|
||||
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._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) {
|
||||
// order the room list appropriately before we re-render
|
||||
//if (debug) console.log("received new props, list = " + newProps.list);
|
||||
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) {
|
||||
@@ -138,7 +119,7 @@ var RoomSubList = React.createClass({
|
||||
// The header is collapsable if it is hidden or not stuck
|
||||
// The dataset elements are added in the RoomList _initAndPositionStickyHeaders method
|
||||
isCollapsableOnClick: function() {
|
||||
var stuck = this.refs.header.refs.header.dataset.stuck;
|
||||
var stuck = this.refs.header.dataset.stuck;
|
||||
if (this.state.hidden || stuck === undefined || stuck === "none") {
|
||||
return true;
|
||||
} else {
|
||||
@@ -161,15 +142,14 @@ var RoomSubList = React.createClass({
|
||||
this.props.onHeaderClick(isHidden);
|
||||
} else {
|
||||
// The header is stuck, so the click is to be interpreted as a scroll to the header
|
||||
this.props.onHeaderClick(this.state.hidden, this.refs.header.refs.header.dataset.originalPosition);
|
||||
this.props.onHeaderClick(this.state.hidden, this.refs.header.dataset.originalPosition);
|
||||
}
|
||||
},
|
||||
|
||||
onRoomTileClick(roomId, ev) {
|
||||
onRoomTileClick(roomId) {
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: roomId,
|
||||
clear_search: (ev && (ev.keyCode == 13 || ev.keyCode == 32)),
|
||||
});
|
||||
},
|
||||
|
||||
@@ -231,6 +211,9 @@ var RoomSubList = React.createClass({
|
||||
if (order === "manual") comparator = this.manualComparator;
|
||||
if (order === "recent") comparator = this.recentsComparator;
|
||||
|
||||
// Fix undefined orders here, and make sure the backend gets updated as well
|
||||
this._fixUndefinedOrder(list);
|
||||
|
||||
//if (debug) console.log("sorting list for sublist " + this.props.label + " with length " + list.length + ", this.props.list = " + this.props.list);
|
||||
this.setState({ sortedList: list.sort(comparator) });
|
||||
},
|
||||
@@ -265,9 +248,10 @@ var RoomSubList = React.createClass({
|
||||
|
||||
if (badges) {
|
||||
result[0] += notificationCount;
|
||||
if (highlight) {
|
||||
result[1] = true;
|
||||
}
|
||||
}
|
||||
|
||||
result[1] |= highlight;
|
||||
}
|
||||
return result;
|
||||
}, [0, false]);
|
||||
@@ -375,6 +359,7 @@ var RoomSubList = React.createClass({
|
||||
var self = this;
|
||||
var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile");
|
||||
return this.state.sortedList.map(function(room) {
|
||||
var selected = room.roomId == self.props.selectedRoom;
|
||||
// XXX: is it evil to pass in self as a prop to RoomTile?
|
||||
return (
|
||||
<DNDRoomTile
|
||||
@@ -382,7 +367,9 @@ var RoomSubList = React.createClass({
|
||||
roomSubList={ self }
|
||||
key={ room.roomId }
|
||||
collapsed={ self.props.collapsed || false}
|
||||
selectedRoom={ self.props.selectedRoom }
|
||||
selected={ selected }
|
||||
unread={ Unread.doesRoomHaveUnreadMessages(room) }
|
||||
highlight={ room.getUnreadNotificationCount('highlight') > 0 || self.props.label === 'Invites' }
|
||||
isInvite={ self.props.label === 'Invites' }
|
||||
refreshSubList={ self._updateSubListCount }
|
||||
incomingCall={ null }
|
||||
@@ -392,6 +379,70 @@ 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) {
|
||||
var content = <div className="mx_RoomSubList_chevronDown"></div>;
|
||||
|
||||
@@ -447,7 +498,7 @@ var RoomSubList = React.createClass({
|
||||
// gets triggered and another list is passed in. Doing it one at a time means that
|
||||
// we always correctly calculate the highest order for the list - stops multiple
|
||||
// rooms getting the same order. This is only really relevant for the first time this
|
||||
// is run with historical room tag data, after that there should only be one undefined
|
||||
// is run with historical room tag data, after that there should only be undefined
|
||||
// in the list at a time anyway.
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (list[i].tags[self.props.tagName] && list[i].tags[self.props.tagName].order === undefined) {
|
||||
@@ -457,8 +508,8 @@ var RoomSubList = React.createClass({
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
console.error("Failed to add tag " + self.props.tagName + " to room" + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to add tag " + self.props.tagName + " to room",
|
||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||
title: "Error",
|
||||
description: "Failed to add tag " + self.props.tagName + " to room",
|
||||
});
|
||||
});
|
||||
break;
|
||||
@@ -469,28 +520,16 @@ var RoomSubList = React.createClass({
|
||||
|
||||
render: function() {
|
||||
var connectDropTarget = this.props.connectDropTarget;
|
||||
var RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget');
|
||||
var TruncatedList = sdk.getComponent('elements.TruncatedList');
|
||||
|
||||
var label = this.props.collapsed ? null : this.props.label;
|
||||
|
||||
//console.log("render: " + JSON.stringify(this.state.sortedList));
|
||||
|
||||
let content;
|
||||
if (this.state.sortedList.length == 0) {
|
||||
//content = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>;
|
||||
content = this.props.emptyContent;
|
||||
} else {
|
||||
content = this.makeRoomTiles();
|
||||
}
|
||||
|
||||
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;
|
||||
var target;
|
||||
if (this.state.sortedList.length == 0 && this.props.editable) {
|
||||
target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>;
|
||||
}
|
||||
|
||||
if (this.state.sortedList.length > 0 || this.props.editable) {
|
||||
@@ -500,7 +539,8 @@ var RoomSubList = React.createClass({
|
||||
if (!this.state.hidden) {
|
||||
subList = <TruncatedList className={ classes } truncateAt={this.state.truncateAt}
|
||||
createOverflowElement={this._createOverflowTile} >
|
||||
{ content }
|
||||
{ target }
|
||||
{ this.makeRoomTiles() }
|
||||
</TruncatedList>;
|
||||
}
|
||||
else {
|
||||
@@ -510,19 +550,7 @@ var RoomSubList = React.createClass({
|
||||
|
||||
return connectDropTarget(
|
||||
<div>
|
||||
<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 }
|
||||
/>
|
||||
{ this._getHeaderJsx() }
|
||||
{ subList }
|
||||
</div>
|
||||
);
|
||||
@@ -531,20 +559,7 @@ var RoomSubList = React.createClass({
|
||||
var Loader = sdk.getComponent("elements.Spinner");
|
||||
return (
|
||||
<div className="mx_RoomSubList">
|
||||
{ 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.alwaysShowHeader ? this._getHeaderJsx() : undefined }
|
||||
{ (this.props.showSpinner && !this.state.hidden) ? <Loader /> : undefined }
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
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,7 +21,6 @@ var sdk = require('matrix-react-sdk')
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');
|
||||
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
|
||||
var KeyCode = require('matrix-react-sdk/lib/KeyCode');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'SearchBox',
|
||||
@@ -39,23 +38,25 @@ module.exports = React.createClass({
|
||||
|
||||
componentDidMount: function() {
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
document.addEventListener('keydown', this._onKeyDown);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
document.removeEventListener('keydown', this._onKeyDown);
|
||||
},
|
||||
|
||||
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) {
|
||||
// Clear up the text field when a room is selected.
|
||||
case 'view_room':
|
||||
if (payload.clear_search && this.refs.search) {
|
||||
if (this.refs.search) {
|
||||
this._clearSearch();
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
onChange: function() {
|
||||
@@ -89,38 +90,6 @@ module.exports = React.createClass({
|
||||
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() {
|
||||
var TintableSvg = sdk.getComponent('elements.TintableSvg');
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ module.exports = React.createClass({
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to remove tag " + tagNameOff + " from room",
|
||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||
description: err.toString()
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -88,7 +88,7 @@ module.exports = React.createClass({
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to add tag " + tagNameOn + " to room",
|
||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||
description: err.toString()
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -149,7 +149,7 @@ module.exports = React.createClass({
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to set Direct Message status of room",
|
||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||
description: err.toString()
|
||||
});
|
||||
});
|
||||
},
|
||||
@@ -187,8 +187,8 @@ module.exports = React.createClass({
|
||||
var errCode = err.errcode || "unknown error code";
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: `Failed to forget room (${errCode})`,
|
||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||
title: "Error",
|
||||
description: `Failed to forget room (${errCode})`
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import sdk from 'matrix-react-sdk';
|
||||
import SdkConfig from 'matrix-react-sdk/lib/SdkConfig';
|
||||
import rageshake from '../../../vector/rageshake';
|
||||
|
||||
export default class BugReportDialog extends React.Component {
|
||||
constructor(props, context) {
|
||||
@@ -26,18 +26,11 @@ export default class BugReportDialog extends React.Component {
|
||||
busy: false,
|
||||
err: null,
|
||||
text: "",
|
||||
progress: null,
|
||||
};
|
||||
this._unmounted = false;
|
||||
this._onSubmit = this._onSubmit.bind(this);
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onTextChange = this._onTextChange.bind(this);
|
||||
this._onSendLogsChange = this._onSendLogsChange.bind(this);
|
||||
this._sendProgressCallback = this._sendProgressCallback.bind(this);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._unmounted = true;
|
||||
}
|
||||
|
||||
_onCancel(ev) {
|
||||
@@ -53,27 +46,12 @@ export default class BugReportDialog extends React.Component {
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.setState({ busy: true, progress: null, err: null });
|
||||
this._sendProgressCallback("Loading bug report module");
|
||||
|
||||
require(['../../../vector/submit-rageshake'], (s) => {
|
||||
s(SdkConfig.get().bug_report_endpoint_url, {
|
||||
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}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
this.setState({ busy: true, err: null });
|
||||
rageshake.sendBugReport(userText, sendLogs).then(() => {
|
||||
this.setState({ busy: false });
|
||||
this.props.onFinished(false);
|
||||
}, (err) => {
|
||||
this.setState({ busy: false, err: `Failed: ${err.message}` });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,13 +63,6 @@ export default class BugReportDialog extends React.Component {
|
||||
this.setState({ sendLogs: ev.target.checked });
|
||||
}
|
||||
|
||||
_sendProgressCallback(progress) {
|
||||
if (this._unmounted) {
|
||||
return;
|
||||
}
|
||||
this.setState({progress: progress});
|
||||
}
|
||||
|
||||
render() {
|
||||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
|
||||
@@ -102,6 +73,8 @@ export default class BugReportDialog extends React.Component {
|
||||
</div>;
|
||||
}
|
||||
|
||||
const okLabel = this.state.busy ? <Loader /> : 'Send';
|
||||
|
||||
let cancelButton = null;
|
||||
if (!this.state.busy) {
|
||||
cancelButton = <button onClick={this._onCancel}>
|
||||
@@ -109,16 +82,6 @@ export default class BugReportDialog extends React.Component {
|
||||
</button>;
|
||||
}
|
||||
|
||||
let progress = null;
|
||||
if (this.state.busy) {
|
||||
progress = (
|
||||
<div className="progress">
|
||||
<Loader />
|
||||
{this.state.progress} ...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_BugReportDialog">
|
||||
<div className="mx_Dialog_title">
|
||||
@@ -141,7 +104,6 @@ export default class BugReportDialog extends React.Component {
|
||||
<input type="checkbox" checked={this.state.sendLogs}
|
||||
onChange={this._onSendLogsChange} id="mx_BugReportDialog_logs"/>
|
||||
<label htmlFor="mx_BugReportDialog_logs">Send logs</label>
|
||||
{progress}
|
||||
{error}
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
@@ -149,9 +111,8 @@ export default class BugReportDialog extends React.Component {
|
||||
className="mx_Dialog_primary danger"
|
||||
onClick={this._onSubmit}
|
||||
autoFocus={true}
|
||||
disabled={this.state.busy}
|
||||
>
|
||||
Send
|
||||
{okLabel}
|
||||
</button>
|
||||
|
||||
{cancelButton}
|
||||
|
||||
@@ -176,7 +176,7 @@ module.exports = React.createClass({
|
||||
{ this.getName() }
|
||||
</div>
|
||||
{ eventMeta }
|
||||
<a className="mx_ImageView_link" href={ this.props.src } download={ this.props.name } target="_blank" rel="noopener">
|
||||
<a className="mx_ImageView_link" href={ this.props.src } target="_blank" rel="noopener">
|
||||
<div className="mx_ImageView_download">
|
||||
Download this file<br/>
|
||||
<span className="mx_ImageView_size">{ size_res }</span>
|
||||
|
||||
@@ -18,9 +18,6 @@ limitations under the License.
|
||||
|
||||
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({
|
||||
displayName: 'VectorLoginHeader',
|
||||
statics: {
|
||||
@@ -33,7 +30,7 @@ module.exports = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_Login_logo">
|
||||
<img src={this.props.icon || DEFAULT_LOGO_URI} alt="Riot"/>
|
||||
<img src={this.props.icon || "img/logo.png"} alt="Riot"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,8 +90,8 @@ var roomTileSource = {
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
console.error("Failed to set direct chat tag " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to set direct chat tag",
|
||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||
title: "Error",
|
||||
description: "Failed to set direct chat tag",
|
||||
});
|
||||
});
|
||||
return;
|
||||
@@ -115,8 +115,8 @@ var roomTileSource = {
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
console.error("Failed to remove tag " + prevTag + " from room: " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to remove tag " + prevTag + " from room",
|
||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||
title: "Error",
|
||||
description: "Failed to remove tag " + prevTag + " from room",
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -137,8 +137,8 @@ var roomTileSource = {
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
console.error("Failed to add tag " + newTag + " to room: " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to add tag " + newTag + " to room",
|
||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||
title: "Error",
|
||||
description: "Failed to add tag " + newTag + " to room",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,12 +22,20 @@ module.exports = React.createClass({
|
||||
displayName: 'RoomDropTarget',
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_RoomDropTarget">
|
||||
<div className="mx_RoomDropTarget_label">
|
||||
{ this.props.label }
|
||||
if (this.props.placeholder) {
|
||||
return (
|
||||
<div className="mx_RoomDropTarget mx_RoomDropTarget_placeholder">
|
||||
</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");
|
||||
console.error("Failed to change settings: " + error);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to change settings",
|
||||
description: ((error && error.message) ? error.message : "Operation failed"),
|
||||
title: "Error",
|
||||
description: "Failed to change settings",
|
||||
onFinished: self._refreshFromServer
|
||||
});
|
||||
});
|
||||
@@ -310,8 +310,8 @@ module.exports = React.createClass({
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
console.error("Can't update user notification settings: " + error);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Can't update user notification settings",
|
||||
description: ((error && error.message) ? error.message : "Operation failed"),
|
||||
title: "Error",
|
||||
description: "Can't update user notification settings",
|
||||
onFinished: self._refreshFromServer
|
||||
});
|
||||
});
|
||||
@@ -352,8 +352,8 @@ module.exports = React.createClass({
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
console.error("Failed to update keywords: " + error);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to update keywords",
|
||||
description: ((error && error.message) ? error.message : "Operation failed"),
|
||||
title: "Error",
|
||||
description: "Failed to update keywords",
|
||||
onFinished: self._refreshFromServer
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ input[type=text].error, input[type=password].error {
|
||||
border: 1px solid $warning-color;
|
||||
}
|
||||
|
||||
input[type=text]:focus, input[type=password]:focus, textarea:focus {
|
||||
input[type=text]:focus, textarea:focus {
|
||||
border: 1px solid $accent-color;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
@@ -225,10 +225,6 @@ textarea {
|
||||
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 {
|
||||
color: $accent-fg-color;
|
||||
background-color: $accent-color;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
@import "./matrix-react-sdk/views/dialogs/_EncryptedEventDialog.scss";
|
||||
@import "./matrix-react-sdk/views/dialogs/_SetDisplayNameDialog.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/_AddressTile.scss";
|
||||
@import "./matrix-react-sdk/views/elements/_DirectorySearchBox.scss";
|
||||
|
||||
@@ -171,7 +171,7 @@ hr.mx_RoomView_myReadMarker {
|
||||
|
||||
max-height: 0px;
|
||||
background-color: $primary-bg-color;
|
||||
z-index: 5;
|
||||
z-index: 1000;
|
||||
overflow: hidden;
|
||||
|
||||
-webkit-transition: all .2s ease-out;
|
||||
@@ -259,4 +259,4 @@ hr.mx_RoomView_myReadMarker {
|
||||
|
||||
.mx_RoomView_ongoingConfCallNotification a {
|
||||
color: $accent-fg-color ! important;
|
||||
}
|
||||
}
|
||||
@@ -176,15 +176,6 @@ limitations under the License.
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_UserSettings_phoneSection {
|
||||
display:table;
|
||||
}
|
||||
|
||||
.mx_UserSettings_phoneCountry {
|
||||
width: 70px;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
input.mx_UserSettings_phoneNumberField {
|
||||
margin-left: 3px;
|
||||
width: 172px;
|
||||
@@ -222,9 +213,3 @@ input.mx_UserSettings_phoneNumberField {
|
||||
.mx_UserSettings_avatarPicker_edit > input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_UserSettings_advanced_spoiler {
|
||||
cursor: pointer;
|
||||
color: $accent-color;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,7 @@ limitations under the License.
|
||||
|
||||
.mx_Login_logo {
|
||||
text-align: center;
|
||||
height: 150px;
|
||||
margin-bottom: 45px;
|
||||
height: 195px;
|
||||
}
|
||||
|
||||
.mx_Login_logo img {
|
||||
@@ -67,6 +66,10 @@ limitations under the License.
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.mx_Login_username {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.mx_Login_fieldLabel {
|
||||
margin-top: -10px;
|
||||
margin-left: 8px;
|
||||
@@ -164,82 +167,16 @@ limitations under the License.
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.mx_Login_type_container {
|
||||
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_phoneSection {
|
||||
display: table;
|
||||
}
|
||||
|
||||
.mx_Login_phoneCountry {
|
||||
margin-bottom: 14px;
|
||||
display: table-cell;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.mx_Login_phoneCountry .mx_Dropdown_option {
|
||||
/*
|
||||
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;
|
||||
.mx_Login_phoneNumberField {
|
||||
width: 210px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
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,15 +27,6 @@ limitations under the License.
|
||||
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 {
|
||||
border-color: $primary-fg-color transparent transparent;
|
||||
border-style: solid;
|
||||
@@ -83,7 +74,7 @@ input.mx_Dropdown_option, input.mx_Dropdown_option:focus {
|
||||
border: 1px solid $accent-color;
|
||||
background-color: $primary-bg-color;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.mx_Dropdown_menu .mx_Dropdown_option_highlight {
|
||||
|
||||
@@ -331,14 +331,6 @@ limitations under the License.
|
||||
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 {
|
||||
color: $accent-color;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ limitations under the License.
|
||||
margin-left: -2px;
|
||||
order: 1;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_spinner {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
Copyright 2107 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.
|
||||
@@ -38,24 +37,3 @@ limitations under the License.
|
||||
.mx_RoomList_scrollbar .gm-scrollbar.-vertical {
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
.mx_RoomList_greyedSubListLabel {
|
||||
color: #a2a2a2;
|
||||
}
|
||||
|
||||
.mx_RoomList_emptySubListTip {
|
||||
font-size: 13px;
|
||||
margin-left: 18px;
|
||||
margin-right: 18px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 7px;
|
||||
padding: 5px;
|
||||
border: 1px solid $accent-color;
|
||||
color: $primary-fg-color;
|
||||
background-color: $droptarget-bg-color;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.mx_RoomList_butonPreview {
|
||||
float: right;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_RoomTile:focus {
|
||||
filter: none ! important;
|
||||
outline: 0;
|
||||
background-color: $roomtile-focused-bg-color;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,15 +17,20 @@ limitations under the License.
|
||||
.mx_TopUnreadMessagesBar {
|
||||
margin: auto; /* centre horizontally */
|
||||
max-width: 960px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid $primary-hairline-color;
|
||||
|
||||
/* in absence of img */
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.mx_TopUnreadMessagesBar_scrollUp {
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
|
||||
/* in absence of img */
|
||||
padding-left: 65px;
|
||||
}
|
||||
|
||||
.mx_TopUnreadMessagesBar_scrollUp img {
|
||||
|
||||
@@ -15,8 +15,6 @@ $accent-color: #76CFA6;
|
||||
|
||||
$selection-fg-color: $primary-bg-color;
|
||||
|
||||
$focus-brightness: 125%;
|
||||
|
||||
// red warning colour
|
||||
$warning-color: #ff0064;
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@ $accent-color: #76CFA6;
|
||||
|
||||
$selection-fg-color: $primary-fg-color;
|
||||
|
||||
$focus-brightness: 200%;
|
||||
|
||||
// red warning colour
|
||||
$warning-color: #ff0064;
|
||||
|
||||
|
||||
@@ -33,6 +33,11 @@ limitations under the License.
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.mx_RoomDropTarget_placeholder {
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.mx_RoomDropTarget_label {
|
||||
position: relative;
|
||||
margin-top: 3px;
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
<?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">
|
||||
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>icons_directory</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<!-- Generator: sketchtool 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>E34C64ED-EBD7-49B6-BDD9-CB729162705A</title>
|
||||
<desc>Created with sketchtool.</desc>
|
||||
<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="Left-panel" transform="translate(-83.000000, -726.000000)">
|
||||
<g id="icons_directory">
|
||||
<g transform="translate(83.000000, 726.000000)">
|
||||
<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 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 id="Room-list-Copy-3" transform="translate(-58.000000, -726.000000)">
|
||||
<g id="icons_directory" transform="translate(58.000000, 726.000000)">
|
||||
<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>
|
||||
<use id="Rectangle-9" stroke="#FFFFFF" mask="url(#mask-2)" stroke-width="2" opacity="0.8" xlink:href="#path-1"></use>
|
||||
<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>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
src/skins/vector/img/logo.png
Normal file
BIN
src/skins/vector/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -1,21 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -259,15 +259,11 @@ async function loadApp() {
|
||||
let configError;
|
||||
try {
|
||||
configJson = await getConfig();
|
||||
rageshake.setBugReportEndpoint(configJson.bug_report_endpoint_url);
|
||||
} catch (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);
|
||||
if (configError) {
|
||||
window.matrixChat = ReactDOM.render(<div className="error">
|
||||
@@ -299,7 +295,6 @@ async function loadApp() {
|
||||
var CompatibilityPage = sdk.getComponent("structures.CompatibilityPage");
|
||||
window.matrixChat = ReactDOM.render(
|
||||
<CompatibilityPage onAccept={function() {
|
||||
if (window.localStorage) window.localStorage.setItem('mx_accepts_unsupported_browser', true);
|
||||
validBrowser = true;
|
||||
console.log("User accepts the compatibility risks.");
|
||||
loadApp();
|
||||
|
||||
@@ -24,12 +24,12 @@ import q from 'q';
|
||||
const electron = require('electron');
|
||||
const remote = electron.remote;
|
||||
|
||||
remote.autoUpdater.on('update-downloaded', onUpdateDownloaded);
|
||||
electron.remote.autoUpdater.on('update-downloaded', onUpdateDownloaded);
|
||||
|
||||
function onUpdateDownloaded(ev, releaseNotes, ver, date, updateURL) {
|
||||
dis.dispatch({
|
||||
action: 'new_version',
|
||||
currentVersion: remote.app.getVersion(),
|
||||
currentVersion: electron.remote.app.getVersion(),
|
||||
newVersion: ver,
|
||||
releaseNotes: releaseNotes,
|
||||
});
|
||||
@@ -68,7 +68,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
try {
|
||||
remote.app.setBadgeCount(count);
|
||||
} catch (e) {
|
||||
console.error('Failed to set notification count', e);
|
||||
console.error("Failed to set notification count", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,24 +81,13 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
}
|
||||
|
||||
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
|
||||
const notification = new global.Notification(
|
||||
title,
|
||||
{
|
||||
body: msg,
|
||||
icon: avatarUrl,
|
||||
tag: 'vector',
|
||||
tag: "vector",
|
||||
silent: true, // we play our own sounds
|
||||
}
|
||||
);
|
||||
@@ -106,14 +95,13 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
notification.onclick = function() {
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: room.roomId,
|
||||
room_id: room.roomId
|
||||
});
|
||||
global.focus();
|
||||
const win = remote.getCurrentWindow();
|
||||
|
||||
if (win.isMinimized()) win.restore();
|
||||
else if (!win.isVisible()) win.show();
|
||||
else win.focus();
|
||||
const currentWin = electron.remote.getCurrentWindow();
|
||||
currentWin.show();
|
||||
currentWin.restore();
|
||||
currentWin.focus();
|
||||
};
|
||||
|
||||
return notification;
|
||||
@@ -124,7 +112,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
}
|
||||
|
||||
getAppVersion() {
|
||||
return q(remote.app.getVersion());
|
||||
return q(electron.remote.app.getVersion());
|
||||
}
|
||||
|
||||
pollForUpdate() {
|
||||
@@ -141,7 +129,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
}
|
||||
|
||||
getDefaultDeviceDisplayName() {
|
||||
return 'Riot Desktop on ' + platformFriendlyName();
|
||||
return "Riot Desktop on " + platformFriendlyName();
|
||||
}
|
||||
|
||||
screenCaptureErrorString() {
|
||||
@@ -153,6 +141,6 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
}
|
||||
|
||||
reload() {
|
||||
remote.getCurrentWebContents().reload();
|
||||
electron.remote.getCurrentWebContents().reload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
|
||||
import request from "browser-request";
|
||||
import q from "q";
|
||||
|
||||
// This module contains all the code needed to log the console, persist it to
|
||||
@@ -203,6 +205,9 @@ class IndexedDBLogStore {
|
||||
}
|
||||
let txn = this.db.transaction(["logs", "logslastmod"], "readwrite");
|
||||
let objStore = txn.objectStore("logs");
|
||||
objStore.add(this._generateLogEntry(lines));
|
||||
let lastModStore = txn.objectStore("logslastmod");
|
||||
lastModStore.put(this._generateLastModifiedTime());
|
||||
txn.oncomplete = (event) => {
|
||||
resolve();
|
||||
};
|
||||
@@ -214,9 +219,6 @@ class IndexedDBLogStore {
|
||||
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;
|
||||
}
|
||||
@@ -394,6 +396,7 @@ function selectQuery(store, keyRange, resultMapper) {
|
||||
let store = null;
|
||||
let logger = null;
|
||||
let initPromise = null;
|
||||
let bugReportEndpoint = null;
|
||||
module.exports = {
|
||||
|
||||
/**
|
||||
@@ -427,29 +430,81 @@ module.exports = {
|
||||
await store.consume();
|
||||
},
|
||||
|
||||
setBugReportEndpoint: function(url) {
|
||||
bugReportEndpoint = url;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a recent snapshot of the logs, ready for attaching to a bug report
|
||||
*
|
||||
* @return {Array<{lines: string, id, string}>} list of log data
|
||||
* Send a bug report.
|
||||
* @param {string} userText Any additional user input.
|
||||
* @param {boolean} sendLogs True to send logs
|
||||
* @return {Promise} Resolved when the bug report is sent.
|
||||
*/
|
||||
getLogsForReport: async function() {
|
||||
sendBugReport: async function(userText, sendLogs) {
|
||||
if (!logger) {
|
||||
throw new Error(
|
||||
"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
|
||||
// sending to work going off the in-memory console logs.
|
||||
if (store) {
|
||||
// flush most recent logs
|
||||
await store.flush();
|
||||
return await store.consume();
|
||||
console.log("Sending bug report.");
|
||||
let logs = [];
|
||||
if (sendLogs) {
|
||||
if (store) {
|
||||
// flush most recent logs
|
||||
await store.flush();
|
||||
logs = await store.consume();
|
||||
}
|
||||
else {
|
||||
logs.push({
|
||||
lines: logger.flush(true),
|
||||
id: "-",
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
return [{
|
||||
lines: logger.flush(true),
|
||||
id: "-",
|
||||
}];
|
||||
}
|
||||
},
|
||||
|
||||
await q.Promise((resolve, reject) => {
|
||||
request({
|
||||
method: "POST",
|
||||
url: bugReportEndpoint,
|
||||
body: {
|
||||
logs: logs,
|
||||
text: (
|
||||
userText || "User did not supply any additional text."
|
||||
),
|
||||
app: 'riot-web',
|
||||
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();
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
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 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;
|
||||
}
|
||||
|
||||
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 (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,13 +72,14 @@ describe('joining a room', function () {
|
||||
var ROOM_ALIAS = '#alias:localhost';
|
||||
var ROOM_ID = '!id:localhost';
|
||||
|
||||
httpBackend.when('PUT', '/presence/'+encodeURIComponent(USER_ID)+'/status')
|
||||
.respond(200, {});
|
||||
httpBackend.when('GET', '/pushrules').respond(200, {});
|
||||
httpBackend.when('POST', '/filter').respond(200, { filter_id: 'fid' });
|
||||
httpBackend.when('GET', '/sync').respond(200, {});
|
||||
|
||||
// note that we deliberately do *not* set an expectation for a
|
||||
// presence update - setting one makes the first httpBackend.flush
|
||||
// return before the first /sync arrives.
|
||||
httpBackend.when('POST', '/publicRooms').respond(200, {chunk: []});
|
||||
httpBackend.when('GET', '/thirdparty/protocols').respond(200, {});
|
||||
httpBackend.when('GET', '/directory/room/'+encodeURIComponent(ROOM_ALIAS)).respond(200, { room_id: ROOM_ID });
|
||||
|
||||
// start with a logged-in client
|
||||
localStorage.setItem("mx_hs_url", HS_URL );
|
||||
@@ -93,18 +94,9 @@ describe('joining a room', function () {
|
||||
matrixChat._setPage(PageTypes.RoomDirectory);
|
||||
|
||||
var roomView;
|
||||
|
||||
// wait for /sync to happen
|
||||
return q.delay(1).then(() => {
|
||||
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(() => {
|
||||
var roomDir = ReactTestUtils.findRenderedComponentWithType(
|
||||
matrixChat, RoomDirectory);
|
||||
@@ -118,7 +110,6 @@ describe('joining a room', function () {
|
||||
|
||||
// that should create a roomview which will start a peek; wait
|
||||
// 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")
|
||||
.respond(401, {errcode: 'M_GUEST_ACCESS_FORBIDDEN'});
|
||||
return httpBackend.flush();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
var ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
@@ -19,11 +19,11 @@ module.exports = {
|
||||
|
||||
// CSS themes
|
||||
"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: {
|
||||
preLoaders: [
|
||||
{ test: /\.js$/, loader: "source-map-loader" },
|
||||
{ test: /\.js$/, loader: "source-map-loader" }
|
||||
],
|
||||
loaders: [
|
||||
{ test: /\.json$/, loader: "json" },
|
||||
@@ -38,7 +38,9 @@ module.exports = {
|
||||
// would also drag in the imgs and fonts that our CSS refers to
|
||||
// as webpack inputs.)
|
||||
// 3. ExtractTextPlugin turns that string into a separate asset.
|
||||
loader: ExtractTextPlugin.extract("css-raw-loader!postcss-loader?config=postcss.config.js"),
|
||||
loader: ExtractTextPlugin.extract(
|
||||
"css-raw-loader!postcss-loader?config=postcss.config.js"
|
||||
),
|
||||
},
|
||||
{
|
||||
// this works similarly to the scss case, without postcss.
|
||||
@@ -47,18 +49,15 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
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
|
||||
// overflows (https://github.com/webpack/webpack/issues/1721), and
|
||||
// there is no need for webpack to parse them - they can just be
|
||||
// included as-is.
|
||||
/highlight\.js[\\\/]lib[\\\/]languages/,
|
||||
/highlight\.js\/lib\/languages/,
|
||||
|
||||
// olm takes ages for webpack to process, and it's already heavily
|
||||
// optimised, so there is little to gain by us uglifying it.
|
||||
/olm[\\\/](javascript[\\\/])?olm\.js$/,
|
||||
/olm\/(javascript\/)?olm\.js$/,
|
||||
],
|
||||
},
|
||||
output: {
|
||||
@@ -84,7 +83,7 @@ module.exports = {
|
||||
// various levels of '.' and '..'
|
||||
// Also, sometimes the resource path is absolute.
|
||||
return path.relative(process.cwd(), info.resourcePath).replace(/^[\/\.]*/, '');
|
||||
},
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
@@ -107,13 +106,16 @@ module.exports = {
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
||||
},
|
||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
|
||||
}
|
||||
}),
|
||||
|
||||
new ExtractTextPlugin("bundles/[hash]/[name].css", {
|
||||
allChunks: true,
|
||||
}),
|
||||
new ExtractTextPlugin(
|
||||
"bundles/[hash]/[name].css",
|
||||
{
|
||||
allChunks: true
|
||||
}
|
||||
),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
template: './src/vector/index.html',
|
||||
|
||||
Reference in New Issue
Block a user