diff --git a/src/PageTypes.js b/src/PageTypes.js
index d87b363a6f..b2346c62c3 100644
--- a/src/PageTypes.js
+++ b/src/PageTypes.js
@@ -22,4 +22,5 @@ export default {
CreateRoom: "create_room",
RoomDirectory: "room_directory",
UserView: "user_view",
+ GroupView: "group_view",
};
diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js
new file mode 100644
index 0000000000..2368c44319
--- /dev/null
+++ b/src/components/structures/GroupView.js
@@ -0,0 +1,130 @@
+/*
+Copyright 2017 Vector Creations Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import MatrixClientPeg from '../../MatrixClientPeg';
+import sdk from '../../index';
+import sanitizeHtml from "sanitize-html";
+import { sanitizeHtmlParams } from '../../HtmlUtils';
+
+
+module.exports = React.createClass({
+ displayName: 'GroupView',
+
+ propTypes: {
+ groupId: React.PropTypes.string.isRequired,
+ },
+
+ getInitialState: function() {
+ return {
+ phase: "GroupView.LOADING", // LOADING / DISPLAY / ERROR / NOT_FOUND
+ summary: null,
+ };
+ },
+
+ componentWillMount: function() {
+ this.setState({
+ phase: "GroupView.LOADING",
+ summary: null,
+ })
+ this._loadGroupFromServer(this.props.groupId)
+ },
+
+ componentWillReceiveProps: function(new_props) {
+ if (this.props.groupId != new_props.groupId) {
+ this.setState({
+ phase: "GroupView.LOADING",
+ summary: null,
+ })
+ this._loadGroupFromServer(new_props.groupId);
+ }
+ },
+
+ _loadGroupFromServer: function(groupId) {
+ const self = this;
+ MatrixClientPeg.get().getGroupSummary(groupId).done(function(res) {
+ self.setState({
+ phase: "GroupView.DISPLAY",
+ summary: res,
+ });
+ }, function(err) {
+ self.setState({
+ phase: err.errcode == 404 ? "GroupView.NOT_FOUND" :"GroupView.ERROR",
+ summary: null,
+ });
+ });
+ },
+
+ render: function() {
+ var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
+ var Loader = sdk.getComponent("elements.Spinner");
+
+ if (this.state.phase == "GroupView.LOADING") {
+ return (
+
+
+
+ );
+ } else if (this.state.phase == "GroupView.DISPLAY") {
+ const summary = this.state.summary;
+ let avatar_url = null;
+ if (summary.profile.avatar_url) {
+ avatar_url = MatrixClientPeg.get().mxcUrlToHttp(summary.profile.avatar_url);
+ }
+ let description = null;
+ if (summary.profile.long_description) {
+ description = sanitizeHtml(summary.profile.long_description);
+ }
+ return (
+
+
+
+
+
+
+
+
+ {summary.profile.name}
+
+ ({this.props.groupId})
+
+
+
+ {summary.profile.short_description}
+
+
+
+
+
+
+ );
+ } else if (this.state.phase == "GroupView.NOT_FOUND") {
+
+ Group {this.props.groupId} not found
+
+ } else {
+ return (
+
+ Failed to load {this.props.groupId}
+
+ );
+ }
+ },
+});
diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js
index e2fdeb4687..cf9a8310b1 100644
--- a/src/components/structures/LoggedInView.js
+++ b/src/components/structures/LoggedInView.js
@@ -179,6 +179,7 @@ export default React.createClass({
const CreateRoom = sdk.getComponent('structures.CreateRoom');
const RoomDirectory = sdk.getComponent('structures.RoomDirectory');
const HomePage = sdk.getComponent('structures.HomePage');
+ const GroupView = sdk.getComponent('structures.GroupView');
const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar');
const GuestWarningBar = sdk.getComponent('globals.GuestWarningBar');
const NewVersionBar = sdk.getComponent('globals.NewVersionBar');
@@ -247,6 +248,12 @@ export default React.createClass({
page_element = null; // deliberately null for now
right_panel = ;
break;
+ case PageTypes.GroupView:
+ // TODO
+ page_element =
+ break;
}
var topBar;
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 0dedc02270..8771231e68 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -261,6 +261,9 @@ module.exports = React.createClass({
if (this.onUserClick) {
linkifyMatrix.onUserClick = this.onUserClick;
}
+ if (this.onGroupClick) {
+ linkifyMatrix.onGroupClick = this.onGroupClick;
+ }
window.addEventListener('resize', this.handleResize);
this.handleResize();
@@ -458,6 +461,12 @@ module.exports = React.createClass({
this._setPage(PageTypes.RoomDirectory);
this.notifyNewScreen('directory');
break;
+ case 'view_group':
+ const groupId = payload.group_id;
+ this.setState({currentGroupId: groupId});
+ this._setPage(PageTypes.GroupView);
+ this.notifyNewScreen('group/' + groupId);
+ break;
case 'view_home_page':
if (!this._teamToken) {
dis.dispatch({action: 'view_room_directory'});
@@ -1001,6 +1010,15 @@ module.exports = React.createClass({
member: member,
});
}
+ } else if (screen.indexOf('group/') == 0) {
+ const groupId = screen.substring(6);
+
+ // TODO: Check valid group ID
+
+ dis.dispatch({
+ action: 'view_group',
+ group_id: groupId,
+ });
} else {
console.info("Ignoring showScreen for '%s'", screen);
}
@@ -1029,6 +1047,11 @@ module.exports = React.createClass({
});
},
+ onGroupClick: function(event, groupId) {
+ event.preventDefault();
+ dis.dispatch({action: 'view_group', group_id: groupId});
+ },
+
onLogoutClick: function(event) {
dis.dispatch({
action: 'logout',
diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js
index d9b0b78982..b96730145a 100644
--- a/src/linkify-matrix.js
+++ b/src/linkify-matrix.js
@@ -108,11 +108,53 @@ function matrixLinkify(linkify) {
S_AT_NAME_COLON_DOMAIN.on(TT.DOT, S_AT_NAME_COLON_DOMAIN_DOT);
S_AT_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID);
+
+
+ var GROUPID = function(value) {
+ MultiToken.call(this, value);
+ this.type = 'groupid';
+ this.isLink = true;
+ };
+ GROUPID.prototype = new MultiToken();
+
+ var S_PLUS = new linkify.parser.State();
+ var S_PLUS_NAME = new linkify.parser.State();
+ var S_PLUS_NAME_COLON = new linkify.parser.State();
+ var S_PLUS_NAME_COLON_DOMAIN = new linkify.parser.State();
+ var S_PLUS_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
+ var S_GROUPID = new linkify.parser.State(GROUPID);
+
+ var groupid_tokens = [
+ TT.DOT,
+ TT.UNDERSCORE,
+ TT.PLUS,
+ TT.NUM,
+ TT.DOMAIN,
+ TT.TLD,
+
+ // as in roomname_tokens
+ TT.LOCALHOST,
+ ];
+
+ S_START.on(TT.PLUS, S_PLUS);
+
+ S_PLUS.on(groupid_tokens, S_PLUS_NAME);
+ S_PLUS_NAME.on(groupid_tokens, S_PLUS_NAME);
+ S_PLUS_NAME.on(TT.DOMAIN, S_PLUS_NAME);
+
+ S_PLUS_NAME.on(TT.COLON, S_PLUS_NAME_COLON);
+
+ S_PLUS_NAME_COLON.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN);
+ S_PLUS_NAME_COLON.on(TT.LOCALHOST, S_GROUPID); // accept +foo:localhost
+ S_PLUS_NAME_COLON_DOMAIN.on(TT.DOT, S_PLUS_NAME_COLON_DOMAIN_DOT);
+ S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN);
+ S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_GROUPID);
}
// stubs, overwritten in MatrixChat's componentDidMount
matrixLinkify.onUserClick = function(e, userId) { e.preventDefault(); };
matrixLinkify.onAliasClick = function(e, roomAlias) { e.preventDefault(); };
+matrixLinkify.onGroupClick = function(e, groupId) { e.preventDefault(); };
var escapeRegExp = function(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -143,6 +185,12 @@ matrixLinkify.options = {
matrixLinkify.onAliasClick(e, href);
}
};
+ case "groupid":
+ return {
+ click: function(e) {
+ matrixLinkify.onGroupClick(e, href);
+ }
+ };
}
},
@@ -150,6 +198,7 @@ matrixLinkify.options = {
switch (type) {
case 'roomalias':
case 'userid':
+ case "groupid":
return matrixLinkify.MATRIXTO_BASE_URL + '/#/' + href;
default:
var m;