From 702a8ff4a947adba2f859f9e063655d8d3652b44 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sun, 8 Dec 2019 01:01:19 +0000 Subject: [PATCH 01/93] Change ref handling in TextualBody to prevent it parsing generated nodes Remove unused paths Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/HtmlUtils.js | 5 ++-- .../views/context_menus/MessageContextMenu.js | 2 +- src/components/views/messages/TextualBody.js | 29 ++++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 2b7384a5aa..9cf3994ff4 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -394,6 +394,7 @@ class TextHighlighter extends BaseHighlighter { * opts.stripReplyFallback: optional argument specifying the event is a reply and so fallback needs removing * opts.returnString: return an HTML string rather than JSX elements * opts.forComposerQuote: optional param to lessen the url rewriting done by sanitization, for quoting into composer + * opts.ref: React ref to attach to any React components returned (not compatible with opts.returnString) */ export function bodyToHtml(content, highlights, opts={}) { const isHtmlMessage = content.format === "org.matrix.custom.html" && content.formatted_body; @@ -476,8 +477,8 @@ export function bodyToHtml(content, highlights, opts={}) { }); return isDisplayedWithHtml ? - : - { strippedBody }; + : + { strippedBody }; } /** diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index efbfc4322f..2084a67cdc 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -422,7 +422,7 @@ module.exports = createReactClass({ ); - if (this.props.eventTileOps && this.props.eventTileOps.getInnerText) { + if (this.props.eventTileOps) { // this event is rendered using TextuaLBody quoteButton = ( { _t('Quote') } diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 2680c13512..fdfa351df3 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {createRef} from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; @@ -86,6 +86,10 @@ module.exports = createReactClass({ return successful; }, + componentWillMount: function() { + this._content = createRef(); + }, + componentDidMount: function() { this._unmounted = false; if (!this.props.editState) { @@ -94,13 +98,13 @@ module.exports = createReactClass({ }, _applyFormatting() { - this.activateSpoilers(this.refs.content.children); + this.activateSpoilers([this._content.current]); // pillifyLinks BEFORE linkifyElement because plain room/user URLs in the composer // are still sent as plaintext URLs. If these are ever pillified in the composer, // we should be pillify them here by doing the linkifying BEFORE the pillifying. - pillifyLinks(this.refs.content.children, this.props.mxEvent); - HtmlUtils.linkifyElement(this.refs.content); + pillifyLinks([this._content.current], this.props.mxEvent); + HtmlUtils.linkifyElement(this._content.current); this.calculateUrlPreview(); if (this.props.mxEvent.getContent().format === "org.matrix.custom.html") { @@ -163,7 +167,8 @@ module.exports = createReactClass({ //console.info("calculateUrlPreview: ShowUrlPreview for %s is %s", this.props.mxEvent.getId(), this.props.showUrlPreview); if (this.props.showUrlPreview) { - let links = this.findLinks(this.refs.content.children); + // pass only the first child which is the event tile otherwise this recurses on edited events + let links = this.findLinks([this._content.current]); if (links.length) { // de-dup the links (but preserve ordering) const seen = new Set(); @@ -325,10 +330,6 @@ module.exports = createReactClass({ global.localStorage.removeItem("hide_preview_" + this.props.mxEvent.getId()); } }, - - getInnerText: () => { - return this.refs.content.innerText; - }, }; }, @@ -424,6 +425,7 @@ module.exports = createReactClass({ disableBigEmoji: content.msgtype === "m.emote" || !SettingsStore.getValue('TextualBody.enableBigEmoji'), // Part of Replies fallback support stripReplyFallback: stripReply, + ref: this._content, }); if (this.props.replacingEventId) { body = [body, this._renderEditedMarker()]; @@ -450,15 +452,14 @@ module.exports = createReactClass({ switch (content.msgtype) { case "m.emote": - const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); return ( - + - { name } + { mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender() }   { body } @@ -467,14 +468,14 @@ module.exports = createReactClass({ ); case "m.notice": return ( - + { body } { widgets } ); default: // including "m.text" return ( - + { body } { widgets } From 4489b5a21aa7550d1bfeee1b4f3960ebc4698cb7 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 28 Dec 2019 20:05:55 +0000 Subject: [PATCH 02/93] Escape HTML in og:description and render any html &-encoded entities --- src/components/views/rooms/LinkPreviewWidget.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js index ee63cd1bb7..06c0201af8 100644 --- a/src/components/views/rooms/LinkPreviewWidget.js +++ b/src/components/views/rooms/LinkPreviewWidget.js @@ -128,15 +128,15 @@ module.exports = createReactClass({ } const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + // Escape to prevent any HTML injections, we can't replace & as the description may contain & encoded html entities + const safeDescription = (p["og:description"] || "").replace("<", "<").replace(">", ">"); return (
{ img }
{ p["og:site_name"] ? (" - " + p["og:site_name"]) : null }
-
- { p["og:description"] } -
+
Date: Sun, 5 Jan 2020 22:22:09 +0000 Subject: [PATCH 03/93] Use html-entities instead Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 3 ++- src/components/views/rooms/LinkPreviewWidget.js | 10 ++++++---- yarn.lock | 5 +++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7ef14e6635..7e2c242b3a 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,6 @@ "file-saver": "^1.3.3", "filesize": "3.5.6", "flux": "2.1.1", - "react-focus-lock": "^2.2.1", "focus-visible": "^5.0.2", "fuse.js": "^2.2.0", "gemini-scrollbar": "github:matrix-org/gemini-scrollbar#91e1e566", @@ -82,6 +81,7 @@ "glob": "^5.0.14", "glob-to-regexp": "^0.4.1", "highlight.js": "^9.15.8", + "html-entities": "^1.2.1", "is-ip": "^2.0.0", "isomorphic-fetch": "^2.2.1", "linkifyjs": "^2.1.6", @@ -99,6 +99,7 @@ "react-addons-css-transition-group": "15.6.2", "react-beautiful-dnd": "^4.0.1", "react-dom": "^16.9.0", + "react-focus-lock": "^2.2.1", "react-gemini-scrollbar": "github:matrix-org/react-gemini-scrollbar#9cf17f63b7c0b0ec5f31df27da0f82f7238dc594", "resize-observer-polyfill": "^1.5.0", "sanitize-html": "^1.18.4", diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js index 06c0201af8..4822848233 100644 --- a/src/components/views/rooms/LinkPreviewWidget.js +++ b/src/components/views/rooms/LinkPreviewWidget.js @@ -18,7 +18,9 @@ limitations under the License. import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; -import { linkifyElement } from '../../../HtmlUtils'; +import { AllHtmlEntities } from 'html-entities'; + +import {linkifyElement} from '../../../HtmlUtils'; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; @@ -128,15 +130,15 @@ module.exports = createReactClass({ } const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - // Escape to prevent any HTML injections, we can't replace & as the description may contain & encoded html entities - const safeDescription = (p["og:description"] || "").replace("<", "<").replace(">", ">"); return (
{ img }
{ p["og:site_name"] ? (" - " + p["og:site_name"]) : null }
-
+
+ { AllHtmlEntities.decode(p["og:description"] || "") } +
Date: Mon, 6 Jan 2020 00:18:24 +0000 Subject: [PATCH 04/93] Add comment and delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/LinkPreviewWidget.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js index 4822848233..3b5545e0e0 100644 --- a/src/components/views/rooms/LinkPreviewWidget.js +++ b/src/components/views/rooms/LinkPreviewWidget.js @@ -19,7 +19,6 @@ import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import { AllHtmlEntities } from 'html-entities'; - import {linkifyElement} from '../../../HtmlUtils'; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; @@ -129,6 +128,10 @@ module.exports = createReactClass({
; } + // The description includes &-encoded HTML entities, we decode those as React treats the thing as an + // opaque string. This does not allow any HTML to be injected into the DOM. + const description = AllHtmlEntities.decode(p["og:description"] || ""); + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); return (
@@ -137,7 +140,7 @@ module.exports = createReactClass({
{ p["og:site_name"] ? (" - " + p["og:site_name"]) : null }
- { AllHtmlEntities.decode(p["og:description"] || "") } + { description }
From c551f2983a2495805f9158e1d335e4ae195ad018 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 6 Jan 2020 13:28:29 +0000 Subject: [PATCH 05/93] Add TextualBody-test.js Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 2 + src/components/views/elements/Pill.js | 2 +- src/utils/pillify.js | 1 + .../views/messages/TextualBody-test.js | 195 +++++++++ test/test-utils.js | 1 + yarn.lock | 376 +++++++++++++++++- 6 files changed, 567 insertions(+), 10 deletions(-) create mode 100644 test/components/views/messages/TextualBody-test.js diff --git a/package.json b/package.json index ad446e26cc..2f8d5f9f7a 100644 --- a/package.json +++ b/package.json @@ -127,6 +127,8 @@ "babel-preset-react": "^6.24.1", "chokidar": "^2.1.2", "concurrently": "^4.0.1", + "enzyme": "^3.10.0", + "enzyme-adapter-react-16": "^1.15.1", "eslint": "^5.12.0", "eslint-config-google": "^0.7.1", "eslint-plugin-babel": "^5.2.1", diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index 99005de03b..da40c53700 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -261,7 +261,7 @@ const Pill = createReactClass({ } const classes = classNames("mx_Pill", pillClass, { - "mx_UserPill_me": userId === MatrixClientPeg.get().credentials.userId, + "mx_UserPill_me": userId === MatrixClientPeg.get().getUserId(), "mx_UserPill_selected": this.props.isSelected, }); diff --git a/src/utils/pillify.js b/src/utils/pillify.js index e943cfe657..ed8a7e18cd 100644 --- a/src/utils/pillify.js +++ b/src/utils/pillify.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import React from "react"; import ReactDOM from 'react-dom'; import MatrixClientPeg from '../MatrixClientPeg'; import SettingsStore from "../settings/SettingsStore"; diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js new file mode 100644 index 0000000000..d93bfd307b --- /dev/null +++ b/test/components/views/messages/TextualBody-test.js @@ -0,0 +1,195 @@ +import React from "react"; +import expect from 'expect'; +import Adapter from "enzyme-adapter-react-16"; +import { configure, mount } from "enzyme"; + +import sdk from "../../../skinned-sdk"; +import {mkEvent, mkStubRoom} from "../../../test-utils"; +import MatrixClientPeg from "../../../../src/MatrixClientPeg"; + +const TextualBody = sdk.getComponent("views.messages.TextualBody"); + +configure({ adapter: new Adapter() }); + +describe("", () => { + afterEach(() => { + MatrixClientPeg.matrixClient = null; + }); + + describe("renders m.emote correctly", () => { + MatrixClientPeg.matrixClient = { + getRoom: () => mkStubRoom("room_id"), + getAccountData: () => undefined, + }; + + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + body: "winks", + msgtype: "m.emote", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe("* sender winks"); + const content = wrapper.find(".mx_EventTile_body"); + expect(content.html()).toBe('winks'); + }); + + describe("renders m.notice correctly", () => { + MatrixClientPeg.matrixClient = { + getRoom: () => mkStubRoom("room_id"), + getAccountData: () => undefined, + }; + + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "bot_sender", + content: { + body: "this is a notice, probably from a bot", + msgtype: "m.notice", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe(ev.getContent().body); + const content = wrapper.find(".mx_EventTile_body"); + expect(content.html()).toBe(`${ ev.getContent().body }`); + }); + + describe("renders plain-text m.text correctly", () => { + MatrixClientPeg.matrixClient = { + getRoom: () => mkStubRoom("room_id"), + getAccountData: () => undefined, + }; + + describe("simple message renders as expected", () => { + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + body: "this is a plaintext message", + msgtype: "m.text", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe(ev.getContent().body); + const content = wrapper.find(".mx_EventTile_body"); + expect(content.html()).toBe(`${ ev.getContent().body }`); + }); + + // If pills were rendered within a Portal/same shadow DOM then it'd be easier to test + describe("linkification get applied correctly into the DOM", () => { + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + body: "Visit https://matrix.org/", + msgtype: "m.text", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe(ev.getContent().body); + const content = wrapper.find(".mx_EventTile_body"); + expect(content.html()).toBe('' + + 'Visit ' + + 'https://matrix.org/'); + }); + }); + + describe("renders formatted m.text correctly", () => { + MatrixClientPeg.matrixClient = { + getRoom: () => mkStubRoom("room_id"), + getAccountData: () => undefined, + getUserId: () => "@me:my_server", + getHomeserverUrl: () => "https://my_server/", + on: () => undefined, + removeListener: () => undefined, + }; + + describe("italics, bold, underline and strikethrough render as expected", () => { + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + body: "foo *baz* __bar__ del u", + msgtype: "m.text", + format: "org.matrix.custom.html", + formatted_body: "foo baz bar del u", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe("foo baz bar del u"); + const content = wrapper.find(".mx_EventTile_body"); + expect(content.html()).toBe('' + + ev.getContent().formatted_body + ''); + }); + + describe("spoilers get injected properly into the DOM", () => { + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + body: "Hey [Spoiler for movie](mxc://someserver/somefile)", + msgtype: "m.text", + format: "org.matrix.custom.html", + formatted_body: "Hey the movie was awesome", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe("Hey (movie) the movie was awesome"); + const content = wrapper.find(".mx_EventTile_body"); + expect(content.html()).toBe('' + + 'Hey ' + + '' + + '(movie) ' + + 'the movie was awesome' + + ''); + }); + + // If pills were rendered within a Portal/same shadow DOM then it'd be easier to test + describe("pills get injected correctly into the DOM", () => { + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + body: "Hey User", + msgtype: "m.text", + format: "org.matrix.custom.html", + formatted_body: "Hey Member", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe("Hey Member"); + const content = wrapper.find(".mx_EventTile_body"); + expect(content.html()).toBe('' + + 'Hey ' + + '' + + 'Member' + + ''); + }); + }); +}); + + diff --git a/test/test-utils.js b/test/test-utils.js index 5c8c7f8a10..e27fff3388 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -238,6 +238,7 @@ export function mkStubRoom(roomId = null) { getMember: sinon.stub().returns({ userId: '@member:domain.bla', name: 'Member', + rawDisplayName: 'Member', roomId: roomId, getAvatarUrl: () => 'mxc://avatar.url/image.png', }), diff --git a/yarn.lock b/yarn.lock index a491ba3941..c32a108934 100644 --- a/yarn.lock +++ b/yarn.lock @@ -531,6 +531,22 @@ agentkeepalive@^3.4.1: dependencies: humanize-ms "^1.2.1" +airbnb-prop-types@^2.15.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/airbnb-prop-types/-/airbnb-prop-types-2.15.0.tgz#5287820043af1eb469f5b0af0d6f70da6c52aaef" + integrity sha512-jUh2/hfKsRjNFC4XONQrxo/n/3GG4Tn6Hl0WlFQN5PY9OMC9loSCoAYKnZsWaP8wEfd5xcrPloK0Zg6iS1xwVA== + dependencies: + array.prototype.find "^2.1.0" + function.prototype.name "^1.1.1" + has "^1.0.3" + is-regex "^1.0.4" + object-is "^1.0.1" + object.assign "^4.1.0" + object.entries "^1.1.0" + prop-types "^15.7.2" + prop-types-exact "^1.2.0" + react-is "^16.9.0" + ajv-errors@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" @@ -659,6 +675,11 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-filter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" + integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= + array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" @@ -699,6 +720,22 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +array.prototype.find@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.1.0.tgz#630f2eaf70a39e608ac3573e45cf8ccd0ede9ad7" + integrity sha512-Wn41+K1yuO5p7wRZDl7890c3xvv5UBrfVXTVIe28rSQb6LS0fZMDrQB6PAcxQFRFy6vJTLDc3A2+3CjQdzVKRg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.13.0" + +array.prototype.flat@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" + integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + arraybuffer.slice@~0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" @@ -1621,6 +1658,11 @@ body-parser@^1.16.1: raw-body "2.4.0" type-is "~1.6.17" +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1957,6 +1999,18 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +cheerio@^1.0.0-rc.3: + version "1.0.0-rc.3" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6" + integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA== + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.1" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash "^4.15.0" + parse5 "^3.0.1" + chokidar@^1.6.1: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" @@ -2136,7 +2190,7 @@ commander@2.15.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== -commander@^2.11.0, commander@^2.20.0: +commander@^2.11.0, commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2374,6 +2428,21 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -2592,6 +2661,11 @@ dir-glob@^2.2.2: dependencies: path-type "^3.0.0" +discontinuous-range@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" + integrity sha1-44Mx8IRLukm5qctxx3FYWqsbxlo= + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -2631,12 +2705,20 @@ dom-serializer@0: domelementtype "^2.0.1" entities "^2.0.0" +dom-serializer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domelementtype@1, domelementtype@^1.3.1: +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== @@ -2653,6 +2735,14 @@ domhandler@^2.3.0: dependencies: domelementtype "1" +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + domutils@^1.5.1: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" @@ -2816,7 +2906,7 @@ ent@~2.2.0: resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= -entities@^1.1.1, "entities@~ 1.1.1": +entities@^1.1.1, "entities@~ 1.1.1", entities@~1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== @@ -2826,6 +2916,69 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== +enzyme-adapter-react-16@^1.15.1: + version "1.15.2" + resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.2.tgz#b16db2f0ea424d58a808f9df86ab6212895a4501" + integrity sha512-SkvDrb8xU3lSxID8Qic9rB8pvevDbLybxPK6D/vW7PrT0s2Cl/zJYuXvsd1EBTz0q4o3iqG3FJhpYz3nUNpM2Q== + dependencies: + enzyme-adapter-utils "^1.13.0" + enzyme-shallow-equal "^1.0.1" + has "^1.0.3" + object.assign "^4.1.0" + object.values "^1.1.1" + prop-types "^15.7.2" + react-is "^16.12.0" + react-test-renderer "^16.0.0-0" + semver "^5.7.0" + +enzyme-adapter-utils@^1.13.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.13.0.tgz#01c885dde2114b4690bf741f8dc94cee3060eb78" + integrity sha512-YuEtfQp76Lj5TG1NvtP2eGJnFKogk/zT70fyYHXK2j3v6CtuHqc8YmgH/vaiBfL8K1SgVVbQXtTcgQZFwzTVyQ== + dependencies: + airbnb-prop-types "^2.15.0" + function.prototype.name "^1.1.2" + object.assign "^4.1.0" + object.fromentries "^2.0.2" + prop-types "^15.7.2" + semver "^5.7.1" + +enzyme-shallow-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.1.tgz#7afe03db3801c9b76de8440694096412a8d9d49e" + integrity sha512-hGA3i1so8OrYOZSM9whlkNmVHOicJpsjgTzC+wn2JMJXhq1oO4kA4bJ5MsfzSIcC71aLDKzJ6gZpIxrqt3QTAQ== + dependencies: + has "^1.0.3" + object-is "^1.0.2" + +enzyme@^3.10.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.11.0.tgz#71d680c580fe9349f6f5ac6c775bc3e6b7a79c28" + integrity sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw== + dependencies: + array.prototype.flat "^1.2.3" + cheerio "^1.0.0-rc.3" + enzyme-shallow-equal "^1.0.1" + function.prototype.name "^1.1.2" + has "^1.0.3" + html-element-map "^1.2.0" + is-boolean-object "^1.0.1" + is-callable "^1.1.5" + is-number-object "^1.0.4" + is-regex "^1.0.5" + is-string "^1.0.5" + is-subset "^0.1.1" + lodash.escape "^4.0.1" + lodash.isequal "^4.5.0" + object-inspect "^1.7.0" + object-is "^1.0.2" + object.assign "^4.1.0" + object.entries "^1.1.1" + object.values "^1.1.1" + raf "^3.4.1" + rst-selector-parser "^2.2.3" + string.prototype.trim "^1.2.1" + err-code@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" @@ -2861,6 +3014,23 @@ es-abstract@^1.12.0, es-abstract@^1.15.0, es-abstract@^1.16.2, es-abstract@^1.7. string.prototype.trimleft "^2.1.0" string.prototype.trimright "^2.1.0" +es-abstract@^1.13.0, es-abstract@^1.17.0-next.1: + version "1.17.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.0.tgz#f42a517d0036a5591dbb2c463591dc8bb50309b1" + integrity sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + es-get-iterator@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.0.1.tgz#ebc4d3bbc2d59dd95a0ecef441ca2dbce7d9e2cd" @@ -3600,6 +3770,15 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function.prototype.name@^1.1.1, function.prototype.name@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.2.tgz#5cdf79d7c05db401591dfde83e3b70c5123e9a45" + integrity sha512-C8A+LlHBJjB2AdcRPorc5JvJ5VUoWlXdEHLOJdCI7kjHEtGTpHQUiqMvCIKUwIsGwZX2jZJy761AXsn356bJQg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + functions-have-names "^1.2.0" + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" @@ -3988,12 +4167,19 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== +html-element-map@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/html-element-map/-/html-element-map-1.2.0.tgz#dfbb09efe882806af63d990cf6db37993f099f22" + integrity sha512-0uXq8HsuG1v2TmQ8QkIhzbrqeskE4kn52Q18QJ9iAA/SnHoEKXWiUxHQtclRsCFWEUD2So34X+0+pZZu862nnw== + dependencies: + array-filter "^1.0.0" + html-tags@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= -htmlparser2@^3.10.0: +htmlparser2@^3.10.0, htmlparser2@^3.9.1: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -4312,6 +4498,11 @@ is-boolean-object@^1.0.0: resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93" integrity sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M= +is-boolean-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e" + integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ== + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -4327,6 +4518,11 @@ is-callable@^1.0.4, is-callable@^1.1.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -4504,6 +4700,11 @@ is-number-object@^1.0.3: resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.3.tgz#f265ab89a9f445034ef6aff15a8f00b00f551799" integrity sha1-8mWrian0RQNO9q/xWo8AsA9VF5k= +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -4567,6 +4768,13 @@ is-regex@^1.0.3, is-regex@^1.0.4: dependencies: has "^1.0.1" +is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== + dependencies: + has "^1.0.3" + is-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" @@ -4587,6 +4795,16 @@ is-string@^1.0.4: resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.4.tgz#cc3a9b69857d621e963725a24caeec873b826e64" integrity sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ= +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + +is-subset@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" + integrity sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY= + is-supported-regexp-flag@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz#21ee16518d2c1dd3edd3e9a0d57e50207ac364ca" @@ -5072,11 +5290,21 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= +lodash.escape@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" + integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg= + lodash.escaperegexp@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c= +lodash.flattendeep@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" + integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= + lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -5087,6 +5315,11 @@ lodash.isboolean@^3.0.3: resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" @@ -5112,7 +5345,7 @@ lodash.unescape@4.0.1: resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= -lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.1: +lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.1: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -5559,6 +5792,11 @@ mocha@^5.0.5: mkdirp "0.5.1" supports-color "5.4.0" +moo@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/moo/-/moo-0.4.3.tgz#3f847a26f31cf625a956a87f2b10fbc013bfd10e" + integrity sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -5613,6 +5851,17 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +nearley@^2.7.10: + version "2.19.0" + resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.19.0.tgz#37717781d0fd0f2bfc95e233ebd75678ca4bda46" + integrity sha512-2v52FTw7RPqieZr3Gth1luAXZR7Je6q3KaDHY5bjl/paDUdMu35fZ8ICNgiYJRr3tf3NMvIQQR1r27AvEr9CRA== + dependencies: + commander "^2.19.0" + moo "^0.4.3" + railroad-diagrams "^1.0.0" + randexp "0.4.6" + semver "^5.4.1" + needle@^2.2.1: version "2.4.0" resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" @@ -5787,6 +6036,13 @@ npmlog@^4.0.2: gauge "~2.7.3" set-blocking "~2.0.0" +nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + null-check@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" @@ -5831,6 +6087,11 @@ object-inspect@^1.1.0, object-inspect@^1.7.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== +object-is@^1.0.1, object-is@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.2.tgz#6b80eb84fe451498f65007982f035a5b445edec4" + integrity sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ== + object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.0.9, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -5863,6 +6124,16 @@ object.entries@^1.1.0: function-bind "^1.1.1" has "^1.0.3" +object.entries@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.1.tgz#ee1cf04153de02bb093fec33683900f57ce5399b" + integrity sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + object.fromentries@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.1.tgz#050f077855c7af8ae6649f45c80b16ee2d31e704" @@ -5873,6 +6144,16 @@ object.fromentries@^2.0.1: function-bind "^1.1.1" has "^1.0.3" +object.fromentries@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9" + integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -5898,6 +6179,16 @@ object.values@^1.1.0: function-bind "^1.1.1" has "^1.0.3" +object.values@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -6108,6 +6399,13 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= +parse5@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" + integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA== + dependencies: + "@types/node" "*" + parseqs@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" @@ -6426,6 +6724,15 @@ promise@^7.0.3, promise@^7.1.1: dependencies: asap "~2.0.3" +prop-types-exact@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/prop-types-exact/-/prop-types-exact-1.2.0.tgz#825d6be46094663848237e3925a98c6e944e9869" + integrity sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA== + dependencies: + has "^1.0.3" + object.assign "^4.1.0" + reflect.ownkeys "^0.2.0" + prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" @@ -6554,13 +6861,26 @@ raf-schd@^2.1.0: resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-2.1.2.tgz#ec622b5167f2912089f054dc03ebd5bcf33c8f62" integrity sha512-Orl0IEvMtUCgPddgSxtxreK77UiQz4nPYJy9RggVzu4mKsZkQWiAaG1y9HlYWdvm9xtN348xRaT37qkvL/+A+g== -raf@^3.1.0: +raf@^3.1.0, raf@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== dependencies: performance-now "^2.1.0" +railroad-diagrams@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" + integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234= + +randexp@0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" + integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ== + dependencies: + discontinuous-range "1.0.0" + ret "~0.1.10" + randomatic@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" @@ -6668,7 +6988,7 @@ react-focus-lock@^2.2.1: dependencies: gemini-scrollbar matrix-org/gemini-scrollbar#91e1e566 -react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6: +react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: version "16.12.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== @@ -6700,7 +7020,7 @@ react-redux@^5.0.6: react-is "^16.6.0" react-lifecycles-compat "^3.0.0" -react-test-renderer@^16.9.0: +react-test-renderer@^16.0.0-0, react-test-renderer@^16.9.0: version "16.12.0" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.12.0.tgz#11417ffda579306d4e841a794d32140f3da1b43f" integrity sha512-Vj/teSqt2oayaWxkbhQ6gKis+t5JrknXfPVo+aIJ8QwYAqMPH77uptOdrlphyxl8eQI/rtkOYg86i/UWkpFu0w== @@ -6817,6 +7137,11 @@ redux@^3.7.2: loose-envify "^1.1.0" symbol-observable "^1.0.3" +reflect.ownkeys@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" + integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA= + regenerate@^1.2.1: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" @@ -7133,6 +7458,14 @@ rollup-pluginutils@^2.8.1: dependencies: estree-walker "^0.6.1" +rst-selector-parser@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91" + integrity sha1-gbIw6i/MYGbInjRy3nlChdmwPZE= + dependencies: + lodash.flattendeep "^4.4.0" + nearley "^2.7.10" + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -7219,7 +7552,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -7668,6 +8001,15 @@ string.prototype.repeat@^0.2.0: resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz#aba36de08dcee6a5a337d49b2ea1da1b28fc0ecf" integrity sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8= +string.prototype.trim@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz#141233dff32c82bfad80684d7e5f0869ee0fb782" + integrity sha512-MjGFEeqixw47dAMFMtgUro/I0+wNqZB5GKXGt1fFr24u3TzDXCPu7J9Buppzoe3r/LqkSDLDDJzE15RGWDGAVw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + string.prototype.trimleft@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" @@ -7676,6 +8018,14 @@ string.prototype.trimleft@^2.1.0: define-properties "^1.1.3" function-bind "^1.1.1" +string.prototype.trimleft@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" + integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + string.prototype.trimright@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" @@ -7684,6 +8034,14 @@ string.prototype.trimright@^2.1.0: define-properties "^1.1.3" function-bind "^1.1.1" +string.prototype.trimright@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" + integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" From 93c44390458f00bcdff090df2c1d4950870cd705 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 6 Jan 2020 13:30:56 +0000 Subject: [PATCH 06/93] js-sdk rc.1 --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ad446e26cc..61e12eceda 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "linkifyjs": "^2.1.6", "lodash": "^4.17.14", "lolex": "4.2", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", + "matrix-js-sdk": "2.4.7", "optimist": "^0.6.1", "pako": "^1.0.5", "png-chunks-extract": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index a491ba3941..1646ac5a59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5271,9 +5271,10 @@ mathml-tag-names@^2.0.1: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.1.tgz#6dff66c99d55ecf739ca53c492e626f1d12a33cc" integrity sha512-pWB896KPGSGkp1XtyzRBftpTzwSOL0Gfk0wLvxt4f2mgzjY19o0LxJ3U25vNWTzsh7da+KTbuXQoQ3lOJZ8WHw== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "2.4.6" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/01f0dd4498fb689cb66091aff7aa0ae49f9b8ebf" +matrix-js-sdk@2.4.7: + version "2.4.7" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-2.4.7.tgz#998949120cb6cfb6362af6ff7b6bce326f7dca6f" + integrity sha512-3BVlZrHJYt7j5N83BLEeqroe4Gi2J/ycZKvKIe6s6SEygP8TpUP+trVSd+bSLm7c2JpPpMCoEsJ22aaPcbWVDQ== dependencies: another-json "^0.2.0" browser-request "^0.3.3" From 6b8f6239c5f29ef3d969c8f7700f097d35ff139b Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 6 Jan 2020 13:58:43 +0000 Subject: [PATCH 07/93] js-sdk 3.0.0-rc.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 61e12eceda..1b97d84abb 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "linkifyjs": "^2.1.6", "lodash": "^4.17.14", "lolex": "4.2", - "matrix-js-sdk": "2.4.7", + "matrix-js-sdk": "3.0.0-rc.1", "optimist": "^0.6.1", "pako": "^1.0.5", "png-chunks-extract": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 1646ac5a59..982760c49a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5271,10 +5271,10 @@ mathml-tag-names@^2.0.1: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.1.tgz#6dff66c99d55ecf739ca53c492e626f1d12a33cc" integrity sha512-pWB896KPGSGkp1XtyzRBftpTzwSOL0Gfk0wLvxt4f2mgzjY19o0LxJ3U25vNWTzsh7da+KTbuXQoQ3lOJZ8WHw== -matrix-js-sdk@2.4.7: - version "2.4.7" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-2.4.7.tgz#998949120cb6cfb6362af6ff7b6bce326f7dca6f" - integrity sha512-3BVlZrHJYt7j5N83BLEeqroe4Gi2J/ycZKvKIe6s6SEygP8TpUP+trVSd+bSLm7c2JpPpMCoEsJ22aaPcbWVDQ== +matrix-js-sdk@3.0.0-rc.1: + version "3.0.0-rc.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-3.0.0-rc.1.tgz#6ecdedab752933f6a0ccf6aa7d2786bd32f6d7f7" + integrity sha512-1eaECVqG64tj1pE0UBFTIGc1whryXLNaRpkrXrZ5+ZMDtuK2ZDlTOLYoK3t4z/hjn+4C6a294ytoEVe0UnIA8w== dependencies: another-json "^0.2.0" browser-request "^0.3.3" From 623799ebdcededefc5c34c3dd5a93fc08fc79f1e Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 6 Jan 2020 14:01:54 +0000 Subject: [PATCH 08/93] Prepare changelog for v1.7.6-rc.1 --- CHANGELOG.md | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5390cad319..3ad057dc7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,177 @@ +Changes in [1.7.6-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.7.6-rc.1) (2020-01-06) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.7.5...v1.7.6-rc.1) + + * Deduplicate recent emoji + [\#3806](https://github.com/matrix-org/matrix-react-sdk/pull/3806) + * Fix ability to remove avatars + [\#3803](https://github.com/matrix-org/matrix-react-sdk/pull/3803) + * Update from Weblate + [\#3810](https://github.com/matrix-org/matrix-react-sdk/pull/3810) + * User Info fetch latest RoomMember instead of showing historical data + [\#3788](https://github.com/matrix-org/matrix-react-sdk/pull/3788) + * Remove all usages of slate in favour of CIDER + [\#3808](https://github.com/matrix-org/matrix-react-sdk/pull/3808) + * Use display name when pinned messages are changed + [\#3809](https://github.com/matrix-org/matrix-react-sdk/pull/3809) + * Fix inverted diff line highlighting in dark theme + [\#3790](https://github.com/matrix-org/matrix-react-sdk/pull/3790) + * Bridge info settings tab + [\#3693](https://github.com/matrix-org/matrix-react-sdk/pull/3693) + * Send the labs flags the client is running with in rageshake + [\#3805](https://github.com/matrix-org/matrix-react-sdk/pull/3805) + * Initial implementation of FTUE user lists design + [\#3792](https://github.com/matrix-org/matrix-react-sdk/pull/3792) + * Update key backup creation and recovery paths for SSSS + [\#3800](https://github.com/matrix-org/matrix-react-sdk/pull/3800) + * Don't fail if logs exists and is an empty dir + [\#3798](https://github.com/matrix-org/matrix-react-sdk/pull/3798) + * Comment remaining non-cross-signing-compliant components + [\#3799](https://github.com/matrix-org/matrix-react-sdk/pull/3799) + * Remove 'unverify' from UserInfoPanel + [\#3797](https://github.com/matrix-org/matrix-react-sdk/pull/3797) + * Use deviceTrust when displaying key backup trust status + [\#3795](https://github.com/matrix-org/matrix-react-sdk/pull/3795) + * Don't crash if a keyshare request is removed + [\#3793](https://github.com/matrix-org/matrix-react-sdk/pull/3793) + * Convert /verify to checkDeviceTrust + [\#3794](https://github.com/matrix-org/matrix-react-sdk/pull/3794) + * Remove E2eIcon onClick + [\#3791](https://github.com/matrix-org/matrix-react-sdk/pull/3791) + * support channel names with slash in name/alias + [\#3778](https://github.com/matrix-org/matrix-react-sdk/pull/3778) + * Fix NPE when filtering the room list + [\#3787](https://github.com/matrix-org/matrix-react-sdk/pull/3787) + * Turn RoomAliasField into properly controlled and use in RoomSettings + [\#3782](https://github.com/matrix-org/matrix-react-sdk/pull/3782) + * fuzzy-sort MemberList + [\#3783](https://github.com/matrix-org/matrix-react-sdk/pull/3783) + * Serialize file uploads into room to match confirmation dialog order + [\#3786](https://github.com/matrix-org/matrix-react-sdk/pull/3786) + * Do not show Top Unread Messages Bar and Jump to bottom button if searching + [\#3785](https://github.com/matrix-org/matrix-react-sdk/pull/3785) + * Fix sticker picker chevron offset calculation + [\#3784](https://github.com/matrix-org/matrix-react-sdk/pull/3784) + * Fix not being able to promote others to the same power level as your own + [\#3781](https://github.com/matrix-org/matrix-react-sdk/pull/3781) + * Room Tile DMs online/active green dot + [\#3751](https://github.com/matrix-org/matrix-react-sdk/pull/3751) + * Fix spelling and grammar in README + [\#3780](https://github.com/matrix-org/matrix-react-sdk/pull/3780) + * Reintroduce working resizer code for right panel + [\#3776](https://github.com/matrix-org/matrix-react-sdk/pull/3776) + * Fix wrong scope binding on openHelp for TopLeftMenu + [\#3775](https://github.com/matrix-org/matrix-react-sdk/pull/3775) + * UserInfo hide kick/mute buttons if they make no sense + [\#3774](https://github.com/matrix-org/matrix-react-sdk/pull/3774) + * Fix duplicate Incoming Call prompt on Community Invite sublist + [\#3773](https://github.com/matrix-org/matrix-react-sdk/pull/3773) + * Apply new design to highlighted tags and add toggle mechanic + [\#3755](https://github.com/matrix-org/matrix-react-sdk/pull/3755) + * stop using ReactDOM.findDOMNode in componentWillUnmount, use refs + [\#3771](https://github.com/matrix-org/matrix-react-sdk/pull/3771) + * Add alt="" to presentational images + [\#3772](https://github.com/matrix-org/matrix-react-sdk/pull/3772) + * Fix room list filtering weird case sensitivity + [\#3759](https://github.com/matrix-org/matrix-react-sdk/pull/3759) + * Don't show the 'verify' button if the user is verified + [\#3758](https://github.com/matrix-org/matrix-react-sdk/pull/3758) + * Switch to using checkDeviceTrust + [\#3757](https://github.com/matrix-org/matrix-react-sdk/pull/3757) + * Migrate away from React Legacy contexts API + [\#3743](https://github.com/matrix-org/matrix-react-sdk/pull/3743) + * Migrate key backups to SSSS + [\#3749](https://github.com/matrix-org/matrix-react-sdk/pull/3749) + * Get rid of stripped-emoji.json in favour of an in-memory single source of + truth + [\#3745](https://github.com/matrix-org/matrix-react-sdk/pull/3745) + * Combine cross signing and verification over DM feature flags + [\#3753](https://github.com/matrix-org/matrix-react-sdk/pull/3753) + * apply unhomoglyph when filtering room list to fuzzify it + [\#3754](https://github.com/matrix-org/matrix-react-sdk/pull/3754) + * Make EmojiPicker an unmanaged Context Menu as it is too complex to be + managed + [\#3746](https://github.com/matrix-org/matrix-react-sdk/pull/3746) + * Internationalise M_TOO_LARGE error from Synapse + [\#3750](https://github.com/matrix-org/matrix-react-sdk/pull/3750) + * Replace UserInfo avatar with for fallback logic + [\#3748](https://github.com/matrix-org/matrix-react-sdk/pull/3748) + * Dropdown stop keyboard propagation if key handled + [\#3741](https://github.com/matrix-org/matrix-react-sdk/pull/3741) + * Fix right panel for multiple member info viewings + [\#3742](https://github.com/matrix-org/matrix-react-sdk/pull/3742) + * Fix Field validation tooltip sticking if blurred before async validation + resolved + [\#3740](https://github.com/matrix-org/matrix-react-sdk/pull/3740) + * Fix UserInfo exploding without a room being passed to it + [\#3738](https://github.com/matrix-org/matrix-react-sdk/pull/3738) + * Fix room directory maintaining and error state + [\#3737](https://github.com/matrix-org/matrix-react-sdk/pull/3737) + * Stop trapping tab in AddressPickerDialog + [\#3735](https://github.com/matrix-org/matrix-react-sdk/pull/3735) + * Stop using KeyboardEvent.keyCode as it is deprecated + [\#3736](https://github.com/matrix-org/matrix-react-sdk/pull/3736) + * Implement new design for uploading/removing avatars + [\#3733](https://github.com/matrix-org/matrix-react-sdk/pull/3733) + * Fix aspect ratio on room/profile avatar preview + [\#3731](https://github.com/matrix-org/matrix-react-sdk/pull/3731) + * Switch to react-focus-lock for it to comprehend Portals + [\#3732](https://github.com/matrix-org/matrix-react-sdk/pull/3732) + * Make combobox dropdown keyboard and screen reader accessible + [\#3729](https://github.com/matrix-org/matrix-react-sdk/pull/3729) + * Verify users when cross-signing enabled + [\#3728](https://github.com/matrix-org/matrix-react-sdk/pull/3728) + * Update from Weblate + [\#3730](https://github.com/matrix-org/matrix-react-sdk/pull/3730) + * Improve a11y of the unignore button in Settings + [\#3727](https://github.com/matrix-org/matrix-react-sdk/pull/3727) + * Fix ToggleSwitch A11Y (trapping tab and switch v. checkbox) + [\#3726](https://github.com/matrix-org/matrix-react-sdk/pull/3726) + * Make URL previews dismissable via keyboard and accessible to screen readers + [\#3725](https://github.com/matrix-org/matrix-react-sdk/pull/3725) + * Create new key backups using secret storage + [\#3720](https://github.com/matrix-org/matrix-react-sdk/pull/3720) + * Replace sign-ins with sessions + [\#3721](https://github.com/matrix-org/matrix-react-sdk/pull/3721) + * Refactor RightPanel to match expected behaviour + [\#3703](https://github.com/matrix-org/matrix-react-sdk/pull/3703) + * Render policy room event updates in the timeline + [\#3716](https://github.com/matrix-org/matrix-react-sdk/pull/3716) + * Wrap the await call for unknown device lookups + [\#3718](https://github.com/matrix-org/matrix-react-sdk/pull/3718) + * Add testing flow to bootstrap secret storage + [\#3640](https://github.com/matrix-org/matrix-react-sdk/pull/3640) + * Fix remaining context menu regressions + [\#3715](https://github.com/matrix-org/matrix-react-sdk/pull/3715) + * Migrate away from React Legacy string refs + [\#3712](https://github.com/matrix-org/matrix-react-sdk/pull/3712) + * Update copy for DM invites + [\#3706](https://github.com/matrix-org/matrix-react-sdk/pull/3706) + * Fix message action bar reaction picker regression + [\#3714](https://github.com/matrix-org/matrix-react-sdk/pull/3714) + * Add what-input to allow different scoping to focus-visible for MAB a11y + [\#3709](https://github.com/matrix-org/matrix-react-sdk/pull/3709) + * Mark the This/All Rooms scope buttons as radios for a11y + [\#3708](https://github.com/matrix-org/matrix-react-sdk/pull/3708) + * Switch ReactionsRowButton to an AccessibleButton for space/enter handling + [\#3707](https://github.com/matrix-org/matrix-react-sdk/pull/3707) + * Change the (edited) link to an AccessibleButton for a11y + [\#3710](https://github.com/matrix-org/matrix-react-sdk/pull/3710) + * Update from Weblate + [\#3713](https://github.com/matrix-org/matrix-react-sdk/pull/3713) + * Fix ?via= args in SpecPermalinkConstructor.js + [\#3694](https://github.com/matrix-org/matrix-react-sdk/pull/3694) + * Don't mark a room as unread when server ACLs are set + [\#3705](https://github.com/matrix-org/matrix-react-sdk/pull/3705) + * Make reaction buttons more accessible + [\#3704](https://github.com/matrix-org/matrix-react-sdk/pull/3704) + * yarn upgrade + [\#3701](https://github.com/matrix-org/matrix-react-sdk/pull/3701) + * Make CI scripts executable + [\#3698](https://github.com/matrix-org/matrix-react-sdk/pull/3698) + * ARIA compliant context menus + [\#3611](https://github.com/matrix-org/matrix-react-sdk/pull/3611) + Changes in [1.7.5](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.7.5) (2019-12-09) =================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.7.5-rc.1...v1.7.5) From 0df16631c24824c4cca5902a83e8c574d12fed9f Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 6 Jan 2020 14:01:54 +0000 Subject: [PATCH 09/93] v1.7.6-rc.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b97d84abb..f155738fbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "1.7.5", + "version": "1.7.6-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From f1de6d060acd66b5ba69f7f494fd176d161b40f5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 6 Jan 2020 14:38:21 +0000 Subject: [PATCH 10/93] Add a regression test for editing events and url previews Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../keybackup/CreateKeyBackupDialog.js | 2 +- .../views/settings/KeyBackupPanel.js | 2 +- .../views/messages/TextualBody-test.js | 62 +++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js index 19720e077a..1095fb4aee 100644 --- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js +++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js @@ -24,7 +24,7 @@ import MatrixClientPeg from '../../../../MatrixClientPeg'; import { scorePassword } from '../../../../utils/PasswordScorer'; import { _t } from '../../../../languageHandler'; import { accessSecretStorage } from '../../../../CrossSigningManager'; -import SettingsStore from '../../../../../lib/settings/SettingsStore'; +import SettingsStore from '../../../../settings/SettingsStore'; const PHASE_PASSPHRASE = 0; const PHASE_PASSPHRASE_CONFIRM = 1; diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js index bfa96f277f..3781f97dbe 100644 --- a/src/components/views/settings/KeyBackupPanel.js +++ b/src/components/views/settings/KeyBackupPanel.js @@ -21,7 +21,7 @@ import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; -import SettingsStore from '../../../../lib/settings/SettingsStore'; +import SettingsStore from '../../../settings/SettingsStore'; export default class KeyBackupPanel extends React.PureComponent { constructor(props) { diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js index d93bfd307b..9e721d1d09 100644 --- a/test/components/views/messages/TextualBody-test.js +++ b/test/components/views/messages/TextualBody-test.js @@ -6,6 +6,8 @@ import { configure, mount } from "enzyme"; import sdk from "../../../skinned-sdk"; import {mkEvent, mkStubRoom} from "../../../test-utils"; import MatrixClientPeg from "../../../../src/MatrixClientPeg"; +import * as languageHandler from "../../../../src/languageHandler"; +import {sleep} from "../../../../src/utils/promise"; const TextualBody = sdk.getComponent("views.messages.TextualBody"); @@ -190,6 +192,66 @@ describe("", () => { ''); }); }); + + describe("renders url previews correctly", () => { + languageHandler.setMissingEntryGenerator(key => key.split('|', 2)[1]); + + MatrixClientPeg.matrixClient = { + getRoom: () => mkStubRoom("room_id"), + getAccountData: () => undefined, + getUrlPreview: (url) => new Promise(() => {}), + }; + + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + body: "Visit https://matrix.org/", + msgtype: "m.text", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe(ev.getContent().body); + + let widgets = wrapper.find("LinkPreviewWidget"); + // at this point we should have exactly one widget + expect(widgets.length).toBe(1); + expect(widgets.at(0).prop("link")).toBe("https://matrix.org/"); + + // simulate an event edit and check the transition from the old URL preview to the new one + const ev2 = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + "m.new_content": { + body: "Visit https://vector.im/ and https://riot.im/", + msgtype: "m.text", + }, + }, + event: true, + }); + ev.makeReplaced(ev2); + + wrapper.setProps({ + mxEvent: ev, + replacingEventId: ev.getId(), + }, () => { + expect(wrapper.text()).toBe(ev2.getContent()["m.new_content"].body + "(edited)"); + + // XXX: this is to give TextualBody enough time for state to settle + wrapper.setState({}, () => { + widgets = wrapper.find("LinkPreviewWidget"); + // at this point we should have exactly two widgets (not the matrix.org one anymore) + expect(widgets.length).toBe(2); + expect(widgets.at(0).prop("link")).toBe("https://vector.im/"); + expect(widgets.at(1).prop("link")).toBe("https://riot.im/"); + }); + }); + }); }); From bdef54622b81c2855d0605f2944b88bb1519e337 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 6 Jan 2020 14:52:08 +0000 Subject: [PATCH 11/93] delint and add copyright Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/messages/TextualBody-test.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js index 9e721d1d09..7aeff94404 100644 --- a/test/components/views/messages/TextualBody-test.js +++ b/test/components/views/messages/TextualBody-test.js @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Matrix.org Foundation C.I.C. + +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 React from "react"; import expect from 'expect'; import Adapter from "enzyme-adapter-react-16"; @@ -7,7 +23,6 @@ import sdk from "../../../skinned-sdk"; import {mkEvent, mkStubRoom} from "../../../test-utils"; import MatrixClientPeg from "../../../../src/MatrixClientPeg"; import * as languageHandler from "../../../../src/languageHandler"; -import {sleep} from "../../../../src/utils/promise"; const TextualBody = sdk.getComponent("views.messages.TextualBody"); From dac31dbe00176d28ec93c0ef579e05f00e808cc1 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Mon, 6 Jan 2020 21:08:18 +0000 Subject: [PATCH 12/93] Translated using Weblate (Hungarian) Currently translated at 100.0% (2000 of 2000 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 92113c3238..10da7537a9 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -2034,5 +2034,6 @@ "Connected to on ": "Ide csatlakozva: itt: ", "Connected via %(protocolName)s": "Ezzel a protokollal csatlakozva: %(protocolName)s", "Bridge Info": "Híd információ", - "Below is a list of bridges connected to this room.": "Alább látható a lista a szobához kapcsolódó hidakról." + "Below is a list of bridges connected to this room.": "Alább látható a lista a szobához kapcsolódó hidakról.", + "Suggestions": "Javaslatok" } From a62c260f794f2f89815045458b05a656bc5962dc Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 7 Jan 2020 12:58:24 +0000 Subject: [PATCH 13/93] Fix userinfo for users not in the room Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/right_panel/UserInfo.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js index b55991eda8..9c90953114 100644 --- a/src/components/views/right_panel/UserInfo.js +++ b/src/components/views/right_panel/UserInfo.js @@ -1000,8 +1000,8 @@ const UserInfo = ({user, groupId, roomId, onClose}) => { // Load room if we are given a room id and memoize it const room = useMemo(() => roomId ? cli.getRoom(roomId) : null, [cli, roomId]); - // fetch latest room member if we have a room, so we don't show historical information - const member = useMemo(() => room ? room.getMember(user.userId) : user, [room, user]); + // fetch latest room member if we have a room, so we don't show historical information, falling back to user + const member = useMemo(() => room ? (room.getMember(user.userId) || user) : user, [room, user]); // only display the devices list if our client supports E2E const _enableDevices = cli.isCryptoEnabled(); From 69dde64a7a6670f9954bfd94d3b64c3afa4af99f Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Tue, 7 Jan 2020 02:52:43 +0000 Subject: [PATCH 14/93] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1998 of 1998 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index db75121f07..d58f37b37a 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -2033,5 +2033,6 @@ "Connected to on ": "連線到 ", "Connected via %(protocolName)s": "透過 %(protocolName)s 連線", "Bridge Info": "橋接資訊", - "Below is a list of bridges connected to this room.": "以下是連線到此聊天室的橋接列表。" + "Below is a list of bridges connected to this room.": "以下是連線到此聊天室的橋接列表。", + "Suggestions": "建議" } From 0381334f45de10054797c170fd89ef221a4db55a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Tue, 7 Jan 2020 11:02:59 +0000 Subject: [PATCH 15/93] Translated using Weblate (French) Currently translated at 100.0% (1998 of 1998 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index c2ee7c575b..7261f62f3a 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -2033,5 +2033,6 @@ "Connected to on ": "Connecté à sur ", "Connected via %(protocolName)s": "Connecté via %(protocolName)s", "Bridge Info": "Informations de la passerelle", - "Below is a list of bridges connected to this room.": "Vous trouverez ci-dessous la liste des passerelles connectées à ce salon." + "Below is a list of bridges connected to this room.": "Vous trouverez ci-dessous la liste des passerelles connectées à ce salon.", + "Suggestions": "Suggestions" } From 8606bb9fba98a39444158e3408d121197465c9ba Mon Sep 17 00:00:00 2001 From: random Date: Tue, 7 Jan 2020 13:50:05 +0000 Subject: [PATCH 16/93] Translated using Weblate (Italian) Currently translated at 99.9% (1997 of 1998 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/it/ --- src/i18n/strings/it.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index 390729950b..22fc083d08 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -2017,5 +2017,20 @@ "The message you are trying to send is too large.": "Il messaggio che stai tentando di inviare è troppo grande.", "Secret Storage will be set up using your existing key backup details.Your secret storage passphrase and recovery key will be the same as they were for your key backup": "L'archivio segreto verrà impostato usando i dettagli del tuo backup chiavi. La password dell'archivio segreto e la chiave di ripristino saranno le stesse del tuo backup chiavi", "Migrate from Key Backup": "Migra dal backup chiavi", - "Help": "Aiuto" + "Help": "Aiuto", + "New DM invite dialog (under development)": "Nuovo invito via messaggio diretto (in sviluppo)", + "Show info about bridges in room settings": "Mostra info sui bridge nelle impostazioni stanza", + "This bridge was provisioned by ": "Questo bridge è stato fornito da ", + "This bridge is managed by .": "Questo bridge è gestito da .", + "Bridged into , on ": "Bridge in , su ", + "Connected to on ": "Connesso a su ", + "Connected via %(protocolName)s": "Connesso via %(protocolName)s", + "Bridge Info": "Info bridge", + "Below is a list of bridges connected to this room.": "Sotto vedi una lista di brdige connessi a questa stanza.", + "Recent Conversations": "Conversazioni recenti", + "Suggestions": "Suggerimenti", + "Show more": "Mostra altro", + "Direct Messages": "Messaggi diretti", + "If you can't find someone, ask them for their username, or share your username (%(userId)s) or profile link.": "Se non riesci a trovare qualcuno, chiedigli il nome utente o condividi il tuo (%(userId)s) o il link al profilo.", + "Go": "Vai" } From 40b23d6aa4cb6ad465c4ec1c9c2b55bd2ebe3cc9 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 7 Jan 2020 18:48:55 +0000 Subject: [PATCH 17/93] Strip all variation selectors on emoji ...when inserting into or looking up in the unicode to emoji map. This broke with emojibase 4.2.0 which changed the type of a whole load of emojis to 'text' when previously they were 'emoji'. This caused them to get the 'text' variant of the unicode string which has the text variation selector (15) appended instead of the emoji variation selector (16). We were only stripping the emoji selector, so upgrading to 4.2.0 caused riot to fail to find the heart in the unicode map, which therefore prevented the app from starting. --- src/emoji.js | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/emoji.js b/src/emoji.js index 7b7a9c1bfe..8b3c4c9fe4 100644 --- a/src/emoji.js +++ b/src/emoji.js @@ -16,14 +16,12 @@ limitations under the License. import EMOJIBASE from 'emojibase-data/en/compact.json'; -export const VARIATION_SELECTOR = String.fromCharCode(0xFE0F); - // The unicode is stored without the variant selector const UNICODE_TO_EMOJI = new Map(); // not exported as gets for it are handled by getEmojiFromUnicode export const EMOTICON_TO_EMOJI = new Map(); export const SHORTCODE_TO_EMOJI = new Map(); -export const getEmojiFromUnicode = unicode => UNICODE_TO_EMOJI.get(unicode.replace(VARIATION_SELECTOR, "")); +export const getEmojiFromUnicode = unicode => UNICODE_TO_EMOJI.get(stripVariation(unicode)); const EMOJIBASE_GROUP_ID_TO_CATEGORY = [ "people", // smileys @@ -51,13 +49,6 @@ export const DATA_BY_CATEGORY = { // Store various mappings from unicode/emoticon/shortcode to the Emoji objects EMOJIBASE.forEach(emoji => { - if (emoji.unicode.includes(VARIATION_SELECTOR)) { - // Clone data into variation-less version - emoji = Object.assign({}, emoji, { - unicode: emoji.unicode.replace(VARIATION_SELECTOR, ""), - }); - } - const categoryId = EMOJIBASE_GROUP_ID_TO_CATEGORY[emoji.group]; if (DATA_BY_CATEGORY.hasOwnProperty(categoryId)) { DATA_BY_CATEGORY[categoryId].push(emoji); @@ -66,7 +57,13 @@ EMOJIBASE.forEach(emoji => { emoji.filterString = `${emoji.annotation}\n${emoji.shortcodes.join('\n')}}\n${emoji.emoticon || ''}`.toLowerCase(); // Add mapping from unicode to Emoji object - UNICODE_TO_EMOJI.set(emoji.unicode, emoji); + // The 'unicode' field that we use in emojibase has either + // VS15 or VS16 appended to any characters that can take + // variation selectors. Which one it appends depends + // on whether emojibase considers their type to be 'text' or + // 'emoji'. We therefore strip any variation chars from strings + // both when building the map and when looking up. + UNICODE_TO_EMOJI.set(stripVariation(emoji.unicode), emoji); if (emoji.emoticon) { // Add mapping from emoticon to Emoji object @@ -80,3 +77,23 @@ EMOJIBASE.forEach(emoji => { }); } }); + +/** + * Strips variation selectors from a string + * NB. Skin tone modifers are not variation selectors: + * this function does not touch them. (Should it?) + * + * @param {string} str string to strip + * @returns {string} stripped string + */ +function stripVariation(str) { + let ret = ''; + for (let i = 0; i < str.length; ++i) { + const charCode = str.charCodeAt(i); + // append to output only if it's outside the variation selector range + if (charCode < 0xFE00 && charCode > 0xFE0F) { + ret += str.charAt(i); + } + } + return ret; +} From ffd40c2c4081ce7bd2a6fb09a39e230f6d07b991 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 6 Jan 2020 20:51:23 -0700 Subject: [PATCH 18/93] Initial editor for user list selection For https://github.com/vector-im/riot-web/issues/11199 --- res/css/views/dialogs/_DMInviteDialog.scss | 77 ++++++- res/img/icon-email-pill-avatar.svg | 37 +++ res/img/icon-pill-remove.svg | 36 +++ .../views/dialogs/DMInviteDialog.js | 214 ++++++++++++++---- 4 files changed, 323 insertions(+), 41 deletions(-) create mode 100644 res/img/icon-email-pill-avatar.svg create mode 100644 res/img/icon-pill-remove.svg diff --git a/res/css/views/dialogs/_DMInviteDialog.scss b/res/css/views/dialogs/_DMInviteDialog.scss index 364c796f16..e581f9dc7a 100644 --- a/res/css/views/dialogs/_DMInviteDialog.scss +++ b/res/css/views/dialogs/_DMInviteDialog.scss @@ -21,15 +21,51 @@ limitations under the License. .mx_DMInviteDialog_editor { flex: 1; width: 100%; // Needed to make the Field inside grow - } + background-color: $user-tile-hover-bg-color; + border-radius: 4px; + min-height: 25px; + padding-left: 8px; + overflow-x: hidden; + overflow-y: auto; - .mx_Field { - margin: 0; + .mx_DMInviteDialog_userTile { + display: inline-block; + float: left; + position: relative; + top: 7px; + } + + // Using a textarea for this element, to circumvent autofill + // Mostly copied from AddressPickerDialog + textarea, + textarea:focus { + height: 34px; + line-height: 34px; + font-size: 14px; + padding-left: 12px; + margin: 0 !important; + border: 0 !important; + outline: 0 !important; + resize: none; + overflow: hidden; + box-sizing: border-box; + word-wrap: nowrap; + + // Roughly fill about 2/5ths of the available space. This is to try and 'fill' the + // remaining space after a bunch of pills, but is a bit hacky. Ideally we'd have + // support for "fill remaining width", but traditional tricks don't work with what + // we're pushing into this "field". Flexbox just makes things worse. The theory is + // that users won't need more than about 2/5ths of the input to find the person + // they're looking for. + width: 40%; + } } .mx_DMInviteDialog_goButton { width: 48px; margin-left: 10px; + height: 25px; + line-height: 25px; } } @@ -83,3 +119,38 @@ limitations under the License. } } +// Many of these styles are stolen from mx_UserPill, but adjusted for the invite dialog. +.mx_DMInviteDialog_userTile { + margin-right: 8px; + + .mx_DMInviteDialog_userTile_pill { + background-color: $username-variant1-color; + border-radius: 12px; + display: inline-block; + height: 24px; + line-height: 24px; + padding-left: 8px; + padding-right: 8px; + color: #ffffff; // this is fine without a var because it's for both themes + + .mx_DMInviteDialog_userTile_avatar { + border-radius: 20px; + position: relative; + left: -5px; + top: 2px; + } + + img.mx_DMInviteDialog_userTile_avatar { + vertical-align: top; + } + + .mx_DMInviteDialog_userTile_name { + vertical-align: top; + } + } + + .mx_DMInviteDialog_userTile_remove { + display: inline-block; + margin-left: 4px; + } +} diff --git a/res/img/icon-email-pill-avatar.svg b/res/img/icon-email-pill-avatar.svg new file mode 100644 index 0000000000..c107ccc480 --- /dev/null +++ b/res/img/icon-email-pill-avatar.svg @@ -0,0 +1,37 @@ + + + + at-sign + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/img/icon-pill-remove.svg b/res/img/icon-pill-remove.svg new file mode 100644 index 0000000000..5b31cca42f --- /dev/null +++ b/res/img/icon-pill-remove.svg @@ -0,0 +1,36 @@ + + + + x + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/views/dialogs/DMInviteDialog.js b/src/components/views/dialogs/DMInviteDialog.js index c5e9c92131..6eb6d0c78b 100644 --- a/src/components/views/dialogs/DMInviteDialog.js +++ b/src/components/views/dialogs/DMInviteDialog.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import {_t} from "../../../languageHandler"; import sdk from "../../../index"; @@ -31,18 +31,46 @@ import {getHttpUriForMxc} from "matrix-js-sdk/lib/content-repo"; const INITIAL_ROOMS_SHOWN = 3; // Number of rooms to show at first const INCREMENT_ROOMS_SHOWN = 5; // Number of rooms to add when 'show more' is clicked -class DirectoryMember { +// This is the interface that is expected by various components in this file. It is a bit +// awkward because it also matches the RoomMember class from the js-sdk with some extra support +// for 3PIDs/email addresses. +// +// Dev note: In order to allow us to compile the app correctly, this needs to be a class +// even though FlowJS supports interfaces. It just means that we "extend" rather than "implement" +// in the classes, at least until TypeScript saves us. +class Member { + /** + * The display name of this Member. For users this should be their profile's display + * name or user ID if none set. For 3PIDs this should be the 3PID address (email). + */ + get name(): string { throw new Error("Member class not implemented"); } + + /** + * The ID of this Member. For users this should be their user ID. For 3PIDs this should + * be the 3PID address (email). + */ + get userId(): string { throw new Error("Member class not implemented"); } + + /** + * Gets the MXC URL of this Member's avatar. For users this should be their profile's + * avatar MXC URL or null if none set. For 3PIDs this should always be null. + */ + getMxcAvatarUrl(): string { throw new Error("Member class not implemented"); } +} + +class DirectoryMember extends Member { _userId: string; _displayName: string; _avatarUrl: string; constructor(userDirResult: {user_id: string, display_name: string, avatar_url: string}) { + super(); this._userId = userDirResult.user_id; this._displayName = userDirResult.display_name; this._avatarUrl = userDirResult.avatar_url; } - // These next members are to implement the contract expected by DMRoomTile + // These next class members are for the Member interface get name(): string { return this._displayName || this._userId; } @@ -56,12 +84,91 @@ class DirectoryMember { } } +class ThreepidMember extends Member { + _id: string; + + constructor(id: string) { + super(); + this._id = id; + } + + // This is a getter that would be falsey on all other implementations. Until we have + // better type support in the react-sdk we can use this trick to determine the kind + // of 3PID we're dealing with, if any. + get isEmail(): boolean { + return this._id.includes('@'); + } + + // These next class members are for the Member interface + get name(): string { + return this._id; + } + + get userId(): string { + return this._id; + } + + getMxcAvatarUrl(): string { + return null; + } +} + +class DMUserTile extends React.PureComponent { + static propTypes = { + member: PropTypes.object.isRequired, // Should be a Member (see interface above) + onRemove: PropTypes.func.isRequired, // takes 1 argument, the member being removed + }; + + _onRemove = (e) => { + // Stop the browser from highlighting text + e.preventDefault(); + e.stopPropagation(); + + this.props.onRemove(this.props.member); + }; + + render() { + const BaseAvatar = sdk.getComponent("views.avatars.BaseAvatar"); + const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); + + const avatarSize = 20; + const avatar = this.props.member.isEmail + ? + : ; + + return ( + + + {avatar} + {this.props.member.name} + + + {_t('Remove')} + + + ); + } +} + class DMRoomTile extends React.PureComponent { static propTypes = { - // Has properties to match RoomMember: userId (str), name (str), getMxcAvatarUrl(): string - member: PropTypes.object.isRequired, + member: PropTypes.object.isRequired, // Should be a Member (see interface above) lastActiveTs: PropTypes.number, - onToggle: PropTypes.func.isRequired, + onToggle: PropTypes.func.isRequired, // takes 1 argument, the member being toggled highlightWord: PropTypes.string, }; @@ -70,7 +177,7 @@ class DMRoomTile extends React.PureComponent { e.preventDefault(); e.stopPropagation(); - this.props.onToggle(this.props.member.userId); + this.props.onToggle(this.props.member); }; _highlightName(str: string) { @@ -121,19 +228,22 @@ class DMRoomTile extends React.PureComponent { } const avatarSize = 36; - const avatarUrl = getHttpUriForMxc( - MatrixClientPeg.get().getHomeserverUrl(), this.props.member.getMxcAvatarUrl(), - avatarSize, avatarSize, "crop"); + const avatar = this.props.member.isEmail + ? + : ; return (
- + {avatar} {this._highlightName(this.props.member.name)} {this._highlightName(this.props.member.userId)} {timestamp} @@ -149,12 +259,13 @@ export default class DMInviteDialog extends React.PureComponent { }; _debounceTimer: number = null; + _editorRef: any = null; constructor() { super(); this.state = { - targets: [], // string[] of mxids/email addresses + targets: [], // array of Member objects (see interface above) filterText: "", recents: this._buildRecents(), numRecentsShown: INITIAL_ROOMS_SHOWN, @@ -162,6 +273,8 @@ export default class DMInviteDialog extends React.PureComponent { numSuggestionsShown: INITIAL_ROOMS_SHOWN, serverResultsMixin: [], // { user: DirectoryMember, userId: string }[], like recents and suggestions }; + + this._editorRef = createRef(); } _buildRecents(): {userId: string, user: RoomMember, lastActive: number} { @@ -245,7 +358,7 @@ export default class DMInviteDialog extends React.PureComponent { } _startDm = () => { - this.props.onFinished(this.state.targets); + this.props.onFinished(this.state.targets.map(t => t.userId)); }; _cancel = () => { @@ -292,14 +405,33 @@ export default class DMInviteDialog extends React.PureComponent { this.setState({numSuggestionsShown: this.state.numSuggestionsShown + INCREMENT_ROOMS_SHOWN}); }; - _toggleMember = (userId) => { + _toggleMember = (member: Member) => { const targets = this.state.targets.map(t => t); // cheap clone for mutation - const idx = targets.indexOf(userId); + const idx = targets.indexOf(member); if (idx >= 0) targets.splice(idx, 1); - else targets.push(userId); + else targets.push(member); this.setState({targets}); }; + _removeMember = (member: Member) => { + const targets = this.state.targets.map(t => t); // cheap clone for mutation + const idx = targets.indexOf(member); + if (idx >= 0) { + targets.splice(idx, 1); + this.setState({targets}); + } + }; + + _onClickInputArea = (e) => { + // Stop the browser from highlighting text + e.preventDefault(); + e.stopPropagation(); + + if (this._editorRef && this._editorRef.current) { + this._editorRef.current.focus(); + } + }; + _renderSection(kind: "recents"|"suggestions") { let sourceMembers = kind === 'recents' ? this.state.recents : this.state.suggestions; let showNum = kind === 'recents' ? this.state.numRecentsShown : this.state.numSuggestionsShown; @@ -371,24 +503,31 @@ export default class DMInviteDialog extends React.PureComponent { ); } + _renderEditor() { + const targets = this.state.targets.map(t => ( + + )); + const input = ( +