handle matrix.to links correctly. add partial support for #/user URLs

This commit is contained in:
Matthew Hodgson 2016-08-28 01:55:42 +01:00
parent 50d09f73f5
commit ad873c2b60
3 changed files with 92 additions and 44 deletions

View file

@ -85,12 +85,28 @@ var sanitizeHtmlParams = {
transformTags: { // custom to matrix transformTags: { // custom to matrix
// add blank targets to all hyperlinks except vector URLs // add blank targets to all hyperlinks except vector URLs
'a': function(tagName, attribs) { 'a': function(tagName, attribs) {
var m = attribs.href ? attribs.href.match(linkifyMatrix.VECTOR_URL_PATTERN) : null; if (attribs.href) {
attribs.target = '_blank'; // by default
var m;
// FIXME: horrible duplication with linkify-matrix
m = attribs.href.match(linkifyMatrix.VECTOR_URL_PATTERN);
if (m) { if (m) {
attribs.href = m[1];
delete attribs.target;
}
m = attribs.href.match(linkifyMatrix.MATRIXTO_URL_PATTERN);
if (m) {
var entity = m[1];
if (entity[0] === '@') {
attribs.href = '#'; // TODO
}
else if (entity[0] === '#') {
attribs.href = '#/room/' + entity;
}
delete attribs.target; delete attribs.target;
} }
else {
attribs.target = '_blank';
} }
attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/ attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/
return { tagName: tagName, attribs : attribs }; return { tagName: tagName, attribs : attribs };

View file

@ -176,12 +176,12 @@ module.exports = React.createClass({
// this can technically be done anywhere but doing this here keeps all // this can technically be done anywhere but doing this here keeps all
// the routing url path logic together. // the routing url path logic together.
if (this.onAliasClick) { // if (this.onAliasClick) {
linkifyMatrix.onAliasClick = this.onAliasClick; // linkifyMatrix.onAliasClick = this.onAliasClick;
} // }
if (this.onUserClick) { // if (this.onUserClick) {
linkifyMatrix.onUserClick = this.onUserClick; // linkifyMatrix.onUserClick = this.onUserClick;
} // }
window.addEventListener('resize', this.handleResize); window.addEventListener('resize', this.handleResize);
this.handleResize(); this.handleResize();
@ -739,6 +739,16 @@ module.exports = React.createClass({
} else { } else {
dis.dispatch(payload); dis.dispatch(payload);
} }
} else if (screen.indexOf('user/') == 0) {
var userId = screen.substring(5);
var member = new Matrix.RoomMember(null, userId);
if (member) {
// FIXME: this doesn't work yet
dis.dispatch({
action: 'view_user',
member: member,
});
}
} }
else { else {
console.info("Ignoring showScreen for '%s'", screen); console.info("Ignoring showScreen for '%s'", screen);
@ -751,31 +761,29 @@ module.exports = React.createClass({
} }
}, },
onAliasClick: function(event, alias) { // onAliasClick: function(event, alias) {
event.preventDefault(); // event.preventDefault();
dis.dispatch({action: 'view_room', room_alias: alias}); // dis.dispatch({action: 'view_room', room_alias: alias});
}, // },
onUserClick: function(event, userId) { // onUserClick: function(event, userId) {
event.preventDefault(); // event.preventDefault();
/* // // var MemberInfo = sdk.getComponent('rooms.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, // // right: window.innerWidth - event.pageX,
right: window.innerWidth - event.pageX, // // top: event.pageY
top: event.pageY // // });
});
*/
var member = new Matrix.RoomMember(null, userId); // var member = new Matrix.RoomMember(null, userId);
if (!member) { return; } // if (!member) { return; }
dis.dispatch({ // dis.dispatch({
action: 'view_user', // action: 'view_user',
member: member, // member: member,
}); // });
}, // },
onLogoutClick: function(event) { onLogoutClick: function(event) {
dis.dispatch({ dis.dispatch({

View file

@ -95,20 +95,25 @@ function matrixLinkify(linkify) {
S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID); S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID);
} }
matrixLinkify.onUserClick = function(e, userId) { e.preventDefault(); }; // stubs, overwritten in MatrixChat's componentDidMount
matrixLinkify.onAliasClick = function(e, roomAlias) { e.preventDefault(); }; // matrixLinkify.onUserClick = function(e, userId) { e.preventDefault(); };
// matrixLinkify.onAliasClick = function(e, roomAlias) { e.preventDefault(); };
var escapeRegExp = function(string) { var escapeRegExp = function(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}; };
// we only recognise URLs which match our current URL as being the same app // Recognise URLs from both our local vector and official vector as vector.
// as if someone explicitly links to vector.im/develop and we're on vector.im/beta // anyone else really should be using matrix.to.
// they may well be trying to get us to explicitly go to develop. matrixLinkify.VECTOR_URL_PATTERN = "^(?:https?:\/\/)?(?:"
// FIXME: intercept matrix.to URLs as well. + escapeRegExp(window.location.host + window.location.pathname) + "|"
matrixLinkify.VECTOR_URL_PATTERN = "^(https?:\/\/)?" + escapeRegExp(window.location.host + window.location.pathname); + "(?:www\\.)?vector\\.im/(?:beta|staging|develop)/"
+ ")(#.*)";
matrixLinkify.MATRIXTO_URL_PATTERN = "^(?:https?:\/\/)?(?:www\\.)?matrix\\.to/#/((#|@).*)";
matrixLinkify.options = { matrixLinkify.options = {
/*
events: function (href, type) { events: function (href, type) {
switch (type) { switch (type) {
case "userid": case "userid":
@ -125,14 +130,31 @@ matrixLinkify.options = {
}; };
} }
}, },
*/
formatHref: function (href, type) { formatHref: function (href, type) {
switch (type) { switch (type) {
case 'roomalias': case 'roomalias':
return '#/room/' + href; return '#/room/' + href;
case 'userid': case 'userid':
return '#'; return '#/user/' + href;
default: default:
var m;
// FIXME: horrible duplication with HtmlUtils' transform tags
m = href.match(matrixLinkify.VECTOR_URL_PATTERN);
if (m) {
return m[1];
}
m = href.match(matrixLinkify.MATRIXTO_URL_PATTERN);
if (m) {
var entity = m[1];
if (entity[0] === '@') {
return '#'; // TODO
}
else if (entity[0] === '#') {
return '#/room/' + entity;
}
}
return href; return href;
} }
}, },
@ -143,7 +165,9 @@ matrixLinkify.options = {
target: function(href, type) { target: function(href, type) {
if (type === 'url') { if (type === 'url') {
if (href.match(matrixLinkify.VECTOR_URL_PATTERN)) { if (href.match(matrixLinkify.VECTOR_URL_PATTERN) ||
href.match(matrixLinkify.MATRIXTO_URL_PATTERN))
{
return null; return null;
} }
else { else {