Compare commits

..

14 Commits

Author SHA1 Message Date
David Baker
5326faa0b8 v0.9.9-rc.2 2017-04-24 18:26:20 +01:00
David Baker
7f2fa09d4c Prepare changelog for v0.9.9-rc.2 2017-04-24 18:26:19 +01:00
David Baker
b6435502fc New version of react-sdk 2017-04-24 18:25:13 +01:00
David Baker
1701ea43a4 Remove spurious changelog entries 2017-04-24 18:22:23 +01:00
David Baker
141aafd18e v0.9.9-rc.1 2017-04-21 18:40:25 +01:00
David Baker
8aed52ece9 Prepare changelog for v0.9.9-rc.1 2017-04-21 18:40:24 +01:00
David Baker
ce5a7ba48a Rewind version to try again, again 2017-04-21 18:39:11 +01:00
David Baker
95647fb7a1 v0.9.9-rc.1 2017-04-21 18:35:15 +01:00
David Baker
d0c0eeac0a Prepare changelog for v0.9.9-rc.1 2017-04-21 18:35:14 +01:00
David Baker
f25612198e 0.9.8, not 0.9.9 2017-04-21 18:33:53 +01:00
David Baker
ca6d9063fd Back up release version to try again 2017-04-21 18:32:55 +01:00
David Baker
eec0c274d2 v0.9.9-rc.1 2017-04-21 18:26:29 +01:00
David Baker
b5a5b472c4 Prepare changelog for v0.9.9-rc.1 2017-04-21 18:26:29 +01:00
David Baker
9747836a4d Update react-sdk and js-sdk dependencies 2017-04-21 18:24:29 +01:00
43 changed files with 334 additions and 899 deletions

1
.gitignore vendored
View File

@@ -12,4 +12,3 @@
npm-debug.log
electron/dist
electron/pub
/config.json

View File

@@ -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)

View File

@@ -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;
});

View File

@@ -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",

View File

@@ -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}],
];

View File

@@ -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';

View File

@@ -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 } >

View File

@@ -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 }

View File

@@ -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");

View File

@@ -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>
);

View File

@@ -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>
);
},
});

View File

@@ -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');

View File

@@ -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})`
});
});

View File

@@ -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}

View File

@@ -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>

View File

@@ -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>
);
}

View File

@@ -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",
});
});
}

View File

@@ -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>
);
}
}
});

View File

@@ -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
});
}

View File

@@ -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;

View File

@@ -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";

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -31,7 +31,6 @@ limitations under the License.
margin-left: -2px;
order: 1;
flex: 1;
overflow: hidden;
}
.mx_RoomHeader_spinner {

View File

@@ -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;
}

View File

@@ -156,7 +156,7 @@ limitations under the License.
}
.mx_RoomTile:focus {
filter: none ! important;
outline: 0;
background-color: $roomtile-focused-bg-color;
}

View File

@@ -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 {

View File

@@ -15,8 +15,6 @@ $accent-color: #76CFA6;
$selection-fg-color: $primary-bg-color;
$focus-brightness: 125%;
// red warning colour
$warning-color: #ff0064;

View File

@@ -15,8 +15,6 @@ $accent-color: #76CFA6;
$selection-fg-color: $primary-fg-color;
$focus-brightness: 200%;
// red warning colour
$warning-color: #ff0064;

View File

@@ -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;

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -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

View File

@@ -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();

View File

@@ -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 &amp;
// 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, '&lt;').replace(/>/g, '&gt;');
}
// 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();
}
}

View File

@@ -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();
})
});
}
};

View File

@@ -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();
}
}

View File

@@ -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();

View File

@@ -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',