mirror of
https://github.com/SchildiChat/element-web.git
synced 2024-10-01 01:26:12 -04:00
Merge pull request #425 from vector-im/kegan/controller-merging3
Phase 3 controller merging
This commit is contained in:
commit
8a5828620c
@ -28,7 +28,6 @@
|
|||||||
"filesize": "^3.1.2",
|
"filesize": "^3.1.2",
|
||||||
"flux": "~2.0.3",
|
"flux": "~2.0.3",
|
||||||
"gfm.css": "^1.1.1",
|
"gfm.css": "^1.1.1",
|
||||||
"highlight.js": "^8.9.1",
|
|
||||||
"linkifyjs": "^2.0.0-beta.4",
|
"linkifyjs": "^2.0.0-beta.4",
|
||||||
"matrix-js-sdk": "https://github.com/matrix-org/matrix-js-sdk.git#develop",
|
"matrix-js-sdk": "https://github.com/matrix-org/matrix-js-sdk.git#develop",
|
||||||
"matrix-react-sdk": "https://github.com/matrix-org/matrix-react-sdk.git#develop",
|
"matrix-react-sdk": "https://github.com/matrix-org/matrix-react-sdk.git#develop",
|
||||||
@ -38,9 +37,7 @@
|
|||||||
"react-dnd": "^2.0.2",
|
"react-dnd": "^2.0.2",
|
||||||
"react-dnd-html5-backend": "^2.0.0",
|
"react-dnd-html5-backend": "^2.0.0",
|
||||||
"react-dom": "^0.14.2",
|
"react-dom": "^0.14.2",
|
||||||
"react-gemini-scrollbar": "^2.0.1",
|
"react-gemini-scrollbar": "^2.0.1"
|
||||||
"sanitize-html": "^1.0.0",
|
|
||||||
"velocity-animate": "^1.2.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel": "^5.8.23",
|
"babel": "^5.8.23",
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var ReactDOM = require('react-dom');
|
|
||||||
|
|
||||||
// Shamelessly ripped off Modal.js. There's probably a better way
|
|
||||||
// of doing reusable widgets like dialog boxes & menus where we go and
|
|
||||||
// pass in a custom control as the actual body.
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
ContextualMenuContainerId: "mx_ContextualMenu_Container",
|
|
||||||
|
|
||||||
getOrCreateContainer: function() {
|
|
||||||
var container = document.getElementById(this.ContextualMenuContainerId);
|
|
||||||
|
|
||||||
if (!container) {
|
|
||||||
container = document.createElement("div");
|
|
||||||
container.id = this.ContextualMenuContainerId;
|
|
||||||
document.body.appendChild(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
return container;
|
|
||||||
},
|
|
||||||
|
|
||||||
createMenu: function (Element, props) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var closeMenu = function() {
|
|
||||||
ReactDOM.unmountComponentAtNode(self.getOrCreateContainer());
|
|
||||||
|
|
||||||
if (props && props.onFinished) props.onFinished.apply(null, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
var position = {
|
|
||||||
top: props.top - 20,
|
|
||||||
};
|
|
||||||
|
|
||||||
var chevron = null;
|
|
||||||
if (props.left) {
|
|
||||||
chevron = <img className="mx_ContextualMenu_chevron_left" src="img/chevron-left.png" width="9" height="16" />
|
|
||||||
position.left = props.left + 8;
|
|
||||||
} else {
|
|
||||||
chevron = <img className="mx_ContextualMenu_chevron_right" src="img/chevron-right.png" width="9" height="16" />
|
|
||||||
position.right = props.right + 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
var className = 'mx_ContextualMenu_wrapper';
|
|
||||||
|
|
||||||
// FIXME: If a menu uses getDefaultProps it clobbers the onFinished
|
|
||||||
// property set here so you can't close the menu from a button click!
|
|
||||||
var menu = (
|
|
||||||
<div className={className}>
|
|
||||||
<div className="mx_ContextualMenu" style={position}>
|
|
||||||
{chevron}
|
|
||||||
<Element {...props} onFinished={closeMenu}/>
|
|
||||||
</div>
|
|
||||||
<div className="mx_ContextualMenu_background" onClick={closeMenu}></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
ReactDOM.render(menu, this.getOrCreateContainer());
|
|
||||||
|
|
||||||
return {close: closeMenu};
|
|
||||||
},
|
|
||||||
};
|
|
108
src/HtmlUtils.js
108
src/HtmlUtils.js
@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var sanitizeHtml = require('sanitize-html');
|
|
||||||
var highlight = require('highlight.js');
|
|
||||||
|
|
||||||
var sanitizeHtmlParams = {
|
|
||||||
allowedTags: [
|
|
||||||
'font', // custom to matrix. deliberately no h1/h2 to stop people shouting.
|
|
||||||
'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
|
|
||||||
'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div',
|
|
||||||
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre'
|
|
||||||
],
|
|
||||||
allowedAttributes: {
|
|
||||||
// custom ones first:
|
|
||||||
font: [ 'color' ], // custom to matrix
|
|
||||||
a: [ 'href', 'name', 'target' ], // remote target: custom to matrix
|
|
||||||
// We don't currently allow img itself by default, but this
|
|
||||||
// would make sense if we did
|
|
||||||
img: [ 'src' ],
|
|
||||||
},
|
|
||||||
// Lots of these won't come up by default because we don't allow them
|
|
||||||
selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
|
|
||||||
// URL schemes we permit
|
|
||||||
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto' ],
|
|
||||||
allowedSchemesByTag: {},
|
|
||||||
|
|
||||||
transformTags: { // custom to matrix
|
|
||||||
// add blank targets to all hyperlinks
|
|
||||||
'a': sanitizeHtml.simpleTransform('a', { target: '_blank'} )
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
bodyToHtml: function(content, searchTerm) {
|
|
||||||
var originalBody = content.body;
|
|
||||||
var body;
|
|
||||||
|
|
||||||
if (searchTerm) {
|
|
||||||
var lastOffset = 0;
|
|
||||||
var bodyList = [];
|
|
||||||
var k = 0;
|
|
||||||
var offset;
|
|
||||||
|
|
||||||
// XXX: rather than searching for the search term in the body,
|
|
||||||
// we should be looking at the match delimiters returned by the FTS engine
|
|
||||||
if (content.format === "org.matrix.custom.html") {
|
|
||||||
|
|
||||||
var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
|
|
||||||
var safeSearchTerm = sanitizeHtml(searchTerm, sanitizeHtmlParams);
|
|
||||||
while ((offset = safeBody.indexOf(safeSearchTerm, lastOffset)) >= 0) {
|
|
||||||
// FIXME: we need to apply the search highlighting to only the text elements of HTML, which means
|
|
||||||
// hooking into the sanitizer parser rather than treating it as a string. Otherwise
|
|
||||||
// the act of highlighting a <b/> or whatever will break the HTML badly.
|
|
||||||
bodyList.push(<span key={ k++ } dangerouslySetInnerHTML={{ __html: safeBody.substring(lastOffset, offset) }} />);
|
|
||||||
bodyList.push(<span key={ k++ } dangerouslySetInnerHTML={{ __html: safeSearchTerm }} className="mx_MessageTile_searchHighlight" />);
|
|
||||||
lastOffset = offset + safeSearchTerm.length;
|
|
||||||
}
|
|
||||||
bodyList.push(<span className="markdown-body" key={ k++ } dangerouslySetInnerHTML={{ __html: safeBody.substring(lastOffset) }} />);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
while ((offset = originalBody.indexOf(searchTerm, lastOffset)) >= 0) {
|
|
||||||
bodyList.push(<span key={ k++ } >{ originalBody.substring(lastOffset, offset) }</span>);
|
|
||||||
bodyList.push(<span key={ k++ } className="mx_MessageTile_searchHighlight">{ searchTerm }</span>);
|
|
||||||
lastOffset = offset + searchTerm.length;
|
|
||||||
}
|
|
||||||
bodyList.push(<span key={ k++ }>{ originalBody.substring(lastOffset) }</span>);
|
|
||||||
}
|
|
||||||
body = bodyList;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (content.format === "org.matrix.custom.html") {
|
|
||||||
var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams);
|
|
||||||
body = <span className="markdown-body" dangerouslySetInnerHTML={{ __html: safeBody }} />;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
body = originalBody;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return body;
|
|
||||||
},
|
|
||||||
|
|
||||||
highlightDom: function(element) {
|
|
||||||
var blocks = element.getElementsByTagName("code");
|
|
||||||
for (var i = 0; i < blocks.length; i++) {
|
|
||||||
highlight.highlightBlock(blocks[i]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
|||||||
var React = require('react');
|
|
||||||
var ReactDom = require('react-dom');
|
|
||||||
var Velocity = require('velocity-animate');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Velociraptor contains components and animates transitions with velocity.
|
|
||||||
* It will only pick up direct changes to properties ('left', currently), and so
|
|
||||||
* will not work for animating positional changes where the position is implicit
|
|
||||||
* from DOM order. This makes it a lot simpler and lighter: if you need fully
|
|
||||||
* automatic positional animation, look at react-shuffle or similar libraries.
|
|
||||||
*/
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'Velociraptor',
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
children: React.PropTypes.array,
|
|
||||||
transition: React.PropTypes.object,
|
|
||||||
container: React.PropTypes.string
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillMount: function() {
|
|
||||||
this.children = {};
|
|
||||||
this.nodes = {};
|
|
||||||
var self = this;
|
|
||||||
React.Children.map(this.props.children, function(c) {
|
|
||||||
self.children[c.key] = c;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillReceiveProps: function(nextProps) {
|
|
||||||
var self = this;
|
|
||||||
var oldChildren = this.children;
|
|
||||||
this.children = {};
|
|
||||||
React.Children.map(nextProps.children, function(c) {
|
|
||||||
if (oldChildren[c.key]) {
|
|
||||||
var old = oldChildren[c.key];
|
|
||||||
var oldNode = ReactDom.findDOMNode(self.nodes[old.key]);
|
|
||||||
|
|
||||||
if (oldNode.style.left != c.props.style.left) {
|
|
||||||
Velocity(oldNode, { left: c.props.style.left }, self.props.transition).then(function() {
|
|
||||||
// special case visibility because it's nonsensical to animate an invisible element
|
|
||||||
// so we always hidden->visible pre-transition and visible->hidden after
|
|
||||||
if (oldNode.style.visibility == 'visible' && c.props.style.visibility == 'hidden') {
|
|
||||||
oldNode.style.visibility = c.props.style.visibility;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (oldNode.style.visibility == 'hidden' && c.props.style.visibility == 'visible') {
|
|
||||||
oldNode.style.visibility = c.props.style.visibility;
|
|
||||||
}
|
|
||||||
//console.log("translation: "+oldNode.style.left+" -> "+c.props.style.left);
|
|
||||||
}
|
|
||||||
self.children[c.key] = old;
|
|
||||||
} else {
|
|
||||||
// new element. If it has a startStyle, use that as the style and go through
|
|
||||||
// the enter animations
|
|
||||||
var newProps = {
|
|
||||||
ref: self.collectNode.bind(self, c.key)
|
|
||||||
};
|
|
||||||
if (c.props.startStyle && Object.keys(c.props.startStyle).length) {
|
|
||||||
var startStyle = c.props.startStyle;
|
|
||||||
if (Array.isArray(startStyle)) {
|
|
||||||
startStyle = startStyle[0];
|
|
||||||
}
|
|
||||||
newProps._restingStyle = c.props.style;
|
|
||||||
newProps.style = startStyle;
|
|
||||||
//console.log("mounted@startstyle0: "+JSON.stringify(startStyle));
|
|
||||||
// apply the enter animations once it's mounted
|
|
||||||
}
|
|
||||||
self.children[c.key] = React.cloneElement(c, newProps);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
collectNode: function(k, node) {
|
|
||||||
if (
|
|
||||||
this.nodes[k] === undefined &&
|
|
||||||
node.props.startStyle &&
|
|
||||||
Object.keys(node.props.startStyle).length
|
|
||||||
) {
|
|
||||||
var domNode = ReactDom.findDOMNode(node);
|
|
||||||
var startStyles = node.props.startStyle;
|
|
||||||
var transitionOpts = node.props.enterTransitionOpts;
|
|
||||||
if (!Array.isArray(startStyles)) {
|
|
||||||
startStyles = [ startStyles ];
|
|
||||||
transitionOpts = [ transitionOpts ];
|
|
||||||
}
|
|
||||||
// start from startStyle 1: 0 is the one we gave it
|
|
||||||
// to start with, so now we animate 1 etc.
|
|
||||||
for (var i = 1; i < startStyles.length; ++i) {
|
|
||||||
Velocity(domNode, startStyles[i], transitionOpts[i-1]);
|
|
||||||
//console.log("start: "+JSON.stringify(startStyles[i]));
|
|
||||||
}
|
|
||||||
// and then we animate to the resting state
|
|
||||||
Velocity(domNode, node.props._restingStyle, transitionOpts[i-1]);
|
|
||||||
//console.log("enter: "+JSON.stringify(node.props._restingStyle));
|
|
||||||
}
|
|
||||||
this.nodes[k] = node;
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var self = this;
|
|
||||||
var childList = Object.keys(this.children).map(function(k) {
|
|
||||||
return React.cloneElement(self.children[k], {
|
|
||||||
ref: self.collectNode.bind(self, self.children[k].key)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{childList}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,15 +0,0 @@
|
|||||||
var Velocity = require('velocity-animate');
|
|
||||||
|
|
||||||
// courtesy of https://github.com/julianshapiro/velocity/issues/283
|
|
||||||
// We only use easeOutBounce (easeInBounce is just sort of nonsensical)
|
|
||||||
function bounce( p ) {
|
|
||||||
var pow2,
|
|
||||||
bounce = 4;
|
|
||||||
|
|
||||||
while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
|
|
||||||
return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
Velocity.Easings.easeOutBounce = function(p) {
|
|
||||||
return 1 - bounce(1 - p);
|
|
||||||
}
|
|
@ -57,8 +57,8 @@ module.exports = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var ChangeDisplayName = sdk.getComponent('molecules.ChangeDisplayName');
|
var ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName');
|
||||||
var ChangeAvatar = sdk.getComponent('molecules.ChangeAvatar');
|
var ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
|
||||||
return (
|
return (
|
||||||
<div className="mx_Login">
|
<div className="mx_Login">
|
||||||
<div className="mx_Login_box">
|
<div className="mx_Login_box">
|
||||||
|
@ -21,11 +21,10 @@ var DragSource = require('react-dnd').DragSource;
|
|||||||
var DropTarget = require('react-dnd').DropTarget;
|
var DropTarget = require('react-dnd').DropTarget;
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
|
|
||||||
var RoomTileController = require('matrix-react-sdk/lib/controllers/molecules/RoomTile')
|
var dis = require("matrix-react-sdk/lib/dispatcher");
|
||||||
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||||
|
var sdk = require('matrix-react-sdk');
|
||||||
var sdk = require('matrix-react-sdk')
|
var RoomTile = require('matrix-react-sdk/lib/components/views/rooms/RoomTile');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the drag source contract.
|
* Specifies the drag source contract.
|
||||||
@ -183,117 +182,6 @@ var roomTileTarget = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var RoomTile = React.createClass({
|
|
||||||
displayName: 'RoomTile',
|
|
||||||
mixins: [RoomTileController],
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
connectDragSource: React.PropTypes.func.isRequired,
|
|
||||||
connectDropTarget: React.PropTypes.func.isRequired,
|
|
||||||
isDragging: React.PropTypes.bool.isRequired,
|
|
||||||
room: React.PropTypes.object.isRequired,
|
|
||||||
collapsed: React.PropTypes.bool.isRequired,
|
|
||||||
selected: React.PropTypes.bool.isRequired,
|
|
||||||
unread: React.PropTypes.bool.isRequired,
|
|
||||||
highlight: React.PropTypes.bool.isRequired,
|
|
||||||
isInvite: React.PropTypes.bool.isRequired,
|
|
||||||
roomSubList: React.PropTypes.object.isRequired,
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState: function() {
|
|
||||||
return( { hover : false });
|
|
||||||
},
|
|
||||||
|
|
||||||
onMouseEnter: function() {
|
|
||||||
this.setState( { hover : true });
|
|
||||||
},
|
|
||||||
|
|
||||||
onMouseLeave: function() {
|
|
||||||
this.setState( { hover : false });
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
// if (this.props.clientOffset) {
|
|
||||||
// //console.log("room " + this.props.room.roomId + " has dropTarget clientOffset " + this.props.clientOffset.x + "," + this.props.clientOffset.y);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (this.props.room._dragging) {
|
|
||||||
var RoomDropTarget = sdk.getComponent("molecules.RoomDropTarget");
|
|
||||||
return <RoomDropTarget placeholder={true}/>;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
var myUserId = MatrixClientPeg.get().credentials.userId;
|
|
||||||
var me = this.props.room.currentState.members[myUserId];
|
|
||||||
var classes = classNames({
|
|
||||||
'mx_RoomTile': true,
|
|
||||||
'mx_RoomTile_selected': this.props.selected,
|
|
||||||
'mx_RoomTile_unread': this.props.unread,
|
|
||||||
'mx_RoomTile_highlight': this.props.highlight,
|
|
||||||
'mx_RoomTile_invited': (me && me.membership == 'invite'),
|
|
||||||
});
|
|
||||||
|
|
||||||
var name;
|
|
||||||
if (this.props.isInvite) {
|
|
||||||
name = this.props.room.getMember(myUserId).events.member.getSender();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// XXX: We should never display raw room IDs, but sometimes the room name js sdk gives is undefined
|
|
||||||
name = this.props.room.name || this.props.room.roomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon
|
|
||||||
var badge;
|
|
||||||
if (this.props.highlight) {
|
|
||||||
badge = <div className="mx_RoomTile_badge"/>;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if (this.props.highlight) {
|
|
||||||
badge = <div className="mx_RoomTile_badge">!</div>;
|
|
||||||
}
|
|
||||||
else if (this.props.unread) {
|
|
||||||
badge = <div className="mx_RoomTile_badge">1</div>;
|
|
||||||
}
|
|
||||||
var nameCell;
|
|
||||||
if (badge) {
|
|
||||||
nameCell = <div className="mx_RoomTile_nameBadge"><div className="mx_RoomTile_name">{name}</div><div className="mx_RoomTile_badgeCell">{badge}</div></div>;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nameCell = <div className="mx_RoomTile_name">{name}</div>;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
var label;
|
|
||||||
if (!this.props.collapsed) {
|
|
||||||
var className = 'mx_RoomTile_name' + (this.props.isInvite ? ' mx_RoomTile_invite' : '');
|
|
||||||
label = <div className={ className }>{name}</div>;
|
|
||||||
}
|
|
||||||
else if (this.state.hover) {
|
|
||||||
var RoomTooltip = sdk.getComponent("molecules.RoomTooltip");
|
|
||||||
label = <RoomTooltip room={this.props.room}/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
var RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
|
|
||||||
|
|
||||||
// These props are injected by React DnD,
|
|
||||||
// as defined by your `collect` function above:
|
|
||||||
var isDragging = this.props.isDragging;
|
|
||||||
var connectDragSource = this.props.connectDragSource;
|
|
||||||
var connectDropTarget = this.props.connectDropTarget;
|
|
||||||
|
|
||||||
return connectDragSource(connectDropTarget(
|
|
||||||
<div className={classes} onClick={this.onClick} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
|
||||||
<div className="mx_RoomTile_avatar">
|
|
||||||
<RoomAvatar room={this.props.room} width="24" height="24" />
|
|
||||||
{ badge }
|
|
||||||
</div>
|
|
||||||
{ label }
|
|
||||||
</div>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Export the wrapped version, inlining the 'collect' functions
|
// Export the wrapped version, inlining the 'collect' functions
|
||||||
// to more closely resemble the ES7
|
// to more closely resemble the ES7
|
||||||
module.exports =
|
module.exports =
|
@ -470,7 +470,7 @@ module.exports = {
|
|||||||
var ret = [];
|
var ret = [];
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
var EventTile = sdk.getComponent('molecules.EventTile');
|
var EventTile = sdk.getComponent('messages.Event');
|
||||||
|
|
||||||
if (this.state.searchResults) {
|
if (this.state.searchResults) {
|
||||||
// XXX: this dance is foul, due to the results API not returning sorted results
|
// XXX: this dance is foul, due to the results API not returning sorted results
|
||||||
|
@ -27,53 +27,61 @@ var skin = {};
|
|||||||
skin['elements.Spinner'] = require('../../components/views/elements/Spinner');
|
skin['elements.Spinner'] = require('../../components/views/elements/Spinner');
|
||||||
skin['elements.ImageView'] = require('../../components/views/elements/ImageView');
|
skin['elements.ImageView'] = require('../../components/views/elements/ImageView');
|
||||||
skin['messages.MessageTimestamp'] = require('../../components/views/messages/MessageTimestamp');
|
skin['messages.MessageTimestamp'] = require('../../components/views/messages/MessageTimestamp');
|
||||||
|
skin['rooms.RoomTile'] = require('../../components/views/rooms/RoomDNDView');
|
||||||
|
|
||||||
// TODO: Fix this so matrix-react-sdk stuff is in react SDK skindex?
|
// TODO: Fix this so matrix-react-sdk stuff is in react SDK skindex?
|
||||||
skin['avatars.RoomAvatar'] = require('matrix-react-sdk/lib/components/views/avatars/RoomAvatar');
|
skin['avatars.RoomAvatar'] = require('matrix-react-sdk/lib/components/views/avatars/RoomAvatar');
|
||||||
skin['avatars.MemberAvatar'] = require('matrix-react-sdk/lib/components/views/avatars/MemberAvatar');
|
skin['avatars.MemberAvatar'] = require('matrix-react-sdk/lib/components/views/avatars/MemberAvatar');
|
||||||
|
|
||||||
skin['settings.EnableNotificationsButton'] = require('matrix-react-sdk/lib/components/views/settings/EnableNotificationsButton');
|
skin['settings.EnableNotificationsButton'] = require('matrix-react-sdk/lib/components/views/settings/EnableNotificationsButton');
|
||||||
|
skin['settings.ChangeAvatar'] = require('matrix-react-sdk/lib/components/views/settings/ChangeAvatar');
|
||||||
|
skin['settings.ChangeDisplayName'] = require('matrix-react-sdk/lib/components/views/settings/ChangeDisplayName');
|
||||||
|
skin['settings.ChangePassword'] = require('matrix-react-sdk/lib/components/views/settings/ChangePassword');
|
||||||
|
|
||||||
skin['elements.EditableText'] = require('matrix-react-sdk/lib/components/views/elements/EditableText');
|
skin['elements.EditableText'] = require('matrix-react-sdk/lib/components/views/elements/EditableText');
|
||||||
skin['voip.VideoFeed'] = require('matrix-react-sdk/lib/components/views/voip/VideoFeed');
|
skin['elements.ProgressBar'] = require('matrix-react-sdk/lib/components/views/elements/ProgressBar');
|
||||||
|
skin['elements.UserSelector'] = require('matrix-react-sdk/lib/components/views/elements/UserSelector');
|
||||||
|
|
||||||
|
skin['messages.MessageComposer'] = require('matrix-react-sdk/lib/components/views/messages/MessageComposer');
|
||||||
|
skin['messages.TextualEvent'] = require('matrix-react-sdk/lib/components/views/messages/TextualEvent');
|
||||||
|
skin['messages.MRoomMemberEvent'] = require('matrix-react-sdk/lib/components/views/messages/MRoomMemberEvent');
|
||||||
|
skin['messages.Event'] = require('matrix-react-sdk/lib/components/views/messages/Event');
|
||||||
|
skin['messages.Message'] = require('matrix-react-sdk/lib/components/views/messages/Message');
|
||||||
|
skin['messages.MEmoteMessage'] = require('matrix-react-sdk/lib/components/views/messages/MEmoteMessage');
|
||||||
|
skin['messages.MFileMessage'] = require('matrix-react-sdk/lib/components/views/messages/MFileMessage');
|
||||||
|
skin['messages.MImageMessage'] = require('matrix-react-sdk/lib/components/views/messages/MImageMessage');
|
||||||
|
skin['messages.MNoticeMessage'] = require('matrix-react-sdk/lib/components/views/messages/MNoticeMessage');
|
||||||
|
skin['messages.MTextMessage'] = require('matrix-react-sdk/lib/components/views/messages/MTextMessage');
|
||||||
|
skin['messages.MVideoMessage'] = require('matrix-react-sdk/lib/components/views/messages/MVideoMessage');
|
||||||
|
skin['messages.UnknownMessage'] = require('matrix-react-sdk/lib/components/views/messages/UnknownMessage');
|
||||||
|
|
||||||
|
skin['rooms.MemberInfo'] = require('matrix-react-sdk/lib/components/views/rooms/MemberInfo');
|
||||||
|
skin['rooms.RoomHeader'] = require('matrix-react-sdk/lib/components/views/rooms/RoomHeader');
|
||||||
|
skin['rooms.RoomSettings'] = require('matrix-react-sdk/lib/components/views/rooms/RoomSettings');
|
||||||
|
skin['rooms.MemberTile'] = require('matrix-react-sdk/lib/components/views/rooms/MemberTile');
|
||||||
|
|
||||||
skin['create_room.CreateRoomButton'] = require('matrix-react-sdk/lib/components/views/create_room/CreateRoomButton');
|
skin['create_room.CreateRoomButton'] = require('matrix-react-sdk/lib/components/views/create_room/CreateRoomButton');
|
||||||
skin['create_room.Presets'] = require('matrix-react-sdk/lib/components/views/create_room/Presets');
|
skin['create_room.Presets'] = require('matrix-react-sdk/lib/components/views/create_room/Presets');
|
||||||
skin['create_room.RoomAlias'] = require('matrix-react-sdk/lib/components/views/create_room/RoomAlias');
|
skin['create_room.RoomAlias'] = require('matrix-react-sdk/lib/components/views/create_room/RoomAlias');
|
||||||
|
|
||||||
skin['voip.CallView'] = require('matrix-react-sdk/lib/components/views/voip/CallView');
|
skin['voip.CallView'] = require('matrix-react-sdk/lib/components/views/voip/CallView');
|
||||||
skin['voip.IncomingCallBox'] = require('matrix-react-sdk/lib/components/views/voip/IncomingCallBox');
|
skin['voip.IncomingCallBox'] = require('matrix-react-sdk/lib/components/views/voip/IncomingCallBox');
|
||||||
skin['voip.VideoView'] = require('matrix-react-sdk/lib/components/views/voip/VideoView');
|
skin['voip.VideoView'] = require('matrix-react-sdk/lib/components/views/voip/VideoView');
|
||||||
|
skin['voip.VideoFeed'] = require('matrix-react-sdk/lib/components/views/voip/VideoFeed');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Old style stuff
|
// Old style stuff
|
||||||
skin['molecules.BottomLeftMenu'] = require('./views/molecules/BottomLeftMenu');
|
skin['molecules.BottomLeftMenu'] = require('./views/molecules/BottomLeftMenu');
|
||||||
skin['molecules.BottomLeftMenuTile'] = require('./views/molecules/BottomLeftMenuTile');
|
skin['molecules.BottomLeftMenuTile'] = require('./views/molecules/BottomLeftMenuTile');
|
||||||
skin['molecules.ChangeAvatar'] = require('./views/molecules/ChangeAvatar');
|
|
||||||
skin['molecules.ChangeDisplayName'] = require('./views/molecules/ChangeDisplayName');
|
|
||||||
skin['molecules.ChangePassword'] = require('./views/molecules/ChangePassword');
|
|
||||||
skin['molecules.DateSeparator'] = require('./views/molecules/DateSeparator');
|
skin['molecules.DateSeparator'] = require('./views/molecules/DateSeparator');
|
||||||
skin['molecules.EventAsTextTile'] = require('./views/molecules/EventAsTextTile');
|
|
||||||
skin['molecules.EventTile'] = require('./views/molecules/EventTile');
|
|
||||||
skin['molecules.MEmoteTile'] = require('./views/molecules/MEmoteTile');
|
|
||||||
skin['molecules.MFileTile'] = require('./views/molecules/MFileTile');
|
|
||||||
skin['molecules.MImageTile'] = require('./views/molecules/MImageTile');
|
|
||||||
skin['molecules.MNoticeTile'] = require('./views/molecules/MNoticeTile');
|
|
||||||
skin['molecules.MRoomMemberTile'] = require('./views/molecules/MRoomMemberTile');
|
|
||||||
skin['molecules.MTextTile'] = require('./views/molecules/MTextTile');
|
|
||||||
skin['molecules.MVideoTile'] = require('./views/molecules/MVideoTile');
|
|
||||||
skin['molecules.MatrixToolbar'] = require('./views/molecules/MatrixToolbar');
|
skin['molecules.MatrixToolbar'] = require('./views/molecules/MatrixToolbar');
|
||||||
skin['molecules.MemberInfo'] = require('./views/molecules/MemberInfo');
|
|
||||||
skin['molecules.MemberTile'] = require('./views/molecules/MemberTile');
|
|
||||||
skin['molecules.MessageComposer'] = require('./views/molecules/MessageComposer');
|
|
||||||
skin['molecules.MessageContextMenu'] = require('./views/molecules/MessageContextMenu');
|
skin['molecules.MessageContextMenu'] = require('./views/molecules/MessageContextMenu');
|
||||||
skin['molecules.MessageTile'] = require('./views/molecules/MessageTile');
|
|
||||||
skin['molecules.ProgressBar'] = require('./views/molecules/ProgressBar');
|
|
||||||
skin['molecules.RoomCreate'] = require('./views/molecules/RoomCreate');
|
skin['molecules.RoomCreate'] = require('./views/molecules/RoomCreate');
|
||||||
skin['molecules.RoomDropTarget'] = require('./views/molecules/RoomDropTarget');
|
skin['molecules.RoomDropTarget'] = require('./views/molecules/RoomDropTarget');
|
||||||
skin['molecules.RoomHeader'] = require('./views/molecules/RoomHeader');
|
|
||||||
skin['molecules.RoomSettings'] = require('./views/molecules/RoomSettings');
|
|
||||||
skin['molecules.RoomTile'] = require('./views/molecules/RoomTile');
|
|
||||||
skin['molecules.RoomTooltip'] = require('./views/molecules/RoomTooltip');
|
skin['molecules.RoomTooltip'] = require('./views/molecules/RoomTooltip');
|
||||||
skin['molecules.SearchBar'] = require('./views/molecules/SearchBar');
|
skin['molecules.SearchBar'] = require('./views/molecules/SearchBar');
|
||||||
skin['molecules.SenderProfile'] = require('./views/molecules/SenderProfile');
|
skin['molecules.SenderProfile'] = require('./views/molecules/SenderProfile');
|
||||||
skin['molecules.UnknownMessageTile'] = require('./views/molecules/UnknownMessageTile');
|
|
||||||
skin['molecules.UserSelector'] = require('./views/molecules/UserSelector');
|
|
||||||
skin['organisms.CreateRoom'] = require('./views/organisms/CreateRoom');
|
skin['organisms.CreateRoom'] = require('./views/organisms/CreateRoom');
|
||||||
skin['organisms.ErrorDialog'] = require('./views/organisms/ErrorDialog');
|
skin['organisms.ErrorDialog'] = require('./views/organisms/ErrorDialog');
|
||||||
skin['organisms.LeftPanel'] = require('./views/organisms/LeftPanel');
|
skin['organisms.LeftPanel'] = require('./views/organisms/LeftPanel');
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
var ChangeAvatarController = require('matrix-react-sdk/lib/controllers/molecules/ChangeAvatar')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'ChangeAvatar',
|
|
||||||
mixins: [ChangeAvatarController],
|
|
||||||
|
|
||||||
onFileSelected: function(ev) {
|
|
||||||
this.avatarSet = true;
|
|
||||||
this.setAvatarFromFile(ev.target.files[0]);
|
|
||||||
},
|
|
||||||
|
|
||||||
onError: function(error) {
|
|
||||||
this.setState({
|
|
||||||
errorText: "Failed to upload profile picture!"
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
|
|
||||||
var avatarImg;
|
|
||||||
// Having just set an avatar we just display that since it will take a little
|
|
||||||
// time to propagate through to the RoomAvatar.
|
|
||||||
if (this.props.room && !this.avatarSet) {
|
|
||||||
avatarImg = <RoomAvatar room={this.props.room} width='320' height='240' resizeMethod='scale' />;
|
|
||||||
} else {
|
|
||||||
var style = {
|
|
||||||
maxWidth: 320,
|
|
||||||
maxHeight: 240,
|
|
||||||
};
|
|
||||||
avatarImg = <img src={this.state.avatarUrl} style={style} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (this.state.phase) {
|
|
||||||
case this.Phases.Display:
|
|
||||||
case this.Phases.Error:
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="mx_Dialog_content">
|
|
||||||
{avatarImg}
|
|
||||||
</div>
|
|
||||||
<div className="mx_Dialog_content">
|
|
||||||
Upload new:
|
|
||||||
<input type="file" onChange={this.onFileSelected}/>
|
|
||||||
{this.state.errorText}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case this.Phases.Uploading:
|
|
||||||
var Loader = sdk.getComponent("elements.Spinner");
|
|
||||||
return (
|
|
||||||
<Loader />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var sdk = require('matrix-react-sdk');
|
|
||||||
|
|
||||||
var ChangeDisplayNameController = require("matrix-react-sdk/lib/controllers/molecules/ChangeDisplayName");
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'ChangeDisplayName',
|
|
||||||
mixins: [ChangeDisplayNameController],
|
|
||||||
|
|
||||||
edit: function() {
|
|
||||||
this.refs.displayname_edit.edit()
|
|
||||||
},
|
|
||||||
|
|
||||||
onValueChanged: function(new_value, shouldSubmit) {
|
|
||||||
if (shouldSubmit) {
|
|
||||||
this.changeDisplayname(new_value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
if (this.state.busy) {
|
|
||||||
var Loader = sdk.getComponent("elements.Spinner");
|
|
||||||
return (
|
|
||||||
<Loader />
|
|
||||||
);
|
|
||||||
} else if (this.state.errorString) {
|
|
||||||
return (
|
|
||||||
<div className="error">{this.state.errorString}</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
var EditableText = sdk.getComponent('elements.EditableText');
|
|
||||||
return (
|
|
||||||
<EditableText ref="displayname_edit" initialValue={this.state.displayName} label="Click to set display name." onValueChanged={this.onValueChanged}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var ChangePasswordController = require('matrix-react-sdk/lib/controllers/molecules/ChangePassword')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'ChangePassword',
|
|
||||||
mixins: [ChangePasswordController],
|
|
||||||
|
|
||||||
onClickChange: function() {
|
|
||||||
var old_password = this.refs.old_input.value;
|
|
||||||
var new_password = this.refs.new_input.value;
|
|
||||||
var confirm_password = this.refs.confirm_input.value;
|
|
||||||
if (new_password != confirm_password) {
|
|
||||||
this.setState({
|
|
||||||
state: this.Phases.Error,
|
|
||||||
errorString: "Passwords don't match"
|
|
||||||
});
|
|
||||||
} else if (new_password == '' || old_password == '') {
|
|
||||||
this.setState({
|
|
||||||
state: this.Phases.Error,
|
|
||||||
errorString: "Passwords can't be empty"
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.changePassword(old_password, new_password);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
switch (this.state.phase) {
|
|
||||||
case this.Phases.Edit:
|
|
||||||
case this.Phases.Error:
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="mx_Dialog_content">
|
|
||||||
<div>{this.state.errorString}</div>
|
|
||||||
<div><label>Old password <input type="password" ref="old_input"/></label></div>
|
|
||||||
<div><label>New password <input type="password" ref="new_input"/></label></div>
|
|
||||||
<div><label>Confirm password <input type="password" ref="confirm_input"/></label></div>
|
|
||||||
</div>
|
|
||||||
<div className="mx_Dialog_buttons">
|
|
||||||
<button onClick={this.onClickChange}>Change Password</button>
|
|
||||||
<button onClick={this.props.onFinished}>Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case this.Phases.Uploading:
|
|
||||||
var Loader = sdk.getComponent("elements.Spinner");
|
|
||||||
return (
|
|
||||||
<div className="mx_Dialog_content">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case this.Phases.Success:
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="mx_Dialog_content">
|
|
||||||
Success!
|
|
||||||
</div>
|
|
||||||
<div className="mx_Dialog_buttons">
|
|
||||||
<button onClick={this.props.onFinished}>Ok</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var TextForEvent = require('matrix-react-sdk/lib/TextForEvent');
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'EventAsTextTile',
|
|
||||||
|
|
||||||
statics: {
|
|
||||||
needsSenderProfile: function() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var text = TextForEvent.textForEvent(this.props.mxEvent);
|
|
||||||
if (text == null || text.length == 0) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mx_EventAsTextTile">
|
|
||||||
{TextForEvent.textForEvent(this.props.mxEvent)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,274 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var ReactDom = require('react-dom');
|
|
||||||
var classNames = require("classnames");
|
|
||||||
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg')
|
|
||||||
|
|
||||||
var EventTileController = require('matrix-react-sdk/lib/controllers/molecules/EventTile')
|
|
||||||
var ContextualMenu = require('../../../../ContextualMenu');
|
|
||||||
|
|
||||||
var TextForEvent = require('matrix-react-sdk/lib/TextForEvent');
|
|
||||||
|
|
||||||
var Velociraptor = require('../../../../Velociraptor');
|
|
||||||
require('../../../../VelocityBounce');
|
|
||||||
|
|
||||||
var bounce = false;
|
|
||||||
try {
|
|
||||||
if (global.localStorage) {
|
|
||||||
bounce = global.localStorage.getItem('avatar_bounce') == 'true';
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventTileTypes = {
|
|
||||||
'm.room.message': 'molecules.MessageTile',
|
|
||||||
'm.room.member' : 'molecules.EventAsTextTile',
|
|
||||||
'm.call.invite' : 'molecules.EventAsTextTile',
|
|
||||||
'm.call.answer' : 'molecules.EventAsTextTile',
|
|
||||||
'm.call.hangup' : 'molecules.EventAsTextTile',
|
|
||||||
'm.room.name' : 'molecules.EventAsTextTile',
|
|
||||||
'm.room.topic' : 'molecules.EventAsTextTile',
|
|
||||||
};
|
|
||||||
|
|
||||||
var MAX_READ_AVATARS = 5;
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'EventTile',
|
|
||||||
mixins: [EventTileController],
|
|
||||||
|
|
||||||
statics: {
|
|
||||||
haveTileForEvent: function(e) {
|
|
||||||
if (eventTileTypes[e.getType()] == undefined) return false;
|
|
||||||
if (eventTileTypes[e.getType()] == 'molecules.EventAsTextTile') {
|
|
||||||
return TextForEvent.textForEvent(e) !== '';
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState: function() {
|
|
||||||
return {menu: false, allReadAvatars: false};
|
|
||||||
},
|
|
||||||
|
|
||||||
onEditClicked: function(e) {
|
|
||||||
var MessageContextMenu = sdk.getComponent('molecules.MessageContextMenu');
|
|
||||||
var buttonRect = e.target.getBoundingClientRect()
|
|
||||||
var x = buttonRect.right;
|
|
||||||
var y = buttonRect.top + (e.target.height / 2);
|
|
||||||
var self = this;
|
|
||||||
ContextualMenu.createMenu(MessageContextMenu, {
|
|
||||||
mxEvent: this.props.mxEvent,
|
|
||||||
left: x,
|
|
||||||
top: y,
|
|
||||||
onFinished: function() {
|
|
||||||
self.setState({menu: false});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.setState({menu: true});
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleAllReadAvatars: function() {
|
|
||||||
this.setState({
|
|
||||||
allReadAvatars: !this.state.allReadAvatars
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
getReadAvatars: function() {
|
|
||||||
var avatars = [];
|
|
||||||
|
|
||||||
var room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
|
|
||||||
|
|
||||||
if (!room) return [];
|
|
||||||
|
|
||||||
var myUserId = MatrixClientPeg.get().credentials.userId;
|
|
||||||
|
|
||||||
// get list of read receipts, sorted most recent first
|
|
||||||
var receipts = room.getReceiptsForEvent(this.props.mxEvent).filter(function(r) {
|
|
||||||
return r.type === "m.read" && r.userId != myUserId;
|
|
||||||
}).sort(function(r1, r2) {
|
|
||||||
return r2.data.ts - r1.data.ts;
|
|
||||||
});
|
|
||||||
|
|
||||||
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
|
||||||
|
|
||||||
var left = 0;
|
|
||||||
|
|
||||||
var reorderTransitionOpts = {
|
|
||||||
duration: 100,
|
|
||||||
easing: 'easeOut'
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var i = 0; i < receipts.length; ++i) {
|
|
||||||
var member = room.getMember(receipts[i].userId);
|
|
||||||
|
|
||||||
// Using react refs here would mean both getting Velociraptor to expose
|
|
||||||
// them and making them scoped to the whole RoomView. Not impossible, but
|
|
||||||
// getElementById seems simpler at least for a first cut.
|
|
||||||
var oldAvatarDomNode = document.getElementById('mx_readAvatar'+member.userId);
|
|
||||||
var startStyles = [];
|
|
||||||
var enterTransitionOpts = [];
|
|
||||||
var oldNodeTop = -15; // For avatars that weren't on screen, act as if they were just off the top
|
|
||||||
if (oldAvatarDomNode) {
|
|
||||||
oldNodeTop = oldAvatarDomNode.getBoundingClientRect().top;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.readAvatarNode) {
|
|
||||||
var topOffset = oldNodeTop - this.readAvatarNode.getBoundingClientRect().top;
|
|
||||||
|
|
||||||
if (oldAvatarDomNode && oldAvatarDomNode.style.left !== '0px') {
|
|
||||||
var leftOffset = oldAvatarDomNode.style.left;
|
|
||||||
// start at the old height and in the old h pos
|
|
||||||
startStyles.push({ top: topOffset, left: leftOffset });
|
|
||||||
enterTransitionOpts.push(reorderTransitionOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// then shift to the rightmost column,
|
|
||||||
// and then it will drop down to its resting position
|
|
||||||
startStyles.push({ top: topOffset, left: '0px' });
|
|
||||||
enterTransitionOpts.push({
|
|
||||||
duration: bounce ? Math.min(Math.log(Math.abs(topOffset)) * 200, 3000) : 300,
|
|
||||||
easing: bounce ? 'easeOutBounce' : 'easeOutCubic',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var style = {
|
|
||||||
left: left+'px',
|
|
||||||
top: '0px',
|
|
||||||
visibility: ((i < MAX_READ_AVATARS) || this.state.allReadAvatars) ? 'visible' : 'hidden'
|
|
||||||
};
|
|
||||||
|
|
||||||
//console.log("i = " + i + ", MAX_READ_AVATARS = " + MAX_READ_AVATARS + ", allReadAvatars = " + this.state.allReadAvatars + " visibility = " + style.visibility);
|
|
||||||
|
|
||||||
// add to the start so the most recent is on the end (ie. ends up rightmost)
|
|
||||||
avatars.unshift(
|
|
||||||
<MemberAvatar key={member.userId} member={member}
|
|
||||||
width={14} height={14} resizeMethod="crop"
|
|
||||||
style={style}
|
|
||||||
startStyle={startStyles}
|
|
||||||
enterTransitionOpts={enterTransitionOpts}
|
|
||||||
id={'mx_readAvatar'+member.userId}
|
|
||||||
onClick={this.toggleAllReadAvatars}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
// TODO: we keep the extra read avatars in the dom to make animation simpler
|
|
||||||
// we could optimise this to reduce the dom size.
|
|
||||||
if (i < MAX_READ_AVATARS - 1 || this.state.allReadAvatars) { // XXX: where does this -1 come from? is it to make the max'th avatar animate properly?
|
|
||||||
left -= 15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var editButton;
|
|
||||||
if (!this.state.allReadAvatars) {
|
|
||||||
var remainder = receipts.length - MAX_READ_AVATARS;
|
|
||||||
var remText;
|
|
||||||
if (i >= MAX_READ_AVATARS - 1) left -= 15;
|
|
||||||
if (remainder > 0) {
|
|
||||||
remText = <span className="mx_EventTile_readAvatarRemainder"
|
|
||||||
onClick={this.toggleAllReadAvatars}
|
|
||||||
style={{ left: left }}>{ remainder }+
|
|
||||||
</span>;
|
|
||||||
left -= 15;
|
|
||||||
}
|
|
||||||
editButton = (
|
|
||||||
<input style={{ left: left }}
|
|
||||||
type="image" src="img/edit.png" alt="Options" title="Options" width="14" height="14"
|
|
||||||
className="mx_EventTile_editButton" onClick={this.onEditClicked} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <span className="mx_EventTile_readAvatars" ref={this.collectReadAvatarNode}>
|
|
||||||
{ editButton }
|
|
||||||
{ remText }
|
|
||||||
<Velociraptor transition={ reorderTransitionOpts }>
|
|
||||||
{ avatars }
|
|
||||||
</Velociraptor>
|
|
||||||
</span>;
|
|
||||||
},
|
|
||||||
|
|
||||||
collectReadAvatarNode: function(node) {
|
|
||||||
this.readAvatarNode = ReactDom.findDOMNode(node);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var MessageTimestamp = sdk.getComponent('messages.MessageTimestamp');
|
|
||||||
var SenderProfile = sdk.getComponent('molecules.SenderProfile');
|
|
||||||
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
|
||||||
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
var msgtype = content.msgtype;
|
|
||||||
|
|
||||||
var EventTileType = sdk.getComponent(eventTileTypes[this.props.mxEvent.getType()]);
|
|
||||||
// This shouldn't happen: the caller should check we support this type
|
|
||||||
// before trying to instantiate us
|
|
||||||
if (!EventTileType) {
|
|
||||||
throw new Error("Event type not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
var classes = classNames({
|
|
||||||
mx_EventTile: true,
|
|
||||||
mx_EventTile_sending: ['sending', 'queued'].indexOf(
|
|
||||||
this.props.mxEvent.status
|
|
||||||
) !== -1,
|
|
||||||
mx_EventTile_notSent: this.props.mxEvent.status == 'not_sent',
|
|
||||||
mx_EventTile_highlight: this.shouldHighlight(),
|
|
||||||
mx_EventTile_continuation: this.props.continuation,
|
|
||||||
mx_EventTile_last: this.props.last,
|
|
||||||
mx_EventTile_contextual: this.props.contextual,
|
|
||||||
menu: this.state.menu,
|
|
||||||
});
|
|
||||||
var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />
|
|
||||||
|
|
||||||
var aux = null;
|
|
||||||
if (msgtype === 'm.image') aux = "sent an image";
|
|
||||||
else if (msgtype === 'm.video') aux = "sent a video";
|
|
||||||
else if (msgtype === 'm.file') aux = "uploaded a file";
|
|
||||||
|
|
||||||
var readAvatars = this.getReadAvatars();
|
|
||||||
|
|
||||||
var avatar, sender;
|
|
||||||
if (!this.props.continuation) {
|
|
||||||
if (this.props.mxEvent.sender) {
|
|
||||||
avatar = (
|
|
||||||
<div className="mx_EventTile_avatar">
|
|
||||||
<MemberAvatar member={this.props.mxEvent.sender} width={24} height={24} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (EventTileType.needsSenderProfile()) {
|
|
||||||
sender = <SenderProfile mxEvent={this.props.mxEvent} aux={aux} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className={classes}>
|
|
||||||
<div className="mx_EventTile_msgOption">
|
|
||||||
{ timestamp }
|
|
||||||
{ readAvatars }
|
|
||||||
</div>
|
|
||||||
{ avatar }
|
|
||||||
{ sender }
|
|
||||||
<div className="mx_EventTile_line">
|
|
||||||
<EventTileType mxEvent={this.props.mxEvent} searchTerm={this.props.searchTerm} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var MEmoteTileController = require('matrix-react-sdk/lib/controllers/molecules/MEmoteTile')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MEmoteTile',
|
|
||||||
mixins: [MEmoteTileController],
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var mxEvent = this.props.mxEvent;
|
|
||||||
var content = mxEvent.getContent();
|
|
||||||
var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
|
||||||
return (
|
|
||||||
<span ref="content" className="mx_MEmoteTile mx_MessageTile_content">
|
|
||||||
* {name} {content.body}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var MFileTileController = require('matrix-react-sdk/lib/controllers/molecules/MFileTile')
|
|
||||||
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MFileTile',
|
|
||||||
mixins: [MFileTileController],
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
var cli = MatrixClientPeg.get();
|
|
||||||
|
|
||||||
var httpUrl = cli.mxcUrlToHttp(content.url);
|
|
||||||
var text = this.presentableTextForFile(content);
|
|
||||||
|
|
||||||
if (httpUrl) {
|
|
||||||
return (
|
|
||||||
<span className="mx_MFileTile">
|
|
||||||
<div className="mx_MImageTile_download">
|
|
||||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
|
||||||
<img src="img/download.png" width="10" height="12"/>
|
|
||||||
Download {text}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
var extra = text ? ': '+text : '';
|
|
||||||
return <span className="mx_MFileTile">
|
|
||||||
Invalid file{extra}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var filesize = require('filesize');
|
|
||||||
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
|
||||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MImageTile',
|
|
||||||
|
|
||||||
thumbHeight: function(fullWidth, fullHeight, thumbWidth, thumbHeight) {
|
|
||||||
if (!fullWidth || !fullHeight) {
|
|
||||||
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
|
|
||||||
// log this because it's spammy
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (fullWidth < thumbWidth && fullHeight < thumbHeight) {
|
|
||||||
// no scaling needs to be applied
|
|
||||||
return fullHeight;
|
|
||||||
}
|
|
||||||
var widthMulti = thumbWidth / fullWidth;
|
|
||||||
var heightMulti = thumbHeight / fullHeight;
|
|
||||||
if (widthMulti < heightMulti) {
|
|
||||||
// width is the dominant dimension so scaling will be fixed on that
|
|
||||||
return Math.floor(widthMulti * fullHeight);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// height is the dominant dimension so scaling will be fixed on that
|
|
||||||
return Math.floor(heightMulti * fullHeight);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function(ev) {
|
|
||||||
if (ev.button == 0 && !ev.metaKey) {
|
|
||||||
ev.preventDefault();
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
var httpUrl = MatrixClientPeg.get().mxcUrlToHttp(content.url);
|
|
||||||
var ImageView = sdk.getComponent("elements.ImageView");
|
|
||||||
Modal.createDialog(ImageView, {
|
|
||||||
src: httpUrl,
|
|
||||||
width: content.info.w,
|
|
||||||
height: content.info.h,
|
|
||||||
mxEvent: this.props.mxEvent,
|
|
||||||
}, "mx_Dialog_lightbox");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_isGif: function() {
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
return (content && content.info && content.info.mimetype === "image/gif");
|
|
||||||
},
|
|
||||||
|
|
||||||
onImageEnter: function(e) {
|
|
||||||
if (!this._isGif()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var imgElement = e.target;
|
|
||||||
imgElement.src = MatrixClientPeg.get().mxcUrlToHttp(
|
|
||||||
this.props.mxEvent.getContent().url
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
onImageLeave: function(e) {
|
|
||||||
if (!this._isGif()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var imgElement = e.target;
|
|
||||||
imgElement.src = this._getThumbUrl();
|
|
||||||
},
|
|
||||||
|
|
||||||
_getThumbUrl: function() {
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
return MatrixClientPeg.get().mxcUrlToHttp(content.url, 480, 360);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
var cli = MatrixClientPeg.get();
|
|
||||||
|
|
||||||
var thumbHeight = null;
|
|
||||||
if (content.info) thumbHeight = this.thumbHeight(content.info.w, content.info.h, 480, 360);
|
|
||||||
|
|
||||||
var imgStyle = {};
|
|
||||||
if (thumbHeight) imgStyle['height'] = thumbHeight;
|
|
||||||
|
|
||||||
var thumbUrl = this._getThumbUrl();
|
|
||||||
if (thumbUrl) {
|
|
||||||
return (
|
|
||||||
<span className="mx_MImageTile">
|
|
||||||
<a href={cli.mxcUrlToHttp(content.url)} onClick={ this.onClick }>
|
|
||||||
<img className="mx_MImageTile_thumbnail" src={thumbUrl}
|
|
||||||
alt={content.body} style={imgStyle}
|
|
||||||
onMouseEnter={this.onImageEnter}
|
|
||||||
onMouseLeave={this.onImageLeave} />
|
|
||||||
</a>
|
|
||||||
<div className="mx_MImageTile_download">
|
|
||||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
|
||||||
<img src="img/download.png" width="10" height="12"/>
|
|
||||||
Download {content.body} ({ content.info && content.info.size ? filesize(content.info.size) : "Unknown size" })
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
} else if (content.body) {
|
|
||||||
return (
|
|
||||||
<span className="mx_MImageTile">
|
|
||||||
Image '{content.body}' cannot be displayed.
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<span className="mx_MImageTile">
|
|
||||||
This image cannot be displayed.
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var HtmlUtils = require('../../../../HtmlUtils');
|
|
||||||
|
|
||||||
var MNoticeTileController = require('matrix-react-sdk/lib/controllers/molecules/MNoticeTile')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MNoticeTile',
|
|
||||||
mixins: [MNoticeTileController],
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
if (this.props.mxEvent.getContent().format === "org.matrix.custom.html")
|
|
||||||
HtmlUtils.highlightDom(this.getDOMNode());
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate: function() {
|
|
||||||
if (this.props.mxEvent.getContent().format === "org.matrix.custom.html")
|
|
||||||
HtmlUtils.highlightDom(this.getDOMNode());
|
|
||||||
},
|
|
||||||
|
|
||||||
shouldComponentUpdate: function(nextProps) {
|
|
||||||
// exploit that events are immutable :)
|
|
||||||
return (nextProps.mxEvent.getId() !== this.props.mxEvent.getId() ||
|
|
||||||
nextProps.searchTerm !== this.props.searchTerm);
|
|
||||||
},
|
|
||||||
|
|
||||||
// XXX: fix horrible duplication with MTextTile
|
|
||||||
render: function() {
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
var body = HtmlUtils.bodyToHtml(content, this.props.searchTerm);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span ref="content" className="mx_MNoticeTile mx_MessageTile_content">
|
|
||||||
{ body }
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
var TextForEvent = require('matrix-react-sdk/lib/TextForEvent');
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MRoomMemberTile',
|
|
||||||
|
|
||||||
getMemberEventText: function() {
|
|
||||||
return TextForEvent.textForEvent(this.props.mxEvent);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
// XXX: for now, just cheekily borrow the css from message tile...
|
|
||||||
var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null;
|
|
||||||
var text = this.getMemberEventText();
|
|
||||||
if (!text) return <div/>;
|
|
||||||
var MessageTimestamp = sdk.getComponent('messages.MessageTimestamp');
|
|
||||||
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
|
||||||
return (
|
|
||||||
<div className="mx_MessageTile mx_MessageTile_notice">
|
|
||||||
<div className="mx_MessageTile_avatar">
|
|
||||||
<MemberAvatar member={this.props.mxEvent.sender} />
|
|
||||||
</div>
|
|
||||||
{ timestamp }
|
|
||||||
<span className="mx_SenderProfile"></span>
|
|
||||||
<span className="mx_MessageTile_content">
|
|
||||||
{ text }
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var HtmlUtils = require('../../../../HtmlUtils');
|
|
||||||
|
|
||||||
var MTextTileController = require('matrix-react-sdk/lib/controllers/molecules/MTextTile')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MTextTile',
|
|
||||||
mixins: [MTextTileController],
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
if (this.props.mxEvent.getContent().format === "org.matrix.custom.html")
|
|
||||||
HtmlUtils.highlightDom(this.getDOMNode());
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate: function() {
|
|
||||||
if (this.props.mxEvent.getContent().format === "org.matrix.custom.html")
|
|
||||||
HtmlUtils.highlightDom(this.getDOMNode());
|
|
||||||
},
|
|
||||||
|
|
||||||
shouldComponentUpdate: function(nextProps) {
|
|
||||||
// exploit that events are immutable :)
|
|
||||||
return (nextProps.mxEvent.getId() !== this.props.mxEvent.getId() ||
|
|
||||||
nextProps.searchTerm !== this.props.searchTerm);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
var body = HtmlUtils.bodyToHtml(content, this.props.searchTerm);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span ref="content" className="mx_MTextTile mx_MessageTile_content">
|
|
||||||
{ body }
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var filesize = require('filesize');
|
|
||||||
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
|
||||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MVideoTile',
|
|
||||||
|
|
||||||
thumbScale: function(fullWidth, fullHeight, thumbWidth, thumbHeight) {
|
|
||||||
if (!fullWidth || !fullHeight) {
|
|
||||||
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
|
|
||||||
// log this because it's spammy
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (fullWidth < thumbWidth && fullHeight < thumbHeight) {
|
|
||||||
// no scaling needs to be applied
|
|
||||||
return fullHeight;
|
|
||||||
}
|
|
||||||
var widthMulti = thumbWidth / fullWidth;
|
|
||||||
var heightMulti = thumbHeight / fullHeight;
|
|
||||||
if (widthMulti < heightMulti) {
|
|
||||||
// width is the dominant dimension so scaling will be fixed on that
|
|
||||||
return widthMulti;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// height is the dominant dimension so scaling will be fixed on that
|
|
||||||
return heightMulti;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
var cli = MatrixClientPeg.get();
|
|
||||||
|
|
||||||
var height = null;
|
|
||||||
var width = null;
|
|
||||||
var poster = null;
|
|
||||||
var preload = "metadata";
|
|
||||||
if (content.info) {
|
|
||||||
var scale = this.thumbScale(content.info.w, content.info.h, 480, 360);
|
|
||||||
if (scale) {
|
|
||||||
width = Math.floor(content.info.w * scale);
|
|
||||||
height = Math.floor(content.info.h * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content.info.thumbnail_url) {
|
|
||||||
poster = cli.mxcUrlToHttp(content.info.thumbnail_url);
|
|
||||||
preload = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span className="mx_MVideoTile">
|
|
||||||
<video className="mx_MVideoTile" src={cli.mxcUrlToHttp(content.url)} alt={content.body}
|
|
||||||
controls preload={preload} autoplay="false" loop
|
|
||||||
height={height} width={width} poster={poster}>
|
|
||||||
</video>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
|
||||||
var MemberInfoController = require('matrix-react-sdk/lib/controllers/molecules/MemberInfo')
|
|
||||||
|
|
||||||
// FIXME: this should probably be an organism, to match with MemberList, not a molecule
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MemberInfo',
|
|
||||||
mixins: [MemberInfoController],
|
|
||||||
|
|
||||||
onCancel: function(e) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: "view_user",
|
|
||||||
member: null
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var interactButton, kickButton, banButton, muteButton, giveModButton, spinner;
|
|
||||||
if (this.props.member.userId === MatrixClientPeg.get().credentials.userId) {
|
|
||||||
interactButton = <div className="mx_MemberInfo_field" onClick={this.onLeaveClick}>Leave room</div>;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
interactButton = <div className="mx_MemberInfo_field" onClick={this.onChatClick}>Start chat</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.creatingRoom) {
|
|
||||||
var Loader = sdk.getComponent("elements.Spinner");
|
|
||||||
spinner = <Loader imgClassName="mx_ContextualMenu_spinner"/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.can.kick) {
|
|
||||||
kickButton = <div className="mx_MemberInfo_field" onClick={this.onKick}>
|
|
||||||
Kick
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
if (this.state.can.ban) {
|
|
||||||
banButton = <div className="mx_MemberInfo_field" onClick={this.onBan}>
|
|
||||||
Ban
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
if (this.state.can.mute) {
|
|
||||||
var muteLabel = this.state.muted ? "Unmute" : "Mute";
|
|
||||||
muteButton = <div className="mx_MemberInfo_field" onClick={this.onMuteToggle}>
|
|
||||||
{muteLabel}
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
if (this.state.can.modifyLevel) {
|
|
||||||
var giveOpLabel = this.state.isTargetMod ? "Revoke Mod" : "Make Mod";
|
|
||||||
giveModButton = <div className="mx_MemberInfo_field" onClick={this.onModToggle}>
|
|
||||||
{giveOpLabel}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
|
||||||
return (
|
|
||||||
<div className="mx_MemberInfo">
|
|
||||||
<img className="mx_MemberInfo_cancel" src="img/cancel-black.png" width="18" height="18" onClick={this.onCancel}/>
|
|
||||||
<div className="mx_MemberInfo_avatar">
|
|
||||||
<MemberAvatar member={this.props.member} width={48} height={48} />
|
|
||||||
</div>
|
|
||||||
<h2>{ this.props.member.name }</h2>
|
|
||||||
<div className="mx_MemberInfo_profileField">
|
|
||||||
{ this.props.member.userId }
|
|
||||||
</div>
|
|
||||||
<div className="mx_MemberInfo_profileField">
|
|
||||||
power: { this.props.member.powerLevelNorm }%
|
|
||||||
</div>
|
|
||||||
<div className="mx_MemberInfo_buttons">
|
|
||||||
{interactButton}
|
|
||||||
{muteButton}
|
|
||||||
{kickButton}
|
|
||||||
{banButton}
|
|
||||||
{giveModButton}
|
|
||||||
{spinner}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
|
||||||
var MemberTileController = require('matrix-react-sdk/lib/controllers/molecules/MemberTile')
|
|
||||||
|
|
||||||
// The Lato WOFF doesn't include sensible combining diacritics, so Chrome chokes on rendering them.
|
|
||||||
// Revert to Arial when this happens, which on OSX works at least.
|
|
||||||
var zalgo = /[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/;
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MemberTile',
|
|
||||||
mixins: [MemberTileController],
|
|
||||||
|
|
||||||
shouldComponentUpdate: function(nextProps, nextState) {
|
|
||||||
if (this.state.hover !== nextState.hover) return true;
|
|
||||||
if (
|
|
||||||
this.member_last_modified_time === undefined ||
|
|
||||||
this.member_last_modified_time < nextProps.member.getLastModifiedTime()
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
nextProps.member.user &&
|
|
||||||
(this.user_last_modified_time === undefined ||
|
|
||||||
this.user_last_modified_time < nextProps.member.user.getLastModifiedTime())
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
mouseEnter: function(e) {
|
|
||||||
this.setState({ 'hover': true });
|
|
||||||
},
|
|
||||||
|
|
||||||
mouseLeave: function(e) {
|
|
||||||
this.setState({ 'hover': false });
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function(e) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'view_user',
|
|
||||||
member: this.props.member,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
getDuration: function(time) {
|
|
||||||
if (!time) return;
|
|
||||||
var t = parseInt(time / 1000);
|
|
||||||
var s = t % 60;
|
|
||||||
var m = parseInt(t / 60) % 60;
|
|
||||||
var h = parseInt(t / (60 * 60)) % 24;
|
|
||||||
var d = parseInt(t / (60 * 60 * 24));
|
|
||||||
if (t < 60) {
|
|
||||||
if (t < 0) {
|
|
||||||
return "0s";
|
|
||||||
}
|
|
||||||
return s + "s";
|
|
||||||
}
|
|
||||||
if (t < 60 * 60) {
|
|
||||||
return m + "m";
|
|
||||||
}
|
|
||||||
if (t < 24 * 60 * 60) {
|
|
||||||
return h + "h";
|
|
||||||
}
|
|
||||||
return d + "d ";
|
|
||||||
},
|
|
||||||
|
|
||||||
getPrettyPresence: function(user) {
|
|
||||||
if (!user) return "Unknown";
|
|
||||||
var presence = user.presence;
|
|
||||||
if (presence === "online") return "Online";
|
|
||||||
if (presence === "unavailable") return "Idle"; // XXX: is this actually right?
|
|
||||||
if (presence === "offline") return "Offline";
|
|
||||||
return "Unknown";
|
|
||||||
},
|
|
||||||
|
|
||||||
getPowerLabel: function() {
|
|
||||||
var label = this.props.member.userId;
|
|
||||||
if (this.state.isTargetMod) {
|
|
||||||
label += " - Mod (" + this.props.member.powerLevelNorm + "%)";
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
this.member_last_modified_time = this.props.member.getLastModifiedTime();
|
|
||||||
if (this.props.member.user) {
|
|
||||||
this.user_last_modified_time = this.props.member.user.getLastModifiedTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
var isMyUser = MatrixClientPeg.get().credentials.userId == this.props.member.userId;
|
|
||||||
|
|
||||||
var power;
|
|
||||||
// if (this.props.member && this.props.member.powerLevelNorm > 0) {
|
|
||||||
// var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
|
|
||||||
// power = <img src={ img } className="mx_MemberTile_power" width="44" height="44" alt=""/>;
|
|
||||||
// }
|
|
||||||
var presenceClass = "mx_MemberTile_offline";
|
|
||||||
var mainClassName = "mx_MemberTile ";
|
|
||||||
if (this.props.member.user) {
|
|
||||||
if (this.props.member.user.presence === "online") {
|
|
||||||
presenceClass = "mx_MemberTile_online";
|
|
||||||
}
|
|
||||||
else if (this.props.member.user.presence === "unavailable") {
|
|
||||||
presenceClass = "mx_MemberTile_unavailable";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mainClassName += presenceClass;
|
|
||||||
if (this.state.hover) {
|
|
||||||
mainClassName += " mx_MemberTile_hover";
|
|
||||||
}
|
|
||||||
|
|
||||||
var name = this.props.member.name;
|
|
||||||
// if (isMyUser) name += " (me)"; // this does nothing other than introduce line wrapping and pain
|
|
||||||
//var leave = isMyUser ? <img className="mx_MemberTile_leave" src="img/delete.png" width="10" height="10" onClick={this.onLeaveClick}/> : null;
|
|
||||||
|
|
||||||
var nameClass = "mx_MemberTile_name";
|
|
||||||
if (zalgo.test(name)) {
|
|
||||||
nameClass += " mx_MemberTile_zalgo";
|
|
||||||
}
|
|
||||||
|
|
||||||
var nameEl;
|
|
||||||
if (this.state.hover) {
|
|
||||||
var presence;
|
|
||||||
// FIXME: make presence data update whenever User.presence changes...
|
|
||||||
var active = this.props.member.user ? ((Date.now() - (this.props.member.user.lastPresenceTs - this.props.member.user.lastActiveAgo)) || -1) : -1;
|
|
||||||
if (active >= 0) {
|
|
||||||
presence = <div className="mx_MemberTile_presence">{ this.getPrettyPresence(this.props.member.user) } { this.getDuration(active) } ago</div>;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
presence = <div className="mx_MemberTile_presence">{ this.getPrettyPresence(this.props.member.user) }</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
nameEl =
|
|
||||||
<div className="mx_MemberTile_details">
|
|
||||||
<img className="mx_MemberTile_chevron" src="img/member_chevron.png" width="8" height="12"/>
|
|
||||||
<div className="mx_MemberTile_userId">{ name }</div>
|
|
||||||
{ presence }
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nameEl =
|
|
||||||
<div className={nameClass}>
|
|
||||||
{ name }
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
|
||||||
return (
|
|
||||||
<div className={mainClassName} title={ this.getPowerLabel() } onClick={ this.onClick } onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }>
|
|
||||||
<div className="mx_MemberTile_avatar">
|
|
||||||
<MemberAvatar member={this.props.member} width={36} height={36} />
|
|
||||||
{ power }
|
|
||||||
</div>
|
|
||||||
{ nameEl }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
|
||||||
var MessageComposerController = require('matrix-react-sdk/lib/controllers/molecules/MessageComposer')
|
|
||||||
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
var dis = require('matrix-react-sdk/lib/dispatcher')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MessageComposer',
|
|
||||||
mixins: [MessageComposerController],
|
|
||||||
|
|
||||||
onInputClick: function(ev) {
|
|
||||||
this.refs.textarea.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
onUploadClick: function(ev) {
|
|
||||||
this.refs.uploadInput.click();
|
|
||||||
},
|
|
||||||
|
|
||||||
onUploadFileSelected: function(ev) {
|
|
||||||
var files = ev.target.files;
|
|
||||||
// MessageComposer shouldn't have to rely on it's parent passing in a callback to upload a file
|
|
||||||
if (files && files.length > 0) {
|
|
||||||
this.props.uploadFile(files[0]);
|
|
||||||
}
|
|
||||||
this.refs.uploadInput.value = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
onCallClick: function(ev) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'place_call',
|
|
||||||
type: ev.shiftKey ? "screensharing" : "video",
|
|
||||||
room_id: this.props.room.roomId
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onVoiceCallClick: function(ev) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'place_call',
|
|
||||||
type: 'voice',
|
|
||||||
room_id: this.props.room.roomId
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
|
|
||||||
var uploadInputStyle = {display: 'none'};
|
|
||||||
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
|
||||||
return (
|
|
||||||
<div className="mx_MessageComposer">
|
|
||||||
<div className="mx_MessageComposer_wrapper">
|
|
||||||
<div className="mx_MessageComposer_row">
|
|
||||||
<div className="mx_MessageComposer_avatar">
|
|
||||||
<MemberAvatar member={me} width={24} height={24} />
|
|
||||||
</div>
|
|
||||||
<div className="mx_MessageComposer_input" onClick={ this.onInputClick }>
|
|
||||||
<textarea ref="textarea" rows="1" onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} placeholder="Type a message..." />
|
|
||||||
</div>
|
|
||||||
<div className="mx_MessageComposer_upload" onClick={this.onUploadClick}>
|
|
||||||
<img src="img/upload.png" alt="Upload file" title="Upload file" width="17" height="22"/>
|
|
||||||
<input type="file" style={uploadInputStyle} ref="uploadInput" onChange={this.onUploadFileSelected} />
|
|
||||||
</div>
|
|
||||||
<div className="mx_MessageComposer_voicecall" onClick={this.onVoiceCallClick}>
|
|
||||||
<img src="img/voice.png" alt="Voice call" title="Voice call" width="16" height="26"/>
|
|
||||||
</div>
|
|
||||||
<div className="mx_MessageComposer_videocall" onClick={this.onCallClick}>
|
|
||||||
<img src="img/call.png" alt="Video call" title="Video call" width="28" height="20"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
|
|
||||||
var MessageTileController = require('matrix-react-sdk/lib/controllers/molecules/MessageTile')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'MessageTile',
|
|
||||||
mixins: [MessageTileController],
|
|
||||||
|
|
||||||
statics: {
|
|
||||||
needsSenderProfile: function() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var UnknownMessageTile = sdk.getComponent('molecules.UnknownMessageTile');
|
|
||||||
|
|
||||||
var tileTypes = {
|
|
||||||
'm.text': sdk.getComponent('molecules.MTextTile'),
|
|
||||||
'm.notice': sdk.getComponent('molecules.MNoticeTile'),
|
|
||||||
'm.emote': sdk.getComponent('molecules.MEmoteTile'),
|
|
||||||
'm.image': sdk.getComponent('molecules.MImageTile'),
|
|
||||||
'm.file': sdk.getComponent('molecules.MFileTile'),
|
|
||||||
'm.video': sdk.getComponent('molecules.MVideoTile')
|
|
||||||
};
|
|
||||||
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
var msgtype = content.msgtype;
|
|
||||||
var TileType = UnknownMessageTile;
|
|
||||||
if (msgtype && tileTypes[msgtype]) {
|
|
||||||
TileType = tileTypes[msgtype];
|
|
||||||
}
|
|
||||||
|
|
||||||
return <TileType mxEvent={this.props.mxEvent} searchTerm={this.props.searchTerm} />;
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var ProgressBarController = require('matrix-react-sdk/lib/controllers/molecules/ProgressBar')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'ProgressBar',
|
|
||||||
mixins: [ProgressBarController],
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
// Would use an HTML5 progress tag but if that doesn't animate if you
|
|
||||||
// use the HTML attributes rather than styles
|
|
||||||
var progressStyle = {
|
|
||||||
width: ((this.props.value / this.props.max) * 100)+"%"
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="mx_ProgressBar"><div className="mx_ProgressBar_fill" style={progressStyle}></div></div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,181 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var sdk = require('matrix-react-sdk')
|
|
||||||
var dis = require('matrix-react-sdk/lib/dispatcher')
|
|
||||||
|
|
||||||
var CallHandler = require('matrix-react-sdk/lib/CallHandler');
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
|
||||||
var RoomHeaderController = require('matrix-react-sdk/lib/controllers/molecules/RoomHeader')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'RoomHeader',
|
|
||||||
mixins: [RoomHeaderController],
|
|
||||||
|
|
||||||
onNameChange: function(new_name) {
|
|
||||||
if (this.props.room.name != new_name && new_name) {
|
|
||||||
MatrixClientPeg.get().setRoomName(this.props.room.roomId, new_name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getRoomName: function() {
|
|
||||||
return this.refs.name_edit.value;
|
|
||||||
},
|
|
||||||
|
|
||||||
onFullscreenClick: function() {
|
|
||||||
dis.dispatch({action: 'video_fullscreen', fullscreen: true}, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var EditableText = sdk.getComponent("elements.EditableText");
|
|
||||||
var RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
|
|
||||||
|
|
||||||
var header;
|
|
||||||
if (this.props.simpleHeader) {
|
|
||||||
header =
|
|
||||||
<div className="mx_RoomHeader_wrapper">
|
|
||||||
<div className="mx_RoomHeader_simpleHeader">
|
|
||||||
{ this.props.simpleHeader }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
|
|
||||||
|
|
||||||
var call_buttons;
|
|
||||||
if (this.state && this.state.call_state != 'ended') {
|
|
||||||
//var muteVideoButton;
|
|
||||||
var activeCall = (
|
|
||||||
CallHandler.getCallForRoom(this.props.room.roomId)
|
|
||||||
);
|
|
||||||
/*
|
|
||||||
if (activeCall && activeCall.type === "video") {
|
|
||||||
muteVideoButton = (
|
|
||||||
<div className="mx_RoomHeader_textButton mx_RoomHeader_voipButton"
|
|
||||||
onClick={this.onMuteVideoClick}>
|
|
||||||
{
|
|
||||||
(activeCall.isLocalVideoMuted() ?
|
|
||||||
"Unmute" : "Mute") + " video"
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
{muteVideoButton}
|
|
||||||
<div className="mx_RoomHeader_textButton mx_RoomHeader_voipButton"
|
|
||||||
onClick={this.onMuteAudioClick}>
|
|
||||||
{
|
|
||||||
(activeCall && activeCall.isMicrophoneMuted() ?
|
|
||||||
"Unmute" : "Mute") + " audio"
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
*/
|
|
||||||
|
|
||||||
call_buttons = (
|
|
||||||
<div className="mx_RoomHeader_textButton"
|
|
||||||
onClick={this.onHangupClick}>
|
|
||||||
End call
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var name = null;
|
|
||||||
var topic_el = null;
|
|
||||||
var cancel_button = null;
|
|
||||||
var save_button = null;
|
|
||||||
var settings_button = null;
|
|
||||||
var actual_name = this.props.room.currentState.getStateEvents('m.room.name', '');
|
|
||||||
if (actual_name) actual_name = actual_name.getContent().name;
|
|
||||||
if (this.props.editing) {
|
|
||||||
name =
|
|
||||||
<div className="mx_RoomHeader_nameEditing">
|
|
||||||
<input className="mx_RoomHeader_nameInput" type="text" defaultValue={actual_name} placeholder="Name" ref="name_edit"/>
|
|
||||||
</div>
|
|
||||||
// if (topic) topic_el = <div className="mx_RoomHeader_topic"><textarea>{ topic.getContent().topic }</textarea></div>
|
|
||||||
cancel_button = <div className="mx_RoomHeader_textButton" onClick={this.props.onCancelClick}>Cancel</div>
|
|
||||||
save_button = <div className="mx_RoomHeader_textButton" onClick={this.props.onSaveClick}>Save Changes</div>
|
|
||||||
} else {
|
|
||||||
// <EditableText label={this.props.room.name} initialValue={actual_name} placeHolder="Name" onValueChanged={this.onNameChange} />
|
|
||||||
name =
|
|
||||||
<div className="mx_RoomHeader_name" onClick={this.props.onSettingsClick}>
|
|
||||||
<div className="mx_RoomHeader_nametext">{ this.props.room.name }</div>
|
|
||||||
<div className="mx_RoomHeader_settingsButton">
|
|
||||||
<img src="img/settings.png" width="12" height="12"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
if (topic) topic_el = <div className="mx_RoomHeader_topic" title={topic.getContent().topic}>{ topic.getContent().topic }</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
var roomAvatar = null;
|
|
||||||
if (this.props.room) {
|
|
||||||
roomAvatar = (
|
|
||||||
<RoomAvatar room={this.props.room} width="48" height="48" />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var zoom_button, video_button, voice_button;
|
|
||||||
if (activeCall) {
|
|
||||||
if (activeCall.type == "video") {
|
|
||||||
zoom_button = (
|
|
||||||
<div className="mx_RoomHeader_button" onClick={this.onFullscreenClick}>
|
|
||||||
<img src="img/zoom.png" title="Fullscreen" alt="Fullscreen" width="32" height="32" style={{ 'marginTop': '-5px' }}/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
video_button =
|
|
||||||
<div className="mx_RoomHeader_button mx_RoomHeader_video" onClick={activeCall && activeCall.type === "video" ? this.onMuteVideoClick : this.onVideoClick}>
|
|
||||||
<img src="img/video.png" title="Video call" alt="Video call" width="32" height="32" style={{ 'marginTop': '-8px' }}/>
|
|
||||||
</div>;
|
|
||||||
voice_button =
|
|
||||||
<div className="mx_RoomHeader_button mx_RoomHeader_voice" onClick={activeCall ? this.onMuteAudioClick : this.onVoiceClick}>
|
|
||||||
<img src="img/voip.png" title="VoIP call" alt="VoIP call" width="32" height="32" style={{ 'marginTop': '-8px' }}/>
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
header =
|
|
||||||
<div className="mx_RoomHeader_wrapper">
|
|
||||||
<div className="mx_RoomHeader_leftRow">
|
|
||||||
<div className="mx_RoomHeader_avatar">
|
|
||||||
{ roomAvatar }
|
|
||||||
</div>
|
|
||||||
<div className="mx_RoomHeader_info">
|
|
||||||
{ name }
|
|
||||||
{ topic_el }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{call_buttons}
|
|
||||||
{cancel_button}
|
|
||||||
{save_button}
|
|
||||||
<div className="mx_RoomHeader_rightRow">
|
|
||||||
{ video_button }
|
|
||||||
{ voice_button }
|
|
||||||
{ zoom_button }
|
|
||||||
<div className="mx_RoomHeader_button">
|
|
||||||
<img src="img/search.png" title="Search" alt="Search" width="21" height="19" onClick={this.props.onSearchClick}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mx_RoomHeader">
|
|
||||||
{ header }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,232 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
|
||||||
var sdk = require('matrix-react-sdk');
|
|
||||||
|
|
||||||
var RoomSettingsController = require('matrix-react-sdk/lib/controllers/molecules/RoomSettings')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'RoomSettings',
|
|
||||||
mixins: [RoomSettingsController],
|
|
||||||
|
|
||||||
getTopic: function() {
|
|
||||||
return this.refs.topic.value;
|
|
||||||
},
|
|
||||||
|
|
||||||
getJoinRules: function() {
|
|
||||||
return this.refs.is_private.checked ? "invite" : "public";
|
|
||||||
},
|
|
||||||
|
|
||||||
getHistoryVisibility: function() {
|
|
||||||
return this.refs.share_history.checked ? "shared" : "invited";
|
|
||||||
},
|
|
||||||
|
|
||||||
getPowerLevels: function() {
|
|
||||||
if (!this.state.power_levels_changed) return undefined;
|
|
||||||
|
|
||||||
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
|
|
||||||
power_levels = power_levels.getContent();
|
|
||||||
|
|
||||||
var new_power_levels = {
|
|
||||||
ban: parseInt(this.refs.ban.value),
|
|
||||||
kick: parseInt(this.refs.kick.value),
|
|
||||||
redact: parseInt(this.refs.redact.value),
|
|
||||||
invite: parseInt(this.refs.invite.value),
|
|
||||||
events_default: parseInt(this.refs.events_default.value),
|
|
||||||
state_default: parseInt(this.refs.state_default.value),
|
|
||||||
users_default: parseInt(this.refs.users_default.value),
|
|
||||||
users: power_levels.users,
|
|
||||||
events: power_levels.events,
|
|
||||||
};
|
|
||||||
|
|
||||||
return new_power_levels;
|
|
||||||
},
|
|
||||||
|
|
||||||
onPowerLevelsChanged: function() {
|
|
||||||
this.setState({
|
|
||||||
power_levels_changed: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var ChangeAvatar = sdk.getComponent('molecules.ChangeAvatar');
|
|
||||||
|
|
||||||
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
|
|
||||||
if (topic) topic = topic.getContent().topic;
|
|
||||||
|
|
||||||
var join_rule = this.props.room.currentState.getStateEvents('m.room.join_rules', '');
|
|
||||||
if (join_rule) join_rule = join_rule.getContent().join_rule;
|
|
||||||
|
|
||||||
var history_visibility = this.props.room.currentState.getStateEvents('m.room.history_visibility', '');
|
|
||||||
if (history_visibility) history_visibility = history_visibility.getContent().history_visibility;
|
|
||||||
|
|
||||||
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
|
|
||||||
|
|
||||||
var events_levels = power_levels.events || {};
|
|
||||||
|
|
||||||
if (power_levels) {
|
|
||||||
power_levels = power_levels.getContent();
|
|
||||||
|
|
||||||
var ban_level = parseInt(power_levels.ban);
|
|
||||||
var kick_level = parseInt(power_levels.kick);
|
|
||||||
var redact_level = parseInt(power_levels.redact);
|
|
||||||
var invite_level = parseInt(power_levels.invite || 0);
|
|
||||||
var send_level = parseInt(power_levels.events_default || 0);
|
|
||||||
var state_level = parseInt(power_levels.state_default || 0);
|
|
||||||
var default_user_level = parseInt(power_levels.users_default || 0);
|
|
||||||
|
|
||||||
if (power_levels.ban == undefined) ban_level = 50;
|
|
||||||
if (power_levels.kick == undefined) kick_level = 50;
|
|
||||||
if (power_levels.redact == undefined) redact_level = 50;
|
|
||||||
|
|
||||||
var user_levels = power_levels.users || {};
|
|
||||||
|
|
||||||
var user_id = MatrixClientPeg.get().credentials.userId;
|
|
||||||
|
|
||||||
var current_user_level = user_levels[user_id];
|
|
||||||
if (current_user_level == undefined) current_user_level = default_user_level;
|
|
||||||
|
|
||||||
var power_level_level = events_levels["m.room.power_levels"];
|
|
||||||
if (power_level_level == undefined) {
|
|
||||||
power_level_level = state_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
var can_change_levels = current_user_level >= power_level_level;
|
|
||||||
} else {
|
|
||||||
var ban_level = 50;
|
|
||||||
var kick_level = 50;
|
|
||||||
var redact_level = 50;
|
|
||||||
var invite_level = 0;
|
|
||||||
var send_level = 0;
|
|
||||||
var state_level = 0;
|
|
||||||
var default_user_level = 0;
|
|
||||||
|
|
||||||
var user_levels = [];
|
|
||||||
var events_levels = [];
|
|
||||||
|
|
||||||
var current_user_level = 0;
|
|
||||||
|
|
||||||
var power_level_level = 0;
|
|
||||||
|
|
||||||
var can_change_levels = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var room_avatar_level = parseInt(power_levels.state_default || 0);
|
|
||||||
if (events_levels['m.room.avatar'] !== undefined) {
|
|
||||||
room_avatar_level = events_levels['m.room.avatar'];
|
|
||||||
}
|
|
||||||
var can_set_room_avatar = current_user_level >= room_avatar_level;
|
|
||||||
|
|
||||||
var change_avatar;
|
|
||||||
if (can_set_room_avatar) {
|
|
||||||
change_avatar = <div>
|
|
||||||
<h3>Room Icon</h3>
|
|
||||||
<ChangeAvatar room={this.props.room} />
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
var banned = this.props.room.getMembersWithMembership("ban");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mx_RoomSettings">
|
|
||||||
<textarea className="mx_RoomSettings_description" placeholder="Topic" defaultValue={topic} ref="topic"/> <br/>
|
|
||||||
<label><input type="checkbox" ref="is_private" defaultChecked={join_rule != "public"}/> Make this room private</label> <br/>
|
|
||||||
<label><input type="checkbox" ref="share_history" defaultChecked={history_visibility == "shared"}/> Share message history with new users</label> <br/>
|
|
||||||
<label className="mx_RoomSettings_encrypt"><input type="checkbox" /> Encrypt room</label> <br/>
|
|
||||||
|
|
||||||
<h3>Power levels</h3>
|
|
||||||
<div className="mx_RoomSettings_power_levels mx_RoomSettings_settings">
|
|
||||||
<div>
|
|
||||||
<label htmlFor="mx_RoomSettings_ban_level">Ban level</label>
|
|
||||||
<input type="text" defaultValue={ban_level} size="3" ref="ban" id="mx_RoomSettings_ban_level"
|
|
||||||
disabled={!can_change_levels || current_user_level < ban_level} onChange={this.onPowerLevelsChanged}/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="mx_RoomSettings_kick_level">Kick level</label>
|
|
||||||
<input type="text" defaultValue={kick_level} size="3" ref="kick" id="mx_RoomSettings_kick_level"
|
|
||||||
disabled={!can_change_levels || current_user_level < kick_level} onChange={this.onPowerLevelsChanged}/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="mx_RoomSettings_redact_level">Redact level</label>
|
|
||||||
<input type="text" defaultValue={redact_level} size="3" ref="redact" id="mx_RoomSettings_redact_level"
|
|
||||||
disabled={!can_change_levels || current_user_level < redact_level} onChange={this.onPowerLevelsChanged}/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="mx_RoomSettings_invite_level">Invite level</label>
|
|
||||||
<input type="text" defaultValue={invite_level} size="3" ref="invite" id="mx_RoomSettings_invite_level"
|
|
||||||
disabled={!can_change_levels || current_user_level < invite_level} onChange={this.onPowerLevelsChanged}/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="mx_RoomSettings_event_level">Send event level</label>
|
|
||||||
<input type="text" defaultValue={send_level} size="3" ref="events_default" id="mx_RoomSettings_event_level"
|
|
||||||
disabled={!can_change_levels || current_user_level < send_level} onChange={this.onPowerLevelsChanged}/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="mx_RoomSettings_state_level">Set state level</label>
|
|
||||||
<input type="text" defaultValue={state_level} size="3" ref="state_default" id="mx_RoomSettings_state_level"
|
|
||||||
disabled={!can_change_levels || current_user_level < state_level} onChange={this.onPowerLevelsChanged}/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="mx_RoomSettings_user_level">Default user level</label>
|
|
||||||
<input type="text" defaultValue={default_user_level} size="3" ref="users_default"
|
|
||||||
id="mx_RoomSettings_user_level" disabled={!can_change_levels || current_user_level < default_user_level}
|
|
||||||
onChange={this.onPowerLevelsChanged}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>User levels</h3>
|
|
||||||
<div className="mx_RoomSettings_user_levels mx_RoomSettings_settings">
|
|
||||||
{Object.keys(user_levels).map(function(user, i) {
|
|
||||||
return (
|
|
||||||
<div key={user}>
|
|
||||||
<label htmlFor={"mx_RoomSettings_user_"+i}>{user}</label>
|
|
||||||
<input type="text" defaultValue={user_levels[user]} size="3" id={"mx_RoomSettings_user_"+i} disabled/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Event levels</h3>
|
|
||||||
<div className="mx_RoomSettings_event_lvels mx_RoomSettings_settings">
|
|
||||||
{Object.keys(events_levels).map(function(event_type, i) {
|
|
||||||
return (
|
|
||||||
<div key={event_type}>
|
|
||||||
<label htmlFor={"mx_RoomSettings_event_"+i}>{event_type}</label>
|
|
||||||
<input type="text" defaultValue={events_levels[event_type]} size="3" id={"mx_RoomSettings_event_"+i} disabled/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Banned users</h3>
|
|
||||||
<div className="mx_RoomSettings_banned">
|
|
||||||
{banned.map(function(member, i) {
|
|
||||||
return (
|
|
||||||
<div key={i}>
|
|
||||||
{member.userId}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
{change_avatar}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'UnknownMessageTile',
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var content = this.props.mxEvent.getContent();
|
|
||||||
return (
|
|
||||||
<span className="mx_UnknownMessageTile">
|
|
||||||
{content.body}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
|
|
||||||
var UserSelectorController = require('matrix-react-sdk/lib/controllers/molecules/UserSelector')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'UserSelector',
|
|
||||||
mixins: [UserSelectorController],
|
|
||||||
|
|
||||||
onAddUserId: function() {
|
|
||||||
this.addUser(this.refs.user_id_input.value);
|
|
||||||
this.refs.user_id_input.value = "";
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
var self = this;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<ul className="mx_UserSelector_UserIdList" ref="list">
|
|
||||||
{this.props.selected_users.map(function(user_id, i) {
|
|
||||||
return <li key={user_id}>{user_id} - <span onClick={function() {self.removeUser(user_id);}}>X</span></li>
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
<input type="text" ref="user_id_input" defaultValue="" className="mx_UserSelector_userIdInput" placeholder="ex. @bob:example.com"/>
|
|
||||||
<button onClick={this.onAddUserId} className="mx_UserSelector_AddUserId">Add User</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
@ -140,8 +140,8 @@ module.exports = React.createClass({
|
|||||||
var CreateRoomButton = sdk.getComponent("create_room.CreateRoomButton");
|
var CreateRoomButton = sdk.getComponent("create_room.CreateRoomButton");
|
||||||
var RoomAlias = sdk.getComponent("create_room.RoomAlias");
|
var RoomAlias = sdk.getComponent("create_room.RoomAlias");
|
||||||
var Presets = sdk.getComponent("create_room.Presets");
|
var Presets = sdk.getComponent("create_room.Presets");
|
||||||
var UserSelector = sdk.getComponent("molecules.UserSelector");
|
var UserSelector = sdk.getComponent("elements.UserSelector");
|
||||||
var RoomHeader = sdk.getComponent("molecules.RoomHeader");
|
var RoomHeader = sdk.getComponent("rooms.RoomHeader");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_CreateRoom">
|
<div className="mx_CreateRoom">
|
||||||
|
@ -56,7 +56,7 @@ module.exports = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
makeMemberTiles: function(membership) {
|
makeMemberTiles: function(membership) {
|
||||||
var MemberTile = sdk.getComponent("molecules.MemberTile");
|
var MemberTile = sdk.getComponent("rooms.MemberTile");
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
return self.state.members.filter(function(userId) {
|
return self.state.members.filter(function(userId) {
|
||||||
|
@ -137,7 +137,7 @@ module.exports = React.createClass({
|
|||||||
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
||||||
}
|
}
|
||||||
else if(this.state.phase == this.Phase.MemberInfo) {
|
else if(this.state.phase == this.Phase.MemberInfo) {
|
||||||
var MemberInfo = sdk.getComponent('molecules.MemberInfo');
|
var MemberInfo = sdk.getComponent('rooms.MemberInfo');
|
||||||
panel = <MemberInfo roomId={this.props.roomId} member={this.state.member} key={this.props.roomId} />
|
panel = <MemberInfo roomId={this.props.roomId} member={this.state.member} key={this.props.roomId} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ module.exports = React.createClass({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var RoomHeader = sdk.getComponent('molecules.RoomHeader');
|
var RoomHeader = sdk.getComponent('rooms.RoomHeader');
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomDirectory">
|
<div className="mx_RoomDirectory">
|
||||||
<RoomHeader simpleHeader="Public Rooms" />
|
<RoomHeader simpleHeader="Public Rooms" />
|
||||||
|
@ -215,7 +215,7 @@ var RoomSubList = React.createClass({
|
|||||||
|
|
||||||
makeRoomTiles: function() {
|
makeRoomTiles: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var RoomTile = sdk.getComponent("molecules.RoomTile");
|
var RoomTile = sdk.getComponent("rooms.RoomTile");
|
||||||
return this.state.sortedList.map(function(room) {
|
return this.state.sortedList.map(function(room) {
|
||||||
var selected = room.roomId == self.props.selectedRoom;
|
var selected = room.roomId == self.props.selectedRoom;
|
||||||
// XXX: is it evil to pass in self as a prop to RoomTile?
|
// XXX: is it evil to pass in self as a prop to RoomTile?
|
||||||
|
@ -108,10 +108,10 @@ module.exports = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var RoomHeader = sdk.getComponent('molecules.RoomHeader');
|
var RoomHeader = sdk.getComponent('rooms.RoomHeader');
|
||||||
var MessageComposer = sdk.getComponent('molecules.MessageComposer');
|
var MessageComposer = sdk.getComponent('messages.MessageComposer');
|
||||||
var CallView = sdk.getComponent("voip.CallView");
|
var CallView = sdk.getComponent("voip.CallView");
|
||||||
var RoomSettings = sdk.getComponent("molecules.RoomSettings");
|
var RoomSettings = sdk.getComponent("rooms.RoomSettings");
|
||||||
var SearchBar = sdk.getComponent("molecules.SearchBar");
|
var SearchBar = sdk.getComponent("molecules.SearchBar");
|
||||||
|
|
||||||
if (!this.state.room) {
|
if (!this.state.room) {
|
||||||
|
@ -27,7 +27,7 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
editAvatar: function() {
|
editAvatar: function() {
|
||||||
var url = MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl);
|
var url = MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl);
|
||||||
var ChangeAvatar = sdk.getComponent('molecules.ChangeAvatar');
|
var ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
|
||||||
var avatarDialog = (
|
var avatarDialog = (
|
||||||
<div>
|
<div>
|
||||||
<ChangeAvatar initialAvatarUrl={url} />
|
<ChangeAvatar initialAvatarUrl={url} />
|
||||||
@ -48,7 +48,7 @@ module.exports = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
changePassword: function() {
|
changePassword: function() {
|
||||||
var ChangePassword = sdk.getComponent('molecules.ChangePassword');
|
var ChangePassword = sdk.getComponent('settings.ChangePassword');
|
||||||
Modal.createDialog(ChangePassword);
|
Modal.createDialog(ChangePassword);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ module.exports = React.createClass({
|
|||||||
case this.Phases.Loading:
|
case this.Phases.Loading:
|
||||||
return <Loader />
|
return <Loader />
|
||||||
case this.Phases.Display:
|
case this.Phases.Display:
|
||||||
var ChangeDisplayName = sdk.getComponent('molecules.ChangeDisplayName');
|
var ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName');
|
||||||
var EnableNotificationsButton = sdk.getComponent('settings.EnableNotificationsButton');
|
var EnableNotificationsButton = sdk.getComponent('settings.EnableNotificationsButton');
|
||||||
return (
|
return (
|
||||||
<div className="mx_UserSettings">
|
<div className="mx_UserSettings">
|
||||||
|
@ -24,7 +24,7 @@ var MatrixChatController = require('matrix-react-sdk/lib/controllers/pages/Matri
|
|||||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||||
var Matrix = require("matrix-js-sdk");
|
var Matrix = require("matrix-js-sdk");
|
||||||
|
|
||||||
var ContextualMenu = require("../../../../ContextualMenu");
|
var ContextualMenu = require("matrix-react-sdk/lib/ContextualMenu");
|
||||||
var Login = require("../../../../components/structures/login/Login");
|
var Login = require("../../../../components/structures/login/Login");
|
||||||
var Registration = require("../../../../components/structures/login/Registration");
|
var Registration = require("../../../../components/structures/login/Registration");
|
||||||
var PostRegistration = require("../../../../components/structures/login/PostRegistration");
|
var PostRegistration = require("../../../../components/structures/login/PostRegistration");
|
||||||
@ -56,7 +56,7 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
onUserClick: function(event, userId) {
|
onUserClick: function(event, userId) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var MemberInfo = sdk.getComponent('molecules.MemberInfo');
|
var MemberInfo = sdk.getComponent('rooms.MemberInfo');
|
||||||
var member = new Matrix.RoomMember(null, userId);
|
var member = new Matrix.RoomMember(null, userId);
|
||||||
ContextualMenu.createMenu(MemberInfo, {
|
ContextualMenu.createMenu(MemberInfo, {
|
||||||
member: member,
|
member: member,
|
||||||
|
Loading…
Reference in New Issue
Block a user