diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js index 1fe7bd08..40564e55 100644 --- a/src/controllers/organisms/RoomView.js +++ b/src/controllers/organisms/RoomView.js @@ -288,6 +288,7 @@ module.exports = { fillSpace: function() { if (!this.refs.messagePanel) return; + if (this.state.searchResults) return; // TODO: paginate search results var messageWrapperScroll = this._getScrollNode(); if (messageWrapperScroll.scrollTop < messageWrapperScroll.clientHeight && this.state.room.oldState.paginationToken) { this.setState({paginating: true}); @@ -426,7 +427,7 @@ module.exports = { onSearch: function(term, scope) { var filter; - if (scope === "Room") { // FIXME: should be enum + if (scope === "Room") { filter = { // XXX: it's unintuitive that the filter for searching doesn't have the same shape as the v2 filter API :( rooms: [ @@ -443,6 +444,14 @@ module.exports = { search_term: term, filter: filter, order_by: "recent", + include_state: true, + groupings: { + group_by: [ + { + key: "room_id" + } + ] + }, event_context: { before_limit: 1, after_limit: 1, @@ -451,9 +460,28 @@ module.exports = { } } }).then(function(data) { + // for debugging: + // data.search_categories.room_events.highlights = ["hello", "everybody"]; + + var highlights; + if (data.search_categories.room_events.highlights && + data.search_categories.room_events.highlights.length > 0) + { + // postgres on synapse returns us precise details of the + // strings which actually got matched for highlighting. + // for overlapping highlights, favour longer (more specific) terms first + highlights = data.search_categories.room_events.highlights + .sort(function(a, b) { b.length - a.length }); + } + else { + // sqlite doesn't, so just try to highlight the literal search term + highlights = [ term ]; + } + self.setState({ - searchTerm: term, + highlights: highlights, searchResults: data, + searchScope: scope, }); }, function(error) { var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); @@ -466,39 +494,54 @@ module.exports = { getEventTiles: function() { var DateSeparator = sdk.getComponent('molecules.DateSeparator'); + var cli = MatrixClientPeg.get(); var ret = []; var count = 0; var EventTile = sdk.getComponent('messages.Event'); + var self = this; - if (this.state.searchResults) { - // XXX: this dance is foul, due to the results API not returning sorted results + if (this.state.searchResults && + this.state.searchResults.search_categories.room_events.results && + this.state.searchResults.search_categories.room_events.groups) + { + // XXX: this dance is foul, due to the results API not directly returning sorted results var results = this.state.searchResults.search_categories.room_events.results; - var eventIds = Object.keys(results); - // XXX: todo: merge overlapping results somehow? - // XXX: why doesn't searching on name work? - var resultList = eventIds.map(function(key) { return results[key]; }); // .sort(function(a, b) { b.rank - a.rank }); - for (var i = 0; i < resultList.length; i++) { - var ts1 = resultList[i].result.origin_server_ts; - ret.push(
  • ); // Rank: {resultList[i].rank} - var mxEv = new Matrix.MatrixEvent(resultList[i].result); - if (resultList[i].context.events_before[0]) { - var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_before[0]); - if (EventTile.haveTileForEvent(mxEv2)) { - ret.push(
  • ); + var roomIdGroups = this.state.searchResults.search_categories.room_events.groups.room_id; + + Object.keys(roomIdGroups) + .sort(function(a, b) { roomIdGroups[a].order - roomIdGroups[b].order }) // WHY NOT RETURN AN ORDERED ARRAY?!?!?! + .forEach(function(roomId) + { + // XXX: todo: merge overlapping results somehow? + // XXX: why doesn't searching on name work? + if (self.state.searchScope === 'All') { + ret.push(
  • Room: { cli.getRoom(roomId).name }

  • ); + } + + var resultList = roomIdGroups[roomId].results.map(function(eventId) { return results[eventId]; }); + for (var i = resultList.length - 1; i >= 0; i--) { + var ts1 = resultList[i].result.origin_server_ts; + ret.push(
  • ); // Rank: {resultList[i].rank} + var mxEv = new Matrix.MatrixEvent(resultList[i].result); + if (resultList[i].context.events_before[0]) { + var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_before[0]); + if (EventTile.haveTileForEvent(mxEv2)) { + ret.push(
  • ); + } + } + if (EventTile.haveTileForEvent(mxEv)) { + ret.push(
  • ); + } + if (resultList[i].context.events_after[0]) { + var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_after[0]); + if (EventTile.haveTileForEvent(mxEv2)) { + ret.push(
  • ); + } } } - if (EventTile.haveTileForEvent(mxEv)) { - ret.push(
  • ); - } - if (resultList[i].context.events_after[0]) { - var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_after[0]); - if (EventTile.haveTileForEvent(mxEv2)) { - ret.push(
  • ); - } - } - } + }); return ret; } @@ -530,7 +573,7 @@ module.exports = { var ts0 = this.state.room.timeline[i - 1].getTs(); var ts1 = this.state.room.timeline[i].getTs(); if (new Date(ts0).toDateString() !== new Date(ts1).toDateString()) { - dateSeparator = ; + dateSeparator =
  • ; continuation = false; } } diff --git a/src/skins/vector/css/atoms/MemberAvatar.css b/src/skins/vector/css/atoms/MemberAvatar.css index e76c2ad1..5f7d18cb 100644 --- a/src/skins/vector/css/atoms/MemberAvatar.css +++ b/src/skins/vector/css/atoms/MemberAvatar.css @@ -15,8 +15,7 @@ limitations under the License. */ .mx_MemberAvatar { - /* commenting this out as it breaks on FF seemingly */ -/* position: relative; */ + position: relative; } .mx_MemberAvatar_initial { diff --git a/src/skins/vector/css/common.css b/src/skins/vector/css/common.css index ba931b9c..af2d4be4 100644 --- a/src/skins/vector/css/common.css +++ b/src/skins/vector/css/common.css @@ -22,7 +22,12 @@ html { } body { - font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif; + /* Myriad Pro lacks combining diacritics, so these will fall through + to the next font. Helevetica's diacritics however do not combine + nicely with Myriad Pro (on OSX, at least) and result in a huge + horizontal mess. Arial empirically gets it right, hence prioritising + Arial here. */ + font-family: 'Myriad Pro', Arial, Helvetica, Sans-Serif; font-size: 16px; color: #454545; border: 0px; diff --git a/src/skins/vector/css/molecules/EventAsTextTile.css b/src/skins/vector/css/molecules/EventAsTextTile.css index d18fdc80..da953522 100644 --- a/src/skins/vector/css/molecules/EventAsTextTile.css +++ b/src/skins/vector/css/molecules/EventAsTextTile.css @@ -16,4 +16,5 @@ limitations under the License. .mx_EventAsTextTile { opacity: 0.5; + overflow-y: hidden; } diff --git a/src/skins/vector/css/molecules/EventTile.css b/src/skins/vector/css/molecules/EventTile.css index 697655e8..152fde1f 100644 --- a/src/skins/vector/css/molecules/EventTile.css +++ b/src/skins/vector/css/molecules/EventTile.css @@ -27,6 +27,7 @@ limitations under the License. margin-left: -73px; margin-top: -4px; float: left; + position: relative; } .mx_EventTile_avatar img { @@ -44,6 +45,7 @@ limitations under the License. font-size: 14px; margin-bottom: 4px; display: block; + overflow-y: hidden; } .mx_EventTile .mx_MessageTimestamp { @@ -63,6 +65,7 @@ limitations under the License. .mx_MessageTile_content { display: block; margin-right: 100px; + overflow-y: hidden; } /* Various markdown overrides */ @@ -87,6 +90,12 @@ limitations under the License. color: #76cfa6; } +.mx_MessageTile_content .markdown-body .hljs { + display: inherit ! important; +} + +/* end of overrides */ + .mx_MessageTile_searchHighlight { background-color: #76cfa6; color: #fff; diff --git a/src/skins/vector/css/molecules/MemberInfo.css b/src/skins/vector/css/molecules/MemberInfo.css index 6471a86c..ac11dde7 100644 --- a/src/skins/vector/css/molecules/MemberInfo.css +++ b/src/skins/vector/css/molecules/MemberInfo.css @@ -37,8 +37,10 @@ limitations under the License. } .mx_MemberInfo_profileField { - opacity: 0.6; + font-color: #999999; font-size: 14px; + position: relative; + background-color: #fff; } .mx_MemberInfo_buttons { diff --git a/src/skins/vector/css/molecules/MemberTile.css b/src/skins/vector/css/molecules/MemberTile.css index cfeaeaee..de34de59 100644 --- a/src/skins/vector/css/molecules/MemberTile.css +++ b/src/skins/vector/css/molecules/MemberTile.css @@ -98,10 +98,6 @@ limitations under the License. opacity: 0.25; } -.mx_MemberTile_zalgo { - font-family: Helvetica, Arial, Sans-Serif; -} - .mx_MemberTile:hover .mx_MessageTimestamp { display: block; } diff --git a/src/skins/vector/css/molecules/MessageComposer.css b/src/skins/vector/css/molecules/MessageComposer.css index 3fb38c31..428d39e6 100644 --- a/src/skins/vector/css/molecules/MessageComposer.css +++ b/src/skins/vector/css/molecules/MessageComposer.css @@ -59,7 +59,7 @@ limitations under the License. box-shadow: none; /* needed for FF */ - font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif; + font-family: 'Myriad Pro', Arial, Helvetica, Sans-Serif; } /* hack for FF as vertical alignment of custom placeholder text is broken */ diff --git a/src/skins/vector/css/molecules/RoomHeader.css b/src/skins/vector/css/molecules/RoomHeader.css index 5519c14d..1a4fdbf3 100644 --- a/src/skins/vector/css/molecules/RoomHeader.css +++ b/src/skins/vector/css/molecules/RoomHeader.css @@ -111,6 +111,7 @@ limitations under the License. .mx_RoomHeader_nametext { display: inline-block; + overflow-y: hidden; } .mx_RoomHeader_settingsButton { diff --git a/src/skins/vector/css/molecules/SenderProfile.css b/src/skins/vector/css/molecules/SenderProfile.css index 45db913e..fd88ee27 100644 --- a/src/skins/vector/css/molecules/SenderProfile.css +++ b/src/skins/vector/css/molecules/SenderProfile.css @@ -13,8 +13,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ - -.mx_SenderProfile_zalgo { - font-family: Helvetica, Arial, Sans-Serif; - display: table-row ! important; -} diff --git a/src/skins/vector/css/organisms/MemberList.css b/src/skins/vector/css/organisms/MemberList.css index df699e64..774f177a 100644 --- a/src/skins/vector/css/organisms/MemberList.css +++ b/src/skins/vector/css/organisms/MemberList.css @@ -45,7 +45,7 @@ limitations under the License. } .mx_MemberList_invite { - font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif; + font-family: 'Myriad Pro', Arial, Helvetica, Sans-Serif; border-radius: 3px; border: 1px solid #f0f0f0; padding: 9px; diff --git a/src/skins/vector/css/organisms/RoomView.css b/src/skins/vector/css/organisms/RoomView.css index 870640f1..94fff290 100644 --- a/src/skins/vector/css/organisms/RoomView.css +++ b/src/skins/vector/css/organisms/RoomView.css @@ -125,7 +125,7 @@ limitations under the License. clear: both; } -.mx_RoomView_MessageList > h2 { +.mx_RoomView_MessageList h2 { clear: both; margin-top: 32px; margin-bottom: 8px; diff --git a/src/skins/vector/skindex.js b/src/skins/vector/skindex.js index 6137200f..859641fb 100644 --- a/src/skins/vector/skindex.js +++ b/src/skins/vector/skindex.js @@ -50,12 +50,10 @@ skin['messages.TextualEvent'] = require('matrix-react-sdk/lib/components/views/m 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.TextualMessage'] = require('matrix-react-sdk/lib/components/views/messages/TextualMessage'); skin['messages.UnknownMessage'] = require('matrix-react-sdk/lib/components/views/messages/UnknownMessage'); skin['rooms.MemberInfo'] = require('matrix-react-sdk/lib/components/views/rooms/MemberInfo'); @@ -101,4 +99,4 @@ skin['organisms.ViewSource'] = require('./views/organisms/ViewSource'); skin['pages.CompatibilityPage'] = require('./views/pages/CompatibilityPage'); skin['pages.MatrixChat'] = require('./views/pages/MatrixChat'); -module.exports = skin; \ No newline at end of file +module.exports = skin; diff --git a/src/skins/vector/views/molecules/SenderProfile.js b/src/skins/vector/views/molecules/SenderProfile.js index c09685aa..ef0173d9 100644 --- a/src/skins/vector/views/molecules/SenderProfile.js +++ b/src/skins/vector/views/molecules/SenderProfile.js @@ -17,11 +17,6 @@ limitations under the License. 'use strict'; var React = require('react'); -var classNames = require("classnames"); - -// 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: 'SenderProfile', @@ -30,18 +25,12 @@ module.exports = React.createClass({ var mxEvent = this.props.mxEvent; var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); - var classes = classNames({ - mx_SenderProfile: true, - // taken from https://en.wikipedia.org/wiki/Combining_character - mx_SenderProfile_zalgo: zalgo.test(name), - }); - var msgtype = mxEvent.getContent().msgtype; if (msgtype && msgtype == 'm.emote') { name = ''; // emote message must include the name so don't duplicate it } return ( - + {name} { this.props.aux } ); diff --git a/src/skins/vector/views/organisms/RoomView.js b/src/skins/vector/views/organisms/RoomView.js index 537bbd55..a34d321e 100644 --- a/src/skins/vector/views/organisms/RoomView.js +++ b/src/skins/vector/views/organisms/RoomView.js @@ -206,7 +206,7 @@ module.exports = React.createClass({ if (this.state.syncState === "ERROR") { statusBar = (
    - /!\ + /!\
    Connectivity to the server has been lost. @@ -221,7 +221,7 @@ module.exports = React.createClass({ else if (this.state.hasUnsentMessages) { statusBar = (
    - /!\ + /!\
    Some of your messages have not been sent. @@ -291,6 +291,12 @@ module.exports = React.createClass({
    ; } + var messageComposer; + if (!this.state.searchResults) { + messageComposer = + + } + return (
    - {statusBar} + { this.state.searchResults ? null : statusBar }
    - + { messageComposer }
    ); }