From 272ba5b004f33c444b2c63a419810c479b5cb5fc Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 13:15:40 +0100 Subject: [PATCH 01/16] Implement opt-in analytics with cookie bar --- src/components/structures/LoggedInView.js | 5 +- src/components/structures/MatrixChat.js | 32 +++++++++- src/components/views/globals/CookieBar.js | 73 +++++++++++++++++++++++ src/i18n/strings/en_EN.json | 5 +- src/settings/Settings.js | 9 ++- 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 src/components/views/globals/CookieBar.js diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index d9ac9de693..abb2eb92aa 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -266,6 +266,7 @@ const LoggedInView = React.createClass({ const GroupView = sdk.getComponent('structures.GroupView'); const MyGroups = sdk.getComponent('structures.MyGroups'); const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); + const CookieBar = sdk.getComponent('globals.CookieBar'); const NewVersionBar = sdk.getComponent('globals.NewVersionBar'); const UpdateCheckBar = sdk.getComponent('globals.UpdateCheckBar'); const PasswordNagBar = sdk.getComponent('globals.PasswordNagBar'); @@ -353,7 +354,9 @@ const LoggedInView = React.createClass({ let topBar; const isGuest = this.props.matrixClient.isGuest(); - if (this.props.hasNewVersion) { + if (this.props.showCookieBar) { + topBar = ; + } else if (this.props.hasNewVersion) { topBar = ; diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 3005bc86ad..051b9ed10b 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -165,6 +165,8 @@ export default React.createClass({ newVersionReleaseNotes: null, checkingForUpdate: null, + showCookieBar: false, + // Parameters used in the registration dance with the IS register_client_secret: null, register_session_id: null, @@ -227,8 +229,6 @@ export default React.createClass({ componentWillMount: function() { SdkConfig.put(this.props.config); - if (!SettingsStore.getValue("analyticsOptOut")) Analytics.enable(); - // Used by _viewRoom before getting state from sync this.firstSyncComplete = false; this.firstSyncPromise = Promise.defer(); @@ -361,6 +361,16 @@ export default React.createClass({ // loadSession as there's logic there to ask the user if they want // to try logging out. }); + + if (SettingsStore.getValue("showCookieBar")) { + this.setState({ + showCookieBar: true, + }); + } + + if (SettingsStore.getValue("analyticsOptIn")) { + Analytics.enable(); + } }, componentWillUnmount: function() { @@ -673,6 +683,23 @@ export default React.createClass({ hideToSRUsers: false, }); break; + case 'accept_cookies': + SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, true); + SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false); + + this.setState({ + showCookieBar: false, + }); + Analytics.enable(); + break; + case 'reject_cookies': + SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, false); + SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false); + + this.setState({ + showCookieBar: false, + }); + break; } }, @@ -1621,6 +1648,7 @@ export default React.createClass({ onRegistered={this.onRegistered} currentRoomId={this.state.currentRoomId} teamToken={this._teamToken} + showCookieBar={this.state.showCookieBar} {...this.props} {...this.state} /> diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js new file mode 100644 index 0000000000..f1fbbcc83a --- /dev/null +++ b/src/components/views/globals/CookieBar.js @@ -0,0 +1,73 @@ +/* +Copyright 2018 New Vector Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import dis from '../../../dispatcher'; +import { _t } from '../../../languageHandler'; +import sdk from '../../../index'; + +const PrivacyLink = (sub) => + + { sub } + ; + +export default React.createClass({ + onAccept: function() { + dis.dispatch({ + action: 'accept_cookies', + }); + }, + + onReject: function() { + dis.dispatch({ + action: 'reject_cookies', + }); + }, + + render: function() { + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + const toolbarClasses = "mx_MatrixToolbar"; + return ( +
+ Warning +
+ { _t( + "Help us improve Riot by sending usage data. " + + "This will use a cookie " + + "(see our cookie and " + + "privacy policies)", + {}, + { + // XXX: We need to link to the page that explains our cookies + 'CookieLink': PrivacyLink, + 'PrivacyLink': PrivacyLink, + }, + ) } +
+ + { _t("Send usage data") } + + + + +
+ ); + }, +}); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9b932ef2b6..0126661a07 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -210,7 +210,8 @@ "Mirror local video feed": "Mirror local video feed", "Disable Community Filter Panel": "Disable Community Filter Panel", "Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls", - "Opt out of analytics": "Opt out of analytics", + "Send analytics data": "Send analytics data", + "Show cookie bar": "Show cookie bar", "Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device", "Never send encrypted messages to unverified devices in this room from this device": "Never send encrypted messages to unverified devices in this room from this device", "Enable inline URL previews by default": "Enable inline URL previews by default", @@ -637,6 +638,8 @@ "Something went wrong when trying to get your communities.": "Something went wrong when trying to get your communities.", "Display your community flair in rooms configured to show it.": "Display your community flair in rooms configured to show it.", "You're not currently a member of any communities.": "You're not currently a member of any communities.", + "Help us improve Riot by sending usage data. This will use a cookie (see our cookie and privacy policies)": "Help us improve Riot by sending usage data. This will use a cookie (see our cookie and privacy policies)", + "Send usage data": "Send usage data", "You are not receiving desktop notifications": "You are not receiving desktop notifications", "Enable them now": "Enable them now", "What's New": "What's New", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 663318f990..8f50885c14 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -213,11 +213,16 @@ export const SETTINGS = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: "en", }, - "analyticsOptOut": { + "analyticsOptIn": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - displayName: _td('Opt out of analytics'), + displayName: _td('Send analytics data'), default: false, }, + "showCookieBar": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + displayName: _td('Show cookie bar'), + default: true, + }, "autocompleteDelay": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: 200, From 0c22343bb895f118df613896d63e4cfd61f08ef0 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 15:38:47 +0100 Subject: [PATCH 02/16] Remove cookie bar setting from UserSettings --- src/i18n/strings/en_EN.json | 1 - src/settings/Settings.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0126661a07..448f5e3a1c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -211,7 +211,6 @@ "Disable Community Filter Panel": "Disable Community Filter Panel", "Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls", "Send analytics data": "Send analytics data", - "Show cookie bar": "Show cookie bar", "Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device", "Never send encrypted messages to unverified devices in this room from this device": "Never send encrypted messages to unverified devices in this room from this device", "Enable inline URL previews by default": "Enable inline URL previews by default", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 8f50885c14..b1bc4161fd 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -220,7 +220,6 @@ export const SETTINGS = { }, "showCookieBar": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - displayName: _td('Show cookie bar'), default: true, }, "autocompleteDelay": { From c191464e972f1298e81ebd46e253381e1eb2d6bd Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 15:39:12 +0100 Subject: [PATCH 03/16] Fix UserSettings for new analyticsOptIn --- src/components/structures/UserSettings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 35a55284fd..c8ce79905d 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -86,9 +86,9 @@ const SIMPLE_SETTINGS = [ // These settings must be defined in SettingsStore const ANALYTICS_SETTINGS = [ { - id: 'analyticsOptOut', + id: 'analyticsOptIn', fn: function(checked) { - Analytics[checked ? 'disable' : 'enable'](); + checked ? Analytics.enable() : Analytics.disable(); }, }, ]; From e98b31958be34769f17c7309692b186ff82cbbe9 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 16 May 2018 10:41:18 +0100 Subject: [PATCH 04/16] Allow arbitrary hrefs for cookie/privacy links --- src/components/views/globals/CookieBar.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js index f1fbbcc83a..7625518252 100644 --- a/src/components/views/globals/CookieBar.js +++ b/src/components/views/globals/CookieBar.js @@ -19,11 +19,11 @@ import dis from '../../../dispatcher'; import { _t } from '../../../languageHandler'; import sdk from '../../../index'; -const PrivacyLink = (sub) => +const makeLink = (href) => (sub) => { sub } ; @@ -56,8 +56,8 @@ export default React.createClass({ {}, { // XXX: We need to link to the page that explains our cookies - 'CookieLink': PrivacyLink, - 'PrivacyLink': PrivacyLink, + 'CookieLink': makeLink("https://riot.im/privacy"), + 'PrivacyLink': makeLink("https://riot.im/privacy"), }, ) } From ac1cd384e75c1b5c67507e519dca1f6e68592d5e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 13:15:40 +0100 Subject: [PATCH 05/16] Implement opt-in analytics with cookie bar --- src/components/structures/LoggedInView.js | 5 +- src/components/structures/MatrixChat.js | 32 +++++++++- src/components/views/globals/CookieBar.js | 73 +++++++++++++++++++++++ src/i18n/strings/en_EN.json | 5 +- src/settings/Settings.js | 9 ++- 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 src/components/views/globals/CookieBar.js diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index d9ac9de693..abb2eb92aa 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -266,6 +266,7 @@ const LoggedInView = React.createClass({ const GroupView = sdk.getComponent('structures.GroupView'); const MyGroups = sdk.getComponent('structures.MyGroups'); const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); + const CookieBar = sdk.getComponent('globals.CookieBar'); const NewVersionBar = sdk.getComponent('globals.NewVersionBar'); const UpdateCheckBar = sdk.getComponent('globals.UpdateCheckBar'); const PasswordNagBar = sdk.getComponent('globals.PasswordNagBar'); @@ -353,7 +354,9 @@ const LoggedInView = React.createClass({ let topBar; const isGuest = this.props.matrixClient.isGuest(); - if (this.props.hasNewVersion) { + if (this.props.showCookieBar) { + topBar = ; + } else if (this.props.hasNewVersion) { topBar = ; diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 3005bc86ad..051b9ed10b 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -165,6 +165,8 @@ export default React.createClass({ newVersionReleaseNotes: null, checkingForUpdate: null, + showCookieBar: false, + // Parameters used in the registration dance with the IS register_client_secret: null, register_session_id: null, @@ -227,8 +229,6 @@ export default React.createClass({ componentWillMount: function() { SdkConfig.put(this.props.config); - if (!SettingsStore.getValue("analyticsOptOut")) Analytics.enable(); - // Used by _viewRoom before getting state from sync this.firstSyncComplete = false; this.firstSyncPromise = Promise.defer(); @@ -361,6 +361,16 @@ export default React.createClass({ // loadSession as there's logic there to ask the user if they want // to try logging out. }); + + if (SettingsStore.getValue("showCookieBar")) { + this.setState({ + showCookieBar: true, + }); + } + + if (SettingsStore.getValue("analyticsOptIn")) { + Analytics.enable(); + } }, componentWillUnmount: function() { @@ -673,6 +683,23 @@ export default React.createClass({ hideToSRUsers: false, }); break; + case 'accept_cookies': + SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, true); + SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false); + + this.setState({ + showCookieBar: false, + }); + Analytics.enable(); + break; + case 'reject_cookies': + SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, false); + SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false); + + this.setState({ + showCookieBar: false, + }); + break; } }, @@ -1621,6 +1648,7 @@ export default React.createClass({ onRegistered={this.onRegistered} currentRoomId={this.state.currentRoomId} teamToken={this._teamToken} + showCookieBar={this.state.showCookieBar} {...this.props} {...this.state} /> diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js new file mode 100644 index 0000000000..f1fbbcc83a --- /dev/null +++ b/src/components/views/globals/CookieBar.js @@ -0,0 +1,73 @@ +/* +Copyright 2018 New Vector Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import dis from '../../../dispatcher'; +import { _t } from '../../../languageHandler'; +import sdk from '../../../index'; + +const PrivacyLink = (sub) => + + { sub } + ; + +export default React.createClass({ + onAccept: function() { + dis.dispatch({ + action: 'accept_cookies', + }); + }, + + onReject: function() { + dis.dispatch({ + action: 'reject_cookies', + }); + }, + + render: function() { + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + const toolbarClasses = "mx_MatrixToolbar"; + return ( +
+ Warning +
+ { _t( + "Help us improve Riot by sending usage data. " + + "This will use a cookie " + + "(see our cookie and " + + "privacy policies)", + {}, + { + // XXX: We need to link to the page that explains our cookies + 'CookieLink': PrivacyLink, + 'PrivacyLink': PrivacyLink, + }, + ) } +
+ + { _t("Send usage data") } + + + + +
+ ); + }, +}); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 957deb35c5..8f7d1c36eb 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -209,7 +209,8 @@ "Mirror local video feed": "Mirror local video feed", "Disable Community Filter Panel": "Disable Community Filter Panel", "Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls", - "Opt out of analytics": "Opt out of analytics", + "Send analytics data": "Send analytics data", + "Show cookie bar": "Show cookie bar", "Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device", "Never send encrypted messages to unverified devices in this room from this device": "Never send encrypted messages to unverified devices in this room from this device", "Enable inline URL previews by default": "Enable inline URL previews by default", @@ -634,6 +635,8 @@ "Something went wrong when trying to get your communities.": "Something went wrong when trying to get your communities.", "Display your community flair in rooms configured to show it.": "Display your community flair in rooms configured to show it.", "You're not currently a member of any communities.": "You're not currently a member of any communities.", + "Help us improve Riot by sending usage data. This will use a cookie (see our cookie and privacy policies)": "Help us improve Riot by sending usage data. This will use a cookie (see our cookie and privacy policies)", + "Send usage data": "Send usage data", "You are not receiving desktop notifications": "You are not receiving desktop notifications", "Enable them now": "Enable them now", "What's New": "What's New", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 663318f990..8f50885c14 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -213,11 +213,16 @@ export const SETTINGS = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: "en", }, - "analyticsOptOut": { + "analyticsOptIn": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - displayName: _td('Opt out of analytics'), + displayName: _td('Send analytics data'), default: false, }, + "showCookieBar": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + displayName: _td('Show cookie bar'), + default: true, + }, "autocompleteDelay": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: 200, From aa4bbbc3db3b8b505f1fa78f4b718ad7662e6f10 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 15:38:47 +0100 Subject: [PATCH 06/16] Remove cookie bar setting from UserSettings --- src/i18n/strings/en_EN.json | 1 - src/settings/Settings.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8f7d1c36eb..70eccca6f1 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -210,7 +210,6 @@ "Disable Community Filter Panel": "Disable Community Filter Panel", "Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls", "Send analytics data": "Send analytics data", - "Show cookie bar": "Show cookie bar", "Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device", "Never send encrypted messages to unverified devices in this room from this device": "Never send encrypted messages to unverified devices in this room from this device", "Enable inline URL previews by default": "Enable inline URL previews by default", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 8f50885c14..b1bc4161fd 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -220,7 +220,6 @@ export const SETTINGS = { }, "showCookieBar": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - displayName: _td('Show cookie bar'), default: true, }, "autocompleteDelay": { From d01e7388393b70e76203964500dec98863056264 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 15 May 2018 15:39:12 +0100 Subject: [PATCH 07/16] Fix UserSettings for new analyticsOptIn --- src/components/structures/UserSettings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 35a55284fd..c8ce79905d 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -86,9 +86,9 @@ const SIMPLE_SETTINGS = [ // These settings must be defined in SettingsStore const ANALYTICS_SETTINGS = [ { - id: 'analyticsOptOut', + id: 'analyticsOptIn', fn: function(checked) { - Analytics[checked ? 'disable' : 'enable'](); + checked ? Analytics.enable() : Analytics.disable(); }, }, ]; From 4e6594d64b58dcd1bc9b0303e0fcef0a2348d057 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 16 May 2018 10:41:18 +0100 Subject: [PATCH 08/16] Allow arbitrary hrefs for cookie/privacy links --- src/components/views/globals/CookieBar.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js index f1fbbcc83a..7625518252 100644 --- a/src/components/views/globals/CookieBar.js +++ b/src/components/views/globals/CookieBar.js @@ -19,11 +19,11 @@ import dis from '../../../dispatcher'; import { _t } from '../../../languageHandler'; import sdk from '../../../index'; -const PrivacyLink = (sub) => +const makeLink = (href) => (sub) => { sub } ; @@ -56,8 +56,8 @@ export default React.createClass({ {}, { // XXX: We need to link to the page that explains our cookies - 'CookieLink': PrivacyLink, - 'PrivacyLink': PrivacyLink, + 'CookieLink': makeLink("https://riot.im/privacy"), + 'PrivacyLink': makeLink("https://riot.im/privacy"), }, ) } From d15051a635633f95a6e058e1c8c565448ae4fa32 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 16 May 2018 15:49:23 +0100 Subject: [PATCH 09/16] Add policyLink configuration to piwik Also: - Make CookieBar ES6 class - Alter phrasing on CookieBar - Conditionaly display longer "...(See our ++cookie and privacy policies++)." if policy link is configured. --- src/components/structures/LoggedInView.js | 3 +- src/components/views/globals/CookieBar.js | 55 ++++++++++++----------- src/i18n/strings/en_EN.json | 5 ++- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index abb2eb92aa..c1d30391ab 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -355,7 +355,8 @@ const LoggedInView = React.createClass({ let topBar; const isGuest = this.props.matrixClient.isGuest(); if (this.props.showCookieBar) { - topBar = ; + const policyUrl = this.props.config.piwik ? (this.props.config.piwik.policyUrl || null) : null; + topBar = ; } else if (this.props.hasNewVersion) { topBar = (sub) => - - { sub } - ; +export default class CookieBar extends React.Component { + static propTypes = { + policyUrl: PropTypes.string, + } -export default React.createClass({ - onAccept: function() { + constructor() { + super(); + } + + onAccept() { dis.dispatch({ action: 'accept_cookies', }); - }, + } - onReject: function() { + onReject() { dis.dispatch({ action: 'reject_cookies', }); - }, + } - render: function() { + render() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const toolbarClasses = "mx_MatrixToolbar"; return (
Warning
- { _t( - "Help us improve Riot by sending usage data. " + - "This will use a cookie " + - "(see our cookie and " + - "privacy policies)", + { this.props.policyUrl ? _t( + "Help improve Riot by sending usage data? " + + "This will use a cookie. " + + "(See our cookie and privacy policies).", {}, { // XXX: We need to link to the page that explains our cookies - 'CookieLink': makeLink("https://riot.im/privacy"), - 'PrivacyLink': makeLink("https://riot.im/privacy"), + 'PolicyLink': (sub) => + { sub } + + , }, - ) } + ) : _t("Help improve Riot by sending usage data? This will use a cookie.") }
- { _t("Send usage data") } + { _t("Yes please") }
); - }, -}); + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 70eccca6f1..239b45c32e 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -634,8 +634,9 @@ "Something went wrong when trying to get your communities.": "Something went wrong when trying to get your communities.", "Display your community flair in rooms configured to show it.": "Display your community flair in rooms configured to show it.", "You're not currently a member of any communities.": "You're not currently a member of any communities.", - "Help us improve Riot by sending usage data. This will use a cookie (see our cookie and privacy policies)": "Help us improve Riot by sending usage data. This will use a cookie (see our cookie and privacy policies)", - "Send usage data": "Send usage data", + "Help improve Riot by sending usage data? This will use a cookie. (See our cookie and privacy policies).": "Help improve Riot by sending usage data? This will use a cookie. (See our cookie and privacy policies).", + "Help improve Riot by sending usage data? This will use a cookie.": "Help improve Riot by sending usage data? This will use a cookie.", + "Yes please": "Yes please", "You are not receiving desktop notifications": "You are not receiving desktop notifications", "Enable them now": "Enable them now", "What's New": "What's New", From 0bda607bb2fb22eb622cb2d5db253f0a1dd6cbad Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 16 May 2018 15:53:43 +0100 Subject: [PATCH 10/16] Only show cookie bar if analytics configured --- src/components/structures/LoggedInView.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index c1d30391ab..2dd5a75c47 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -354,8 +354,10 @@ const LoggedInView = React.createClass({ let topBar; const isGuest = this.props.matrixClient.isGuest(); - if (this.props.showCookieBar) { - const policyUrl = this.props.config.piwik ? (this.props.config.piwik.policyUrl || null) : null; + if (this.props.showCookieBar && + this.props.config.piwik + ) { + const policyUrl = this.props.config.piwik.policyUrl || null; topBar = ; } else if (this.props.hasNewVersion) { topBar = Date: Wed, 16 May 2018 18:57:53 +0100 Subject: [PATCH 11/16] Specify valid address types to "Start a chat" dialog fixes https://github.com/vector-im/riot-web/issues/5459 --- src/RoomInvite.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/RoomInvite.js b/src/RoomInvite.js index 31541148d9..0bcc08eb06 100644 --- a/src/RoomInvite.js +++ b/src/RoomInvite.js @@ -57,6 +57,7 @@ export function showStartChatInviteDialog() { title: _t('Start a chat'), description: _t("Who would you like to communicate with?"), placeholder: _t("Email, name or matrix ID"), + validAddressTypes: ['mx-user-id', 'email'], button: _t("Start Chat"), onFinished: _onStartChatFinished, }); From e53497421e0d0a1974205821619676244ef28802 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 17 May 2018 16:47:17 +0100 Subject: [PATCH 12/16] Fix image size jumping regression Fixes https://github.com/vector-im/riot-web/issues/6654 --- src/components/views/messages/MImageBody.js | 3 ++- src/components/views/messages/MStickerBody.js | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index 6cc492acf8..f59b3a9e2c 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2018 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -140,7 +141,6 @@ export default class extends React.Component { } onImageLoad() { - this.fixupHeight(); this.props.onWidgetLoad(); } @@ -208,6 +208,7 @@ export default class extends React.Component { }).done(); } this._afterComponentDidMount(); + this.fixupHeight(); } // To be overridden by subclasses (e.g. MStickerBody) for further diff --git a/src/components/views/messages/MStickerBody.js b/src/components/views/messages/MStickerBody.js index 3a412fc2e2..aaad5ba75e 100644 --- a/src/components/views/messages/MStickerBody.js +++ b/src/components/views/messages/MStickerBody.js @@ -40,7 +40,6 @@ export default class MStickerBody extends MImageBody { } _onImageLoad() { - this.fixupHeight(); this.setState({ placeholderClasses: 'mx_MStickerBody_placeholder_invisible', }); From a7006307bf3631824cd484d3b51cec6d8124ed9c Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 17 May 2018 16:50:16 +0100 Subject: [PATCH 13/16] Call afterComponentDidMount() after componentDidMount --- src/components/views/messages/MImageBody.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index f59b3a9e2c..8045d43104 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -207,8 +207,8 @@ export default class extends React.Component { }); }).done(); } - this._afterComponentDidMount(); this.fixupHeight(); + this._afterComponentDidMount(); } // To be overridden by subclasses (e.g. MStickerBody) for further From 43dbf306b057f6415a3ab7bebcebdcbfd16e7ec0 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 17 May 2018 17:04:38 +0100 Subject: [PATCH 14/16] Prepare changelog for v0.12.5 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a20b902a6e..b161a9d908 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +Changes in [0.12.5](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.12.5) (2018-05-17) +===================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.12.4...v0.12.5) + + * Fix image size jumping regression + [\#1909](https://github.com/matrix-org/matrix-react-sdk/pull/1909) + Changes in [0.12.4](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.12.4) (2018-05-16) ===================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.12.4-rc.6...v0.12.4) From fa7f6c2c4cd1c938e4365bd2380264b1245cc44f Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 17 May 2018 17:04:39 +0100 Subject: [PATCH 15/16] v0.12.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60f65f4c39..6c34979c43 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.12.4", + "version": "0.12.5", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 4a9f4ba5eb889be78bba574ef8c3ea6269ef1775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Sch=C3=BCrmann?= Date: Thu, 17 May 2018 20:12:51 +0200 Subject: [PATCH 16/16] Fix vector-im/riot-web#6523 Emoji rendering destroys paragraphs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This regression was probably introduced in 4f4441fb07dcdfb831e4b54b9f8d7e611c172f29 and is caused by the fact that the variable `isHtml` conflates two different meanings: - The event contains an HTML message - The event message is displayed using HTML This is an important difference. Plain text messages that contain emojies are rendered with an HTML string and thus have to be sanitized etc. But they must not use the MarkDown CSS styles for HTML messages. The MarkDown CSS styles include `whitespace: normal` because HTML events use `
`-tags for line breaks. Plain text messages with emojies obviously don't use `
`-tags, so these styles must not be applied. Signed-off-by: Jonas Schürmann --- src/HtmlUtils.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 58572cf144..7ca404be31 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -413,12 +413,13 @@ class TextHighlighter extends BaseHighlighter { * opts.stripReplyFallback: optional argument specifying the event is a reply and so fallback needs removing */ export function bodyToHtml(content, highlights, opts={}) { - let isHtml = content.format === "org.matrix.custom.html" && content.formatted_body; + const isHtmlMessage = content.format === "org.matrix.custom.html" && content.formatted_body; let bodyHasEmoji = false; let strippedBody; let safeBody; + let isDisplayedWithHtml; // XXX: We sanitize the HTML whilst also highlighting its text nodes, to avoid accidentally trying // to highlight HTML tags themselves. However, this does mean that we don't highlight textnodes which // are interrupted by HTML tags (not that we did before) - e.g. foobar won't get highlighted @@ -439,17 +440,18 @@ export function bodyToHtml(content, highlights, opts={}) { if (opts.stripReplyFallback && formattedBody) formattedBody = ReplyThread.stripHTMLReply(formattedBody); strippedBody = opts.stripReplyFallback ? ReplyThread.stripPlainReply(content.body) : content.body; - bodyHasEmoji = containsEmoji(isHtml ? formattedBody : content.body); + bodyHasEmoji = containsEmoji(isHtmlMessage ? formattedBody : content.body); // Only generate safeBody if the message was sent as org.matrix.custom.html - if (isHtml) { + if (isHtmlMessage) { + isDisplayedWithHtml = true; safeBody = sanitizeHtml(formattedBody, sanitizeHtmlParams); } else { // ... or if there are emoji, which we insert as HTML alongside the // escaped plaintext body. if (bodyHasEmoji) { - isHtml = true; + isDisplayedWithHtml = true; safeBody = sanitizeHtml(escape(strippedBody), sanitizeHtmlParams); } } @@ -475,10 +477,10 @@ export function bodyToHtml(content, highlights, opts={}) { const className = classNames({ 'mx_EventTile_body': true, 'mx_EventTile_bigEmoji': emojiBody, - 'markdown-body': isHtml, + 'markdown-body': isHtmlMessage, }); - return isHtml ? + return isDisplayedWithHtml ? : { strippedBody }; }