From ee0e6c5913f2b0202bad6e81fd963e3dd59454ec Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 9 May 2018 11:53:37 +0100 Subject: [PATCH 01/44] Remove margins when in a ReplyThread to stop them taking so much space Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- res/css/views/elements/_ReplyThread.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/res/css/views/elements/_ReplyThread.scss b/res/css/views/elements/_ReplyThread.scss index a02f42751c..bf44a11728 100644 --- a/res/css/views/elements/_ReplyThread.scss +++ b/res/css/views/elements/_ReplyThread.scss @@ -14,8 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_ReplyThread { + margin-top: 0; +} + .mx_ReplyThread .mx_DateSeparator { font-size: 1em !important; + margin-top: 0; margin-bottom: 0; padding-bottom: 1px; bottom: -5px; From 76f19787215febec549368c444790c2e16c251e2 Mon Sep 17 00:00:00 2001 From: Kenneth Larsson Date: Wed, 9 May 2018 12:32:02 +0000 Subject: [PATCH 02/44] Translated using Weblate (Swedish) Currently translated at 57.4% (674 of 1174 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sv/ --- src/i18n/strings/sv.json | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json index 42c06615cb..fea64b3f27 100644 --- a/src/i18n/strings/sv.json +++ b/src/i18n/strings/sv.json @@ -651,5 +651,28 @@ "Remove avatar": "Ta bort profilbild", "This invitation was sent to an email address which is not associated with this account:": "Den här inbjudan skickades till en emailadress som inte är kopplad till detta konto:", "To link to a room it must have an address.": "För att länka till ett rum behöver det en adress.", - "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (nivå %(powerLevelNumber)s)" + "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (nivå %(powerLevelNumber)s)", + "Unknown Address": "Okänd adress", + "%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s", + "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)s har gått med %(count)s gånger", + "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)sgick med", + "%(oneUser)sjoined %(count)s times|other": "%(oneUser)s har gått med %(count)s gånger", + "%(oneUser)sjoined %(count)s times|one": "%(oneUser)sgick med", + "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)shar lämnat %(count)s gånger", + "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)slämnade", + "%(oneUser)sleft %(count)s times|other": "%(oneUser)shar lämnat %(count)s gånger", + "%(oneUser)sleft %(count)s times|one": "%(oneUser)slämnade", + "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)shar gått med och lämnat %(count)s gånger", + "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)shar gått med och lämnat", + "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)shar gått med och lämnat %(count)s gånger", + "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)shar gått med och lämnat", + "And %(count)s more...|other": "Och %(count)s till...", + "ex. @bob:example.com": "t.ex. @kalle:exempel.com", + "Add User": "Lägg till användare", + "Matrix ID": "Matrix-ID", + "Matrix Room ID": "Matrix-rums-ID", + "email address": "epostadress", + "Try using one of the following valid address types: %(validTypesList)s.": "Prova att använda någon av följande giltiga adresstyper: %(validTypesList)s.", + "You have entered an invalid address.": "Du har angett en ogiltig adress.", + "Preparing to send logs": "Förbereder att skicka loggar" } From 7d0f6532ec69efc0c1c123e7afe3fdcb06c1382f Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 9 May 2018 13:44:41 +0100 Subject: [PATCH 03/44] Prepare changelog for v0.12.4-rc.1 --- CHANGELOG.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 334461bffb..30099319a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,68 @@ +Changes in [0.12.4-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.12.4-rc.1) (2018-05-09) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.12.3...v0.12.4-rc.1) + + * Update from Weblate. + [\#1881](https://github.com/matrix-org/matrix-react-sdk/pull/1881) + * Pin lolex at 2.3.2 to avoid bug causing tests to fail + [\#1880](https://github.com/matrix-org/matrix-react-sdk/pull/1880) + * Replies: un-break click-to-mention on SenderProfile for reply&preview + [\#1878](https://github.com/matrix-org/matrix-react-sdk/pull/1878) + * Add tests for RoomList + [\#1877](https://github.com/matrix-org/matrix-react-sdk/pull/1877) + * Fix crash when browser doesn't report page change measurement + [\#1874](https://github.com/matrix-org/matrix-react-sdk/pull/1874) + * fix thinko when changing from ClientPeg to context in static method (DUH) + [\#1875](https://github.com/matrix-org/matrix-react-sdk/pull/1875) + * Fix Replies :D + [\#1873](https://github.com/matrix-org/matrix-react-sdk/pull/1873) + * Update eslint-plugin-react + [\#1871](https://github.com/matrix-org/matrix-react-sdk/pull/1871) + * relax lint for jsx-curly-spacing and arrow-parens + [\#1872](https://github.com/matrix-org/matrix-react-sdk/pull/1872) + * Use develop js-sdk in jenkins build + [\#1870](https://github.com/matrix-org/matrix-react-sdk/pull/1870) + * Replies + [\#1741](https://github.com/matrix-org/matrix-react-sdk/pull/1741) + * Use the right js-sdk branch when testing + [\#1869](https://github.com/matrix-org/matrix-react-sdk/pull/1869) + * Prevent error responses wedging group request concurrency limit + [\#1867](https://github.com/matrix-org/matrix-react-sdk/pull/1867) + * Refresh group rooms and members when selecting a tag + [\#1868](https://github.com/matrix-org/matrix-react-sdk/pull/1868) + * Refactor GroupStores into one global GroupStore + [\#1866](https://github.com/matrix-org/matrix-react-sdk/pull/1866) + * Switch back to using blob URLs for rendering e2e attachments + [\#1864](https://github.com/matrix-org/matrix-react-sdk/pull/1864) + * Hide inline encryption icons except when hovering over a message + [\#1845](https://github.com/matrix-org/matrix-react-sdk/pull/1845) + * UI fixes in SessionRestoreErrorDialog + [\#1860](https://github.com/matrix-org/matrix-react-sdk/pull/1860) + * Fix UX issues with bug report dialog + [\#1863](https://github.com/matrix-org/matrix-react-sdk/pull/1863) + * fix ugly img errors and correctly render SVG thumbnails + [\#1865](https://github.com/matrix-org/matrix-react-sdk/pull/1865) + * Fix error handling on session restore + [\#1859](https://github.com/matrix-org/matrix-react-sdk/pull/1859) + * Add tests for GroupView + [\#1862](https://github.com/matrix-org/matrix-react-sdk/pull/1862) + * Update version of hoek + [\#1861](https://github.com/matrix-org/matrix-react-sdk/pull/1861) + * Fix bug that caused crash when analytics HS/IS whitelists not specified + [\#1858](https://github.com/matrix-org/matrix-react-sdk/pull/1858) + * Fix Analytics to not import DEFAULTS, therefore avoiding NPE + [\#1857](https://github.com/matrix-org/matrix-react-sdk/pull/1857) + * Null check piwik config before using it + [\#1856](https://github.com/matrix-org/matrix-react-sdk/pull/1856) + * Track actual window location origin and hash + [\#1853](https://github.com/matrix-org/matrix-react-sdk/pull/1853) + * Replace document.origin with window.location.origin + [\#1855](https://github.com/matrix-org/matrix-react-sdk/pull/1855) + * Optionally hide widget popout button. + [\#1854](https://github.com/matrix-org/matrix-react-sdk/pull/1854) + * Add a button to 'pop out' widgets in to their own tab. + [\#1851](https://github.com/matrix-org/matrix-react-sdk/pull/1851) + Changes in [0.12.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.12.3) (2018-04-30) ===================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.12.3-rc.3...v0.12.3) From ddf98705f2e4fcee3f8449a4613bae6f1c7fbccb Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 9 May 2018 13:44:42 +0100 Subject: [PATCH 04/44] v0.12.4-rc.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9c71c1399c..eb6c2e33b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.12.3", + "version": "0.12.4-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From cf77c9ea055c9f869064c109c538f1213bfb2154 Mon Sep 17 00:00:00 2001 From: Kenneth Larsson Date: Wed, 9 May 2018 13:21:40 +0000 Subject: [PATCH 05/44] Translated using Weblate (Swedish) Currently translated at 58.0% (682 of 1174 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sv/ --- src/i18n/strings/sv.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json index fea64b3f27..b2d6ac9ad9 100644 --- a/src/i18n/strings/sv.json +++ b/src/i18n/strings/sv.json @@ -674,5 +674,13 @@ "email address": "epostadress", "Try using one of the following valid address types: %(validTypesList)s.": "Prova att använda någon av följande giltiga adresstyper: %(validTypesList)s.", "You have entered an invalid address.": "Du har angett en ogiltig adress.", - "Preparing to send logs": "Förbereder att skicka loggar" + "Preparing to send logs": "Förbereder att skicka loggar", + "Logs sent": "Loggar skickade", + "Failed to send logs: ": "Det gick inte att skicka loggar: ", + "Submit debug logs": "Skicka felsökningsloggar", + "Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Felsökningsloggar innehåller användningsdata för applikationen inklusive ditt användarnamn, ID:n eller alias för de rum och grupper du har besökt och användarnamn för andra användare. De innehåller inte meddelanden.", + "Riot bugs are tracked on GitHub: create a GitHub issue.": "Riot-buggar hanteras på GitHub: skapa en GitHub-issue.", + "GitHub issue link:": "Länk till GitHub-issue:", + "Notes:": "Noteringar:", + "Start new chat": "Starta ny chatt" } From 97b9316ec760376a7ac402e40c2a968e334f2091 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 9 May 2018 15:48:53 +0100 Subject: [PATCH 06/44] Fix issue incorrect positioning with widget loading indicator by making sure to apply the correct CSS class to the parent --- src/components/views/elements/AppTile.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 007eb8126c..bf24da506b 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -534,7 +534,11 @@ export default class AppTile extends React.Component { ); if (this.state.initialising) { - appTileBody = loadingElement; + appTileBody = ( +
+ { loadingElement } +
+ ); } else if (this.state.hasPermissionToLoad == true) { if (this.isMixedContent()) { appTileBody = ( From 0a326dc6a02c664f58fbe65d21ab568a969a1fd5 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 9 May 2018 14:59:35 +0100 Subject: [PATCH 07/44] Take feature_sticker_messagse out of labs --- src/components/views/rooms/MessageComposer.js | 5 +---- src/settings/Settings.js | 6 ------ 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 24b07eb3bf..28a90b375a 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -338,10 +338,7 @@ export default class MessageComposer extends React.Component { } } - let stickerpickerButton; - if (SettingsStore.isFeatureEnabled('feature_sticker_messages')) { - stickerpickerButton = ; - } + const stickerpickerButton = ; controls.push( Date: Wed, 9 May 2018 16:41:45 +0100 Subject: [PATCH 08/44] Improve appearance of short-lived app loading spinner by hiding it for 500ms - thereby only showing it if the loading is taking a long time. --- res/css/views/rooms/_AppsDrawer.scss | 13 +++++++++++++ src/components/views/elements/AppTile.js | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/res/css/views/rooms/_AppsDrawer.scss b/res/css/views/rooms/_AppsDrawer.scss index 0cf3e7b9cb..28d432686d 100644 --- a/res/css/views/rooms/_AppsDrawer.scss +++ b/res/css/views/rooms/_AppsDrawer.scss @@ -266,6 +266,19 @@ form.mx_Custom_Widget_Form div { right: 0; } +.mx_AppLoading_spinner_fadeIn { + animation-fill-mode: backwards; + animation-duration: 200ms; + animation-delay: 500ms; + animation-name: mx_AppLoading_spinner_fadeIn_animation; +} + +@keyframes mx_AppLoading_spinner_fadeIn_animation { + from { opacity: 0 } + to { opacity: 1 } +} + + .mx_AppLoading iframe { display: none; } diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index bf24da506b..7c4ab13c5a 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -529,7 +529,7 @@ export default class AppTile extends React.Component { if (this.props.show) { const loadingElement = ( -
+
); From 54fdb234d5e780ab94ab7e33af1f98e5832ec20e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 9 May 2018 17:34:53 +0100 Subject: [PATCH 09/44] Prepare changelog for v0.12.4-rc.2 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30099319a9..8f8e89250e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +Changes in [0.12.4-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.12.4-rc.2) (2018-05-09) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.12.4-rc.1...v0.12.4-rc.2) + + * Improve appearance of short-lived widget loading spinner + * Make sticker picker fully-fledged feature + * Fix incorrect positioning with widget loading indicator + Changes in [0.12.4-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.12.4-rc.1) (2018-05-09) =============================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.12.3...v0.12.4-rc.1) From 6a0bff6685acd3e68b5b7221310140ed3a9aef48 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 9 May 2018 17:34:54 +0100 Subject: [PATCH 10/44] v0.12.4-rc.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eb6c2e33b3..3958e1b3d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.12.4-rc.1", + "version": "0.12.4-rc.2", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 1f23809c99274111622dd52582c3dc5580f7225d Mon Sep 17 00:00:00 2001 From: Sotiris Papatheodorou Date: Thu, 10 May 2018 11:31:03 +0000 Subject: [PATCH 11/44] Translated using Weblate (Greek) Currently translated at 66.5% (781 of 1174 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/el/ --- src/i18n/strings/el.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/el.json b/src/i18n/strings/el.json index b5acd8855e..12d08787d5 100644 --- a/src/i18n/strings/el.json +++ b/src/i18n/strings/el.json @@ -57,7 +57,7 @@ "%(senderDisplayName)s removed the room name.": "Ο %(senderDisplayName)s διέγραψε το όνομα του δωματίου.", "Changes your display nickname": "Αλλάζει το ψευδώνυμο χρήστη", "Conference call failed.": "Η κλήση συνδιάσκεψης απέτυχε.", - "powered by Matrix": "βασισμένο στο πρωτόκολλο Matrix", + "powered by Matrix": "βασισμένο στο Matrix", "Confirm password": "Επιβεβαίωση κωδικού πρόσβασης", "Confirm your new password": "Επιβεβαίωση του νέου κωδικού πρόσβασης", "Continue": "Συνέχεια", @@ -772,5 +772,15 @@ "Collapse panel": "Ελαχιστοποίηση καρτέλας", "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Με τον τρέχον περιηγητή, η εμφάνιση και η αίσθηση της εφαρμογής ενδέχεται να είναι εντελώς εσφαλμένη και ορισμένες ή όλες οι λειτουργίες ενδέχεται να μην λειτουργούν. Εάν θέλετε να το δοκιμάσετε ούτως ή άλλως μπορείτε να συνεχίσετε, αλλά είστε μόνοι σας σε ό, τι αφορά τα προβλήματα που μπορεί να αντιμετωπίσετε!", "Checking for an update...": "Γίνεται έλεγχος για ενημέρωση...", - "There are advanced notifications which are not shown here": "Υπάρχουν προχωρημένες ειδοποιήσεις οι οποίες δεν εμφανίζονται εδώ" + "There are advanced notifications which are not shown here": "Υπάρχουν προχωρημένες ειδοποιήσεις οι οποίες δεν εμφανίζονται εδώ", + "Your identity server's URL": "Το URL του διακομιστή ταυτοποίησής σας", + "The platform you're on": "Η πλατφόρμα στην οποία βρίσκεστε", + "The version of Riot.im": "Η έκδοση του Riot.im", + "Your language of choice": "Η γλώσσα επιλογής σας", + "Your homeserver's URL": "Το URL του διακομιστή σας", + "Every page you use in the app": "Κάθε σελίδα που χρησιμοποιείτε στην εφαρμογή", + "e.g. ": "π.χ. ", + "Your device resolution": "Η ανάλυση της συσκευής σας", + "The information being sent to us to help make Riot.im better includes:": "Οι πληροφορίες που στέλνονται σε εμάς με σκοπό την βελτίωση του Riot.im περιλαμβάνουν:", + "Call Failed": "Η κλήση απέτυχε" } From f6a2e8d52ca22ee4ba58cfbfae19e7d288b3304d Mon Sep 17 00:00:00 2001 From: Xose M Date: Fri, 11 May 2018 10:43:02 +0000 Subject: [PATCH 12/44] Translated using Weblate (Galician) Currently translated at 100.0% (1174 of 1174 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/gl/ --- src/i18n/strings/gl.json | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/gl.json b/src/i18n/strings/gl.json index 06bff9eb76..7d10ca4ec5 100644 --- a/src/i18n/strings/gl.json +++ b/src/i18n/strings/gl.json @@ -1156,5 +1156,25 @@ "Collapse panel": "Agochar panel", "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Co seu navegador actual a apareciencia e uso do aplicativo poderían estar totalmente falseadas, e algunhas características poderían non funcionar. Se quere pode continuar, pero debe ser consciente de que poden haber fallos!", "Checking for an update...": "Comprobando as actualizacións...", - "There are advanced notifications which are not shown here": "Existen notificacións avanzadas que non se mostran aquí" + "There are advanced notifications which are not shown here": "Existen notificacións avanzadas que non se mostran aquí", + "Every page you use in the app": "Cada páxina que vostede utiliza no aplicativo", + "e.g. ": "ex. ", + "Your User Agent": "User Agent", + "Your device resolution": "Resolución do dispositivo", + "Missing roomId.": "Falta o id da sala.", + "Always show encryption icons": "Mostra sempre iconas de cifrado", + "At this time it is not possible to reply with a file so this will be sent without being a reply.": "En este intre non é posible respostar con un ficheiro así que este será enviado sin ser considerado resposta.", + "Unable to reply": "Non puido respostar", + "At this time it is not possible to reply with an emote.": "En este intre non é posible respostar con un emote.", + "Popout widget": "Widget emerxente", + "Picture": "Imaxe", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Non se cargou o evento ao que respostaba, ou non existe ou non ten permiso para velo.", + "Riot bugs are tracked on GitHub: create a GitHub issue.": "Os fallos de Riot séguense en GitHub: crear un informe en GitHub.", + "Log out and remove encryption keys?": "Desconectar e eliminar as chaves de cifrado?", + "Send Logs": "Enviar informes", + "Clear Storage and Sign Out": "Limpar o almacenamento e Desconectar", + "Refresh": "Actualizar", + "We encountered an error trying to restore your previous session.": "Atopamos un fallo intentando restablecer a súa sesión anterior.", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Limpando o almacenamento do navegador podería resolver o problema, pero desconectarao e non poderá ler o historial cifrado da conversa.", + "Collapse Reply Thread": "Comprimir o fío de respostas" } From d503c86576380c4a7bdf1504ea4b8cdb76d3c37c Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 10 May 2018 16:00:58 +0100 Subject: [PATCH 13/44] Factor out ContextualMenu component --- src/components/structures/ContextualMenu.js | 88 +++++++++++---------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/src/components/structures/ContextualMenu.js b/src/components/structures/ContextualMenu.js index 0e2df890f3..99d1f892b9 100644 --- a/src/components/structures/ContextualMenu.js +++ b/src/components/structures/ContextualMenu.js @@ -26,9 +26,21 @@ import PropTypes from 'prop-types'; // of doing reusable widgets like dialog boxes & menus where we go and // pass in a custom control as the actual body. -module.exports = { - ContextualMenuContainerId: "mx_ContextualMenu_Container", +const ContextualMenuContainerId = "mx_ContextualMenu_Container"; +function getOrCreateContainer() { + let container = document.getElementById(ContextualMenuContainerId); + + if (!container) { + container = document.createElement("div"); + container.id = ContextualMenuContainerId; + document.body.appendChild(container); + } + + return container; +} + +class ContextualMenu extends React.Component { propTypes: { top: PropTypes.number, bottom: PropTypes.number, @@ -45,39 +57,14 @@ module.exports = { menuPaddingRight: PropTypes.number, menuPaddingBottom: PropTypes.number, menuPaddingLeft: PropTypes.number, - }, - - getOrCreateContainer: function() { - let container = document.getElementById(this.ContextualMenuContainerId); - - if (!container) { - container = document.createElement("div"); - container.id = this.ContextualMenuContainerId; - document.body.appendChild(container); - } - - return container; - }, - - createMenu: function(Element, props) { - const self = this; - - const closeMenu = function(...args) { - ReactDOM.unmountComponentAtNode(self.getOrCreateContainer()); - - if (props && props.onFinished) { - props.onFinished.apply(null, args); - } - }; - - // Close the menu on window resize - const windowResize = function() { - closeMenu(); - }; + } + render() { const position = {}; let chevronFace = null; + const props = this.props; + if (props.top) { position.top = props.top; } else { @@ -158,20 +145,39 @@ module.exports = { menuStyle["paddingRight"] = props.menuPaddingRight; } + const ElementClass = props.elementClass; + // FIXME: If a menu uses getDefaultProps it clobbers the onFinished // property set here so you can't close the menu from a button click! - const menu = ( -
-
- { chevron } - -
-
- + return
+
+ { chevron } +
- ); +
+ +
; + } +} - ReactDOM.render(menu, this.getOrCreateContainer()); +module.exports = { + createMenu: function(ElementClass, props) { + const closeMenu = function(...args) { + ReactDOM.unmountComponentAtNode(getOrCreateContainer()); + + if (props && props.onFinished) { + props.onFinished.apply(null, args); + } + }; + + const menu = ; + + ReactDOM.render(menu, getOrCreateContainer()); return {close: closeMenu}; }, From 9ec2570eab2330e6e079fad1537af28f0f1996ee Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 10 May 2018 17:51:49 +0100 Subject: [PATCH 14/44] Export ContextualMenu component, with added `hasBackground` property , which is only enabled when `createMenu` is used. --- src/components/structures/ContextualMenu.js | 43 +++++++++++---------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/components/structures/ContextualMenu.js b/src/components/structures/ContextualMenu.js index 99d1f892b9..17f1a23e14 100644 --- a/src/components/structures/ContextualMenu.js +++ b/src/components/structures/ContextualMenu.js @@ -40,7 +40,7 @@ function getOrCreateContainer() { return container; } -class ContextualMenu extends React.Component { +export default class ContextualMenu extends React.Component { propTypes: { top: PropTypes.number, bottom: PropTypes.number, @@ -57,6 +57,10 @@ class ContextualMenu extends React.Component { menuPaddingRight: PropTypes.number, menuPaddingBottom: PropTypes.number, menuPaddingLeft: PropTypes.number, + + // If true, insert an invisible screen-sized element behind the + // menu that when clicked will close it. + hasBackground: PropTypes.bool, } render() { @@ -154,31 +158,30 @@ class ContextualMenu extends React.Component { { chevron }
-
+ { props.hasBackground &&
}
; } } -module.exports = { - createMenu: function(ElementClass, props) { - const closeMenu = function(...args) { - ReactDOM.unmountComponentAtNode(getOrCreateContainer()); +export function createMenu(ElementClass, props) { + const closeMenu = function(...args) { + ReactDOM.unmountComponentAtNode(getOrCreateContainer()); - if (props && props.onFinished) { - props.onFinished.apply(null, args); - } - }; + if (props && props.onFinished) { + props.onFinished.apply(null, args); + } + }; - const menu = ; + const menu = ; - ReactDOM.render(menu, getOrCreateContainer()); + ReactDOM.render(menu, getOrCreateContainer()); - return {close: closeMenu}; - }, -}; + return {close: closeMenu}; +} From 2d2b529f80f8805bdce7d39c27ac0f61397c388d Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 14:47:57 +0100 Subject: [PATCH 15/44] Use new ContextualMenu component in Stickerpicker --- src/components/views/rooms/Stickerpicker.js | 93 +++++++++++++-------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index c055c67cd3..a252c0c886 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -17,7 +17,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import Widgets from '../../../utils/widgets'; import AppTile from '../elements/AppTile'; -import ContextualMenu from '../../structures/ContextualMenu'; import MatrixClientPeg from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import sdk from '../../../index'; @@ -36,6 +35,7 @@ export default class Stickerpicker extends React.Component { this._launchManageIntegrations = this._launchManageIntegrations.bind(this); this._removeStickerpickerWidgets = this._removeStickerpickerWidgets.bind(this); this._onWidgetAction = this._onWidgetAction.bind(this); + this._onResize = this._onResize.bind(this); this._onFinished = this._onFinished.bind(this); this.popoverWidth = 300; @@ -44,13 +44,17 @@ export default class Stickerpicker extends React.Component { this.state = { showStickers: false, imError: null, + stickerpickerX: null, + stickerpickerY: null, + stickerpickerWidget: null, + widgetId: null, }; } _removeStickerpickerWidgets() { console.warn('Removing Stickerpicker widgets'); - if (this.widgetId) { - this.scalarClient.disableWidgetAssets(widgetType, this.widgetId).then(() => { + if (this.state.widgetId) { + this.scalarClient.disableWidgetAssets(widgetType, this.state.widgetId).then(() => { console.warn('Assets disabled'); }).catch((err) => { console.error('Failed to disable assets'); @@ -59,8 +63,7 @@ export default class Stickerpicker extends React.Component { console.warn('No widget ID specified, not disabling assets'); } - // Wrap this in a timeout in order to avoid the DOM node from being pulled from under its feet - setTimeout(() => this.stickersMenu.close()); + this.setState({showStickers: false}); Widgets.removeStickerpickerWidgets().then(() => { this.forceUpdate(); }).catch((e) => { @@ -69,6 +72,9 @@ export default class Stickerpicker extends React.Component { } componentDidMount() { + // Close the sticker picker when the window resizes + window.addEventListener('resize', this._onResize); + this.scalarClient = null; if (SdkConfig.get().integrations_ui_url && SdkConfig.get().integrations_rest_url) { this.scalarClient = new ScalarAuthClient(); @@ -82,9 +88,15 @@ export default class Stickerpicker extends React.Component { if (!this.state.imError) { this.dispatcherRef = dis.register(this._onWidgetAction); } + const stickerpickerWidget = Widgets.getStickerpickerWidgets()[0]; + this.setState({ + stickerpickerWidget, + widgetId: stickerpickerWidget ? stickerpickerWidget.id : null, + }); } componentWillUnmount() { + window.removeEventListener('resize', this._onResize); if (this.dispatcherRef) { dis.unregister(this.dispatcherRef); } @@ -102,9 +114,7 @@ export default class Stickerpicker extends React.Component { if (payload.action === "user_widget_updated") { this.forceUpdate(); } else if (payload.action === "stickerpicker_close") { - // Wrap this in a timeout in order to avoid the DOM node from being - // pulled from under its feet - setTimeout(() => this.stickersMenu.close()); + this.setState({showStickers: false}); } } @@ -137,14 +147,13 @@ export default class Stickerpicker extends React.Component { // TODO - Add support for Stickerpickers from multiple app stores. // Render content from multiple stickerpack sources, each within their // own iframe, within the stickerpicker UI element. - const stickerpickerWidget = Widgets.getStickerpickerWidgets()[0]; + const stickerpickerWidget = this.state.stickerpickerWidget; let stickersContent; // Load stickerpack content if (stickerpickerWidget && stickerpickerWidget.content && stickerpickerWidget.content.url) { // Set default name stickerpickerWidget.content.name = stickerpickerWidget.name || _t("Stickerpack"); - this.widgetId = stickerpickerWidget.id; stickersContent = (
@@ -186,12 +195,7 @@ export default class Stickerpicker extends React.Component { // Default content to show if stickerpicker widget not added console.warn("No available sticker picker widgets"); stickersContent = this._defaultStickerpickerContent(); - this.widgetId = null; - this.forceUpdate(); } - this.setState({ - showStickers: false, - }); return stickersContent; } @@ -201,29 +205,17 @@ export default class Stickerpicker extends React.Component { * @param {Event} e Event that triggered the function */ _onShowStickersClick(e) { - const GenericElementContextMenu = sdk.getComponent('context_menus.GenericElementContextMenu'); const buttonRect = e.target.getBoundingClientRect(); // The window X and Y offsets are to adjust position when zoomed in to page const x = buttonRect.right + window.pageXOffset - 42; const y = (buttonRect.top + (buttonRect.height / 2) + window.pageYOffset) - 19; - // const self = this; - this.stickersMenu = ContextualMenu.createMenu(GenericElementContextMenu, { - chevronOffset: 10, - chevronFace: 'bottom', - left: x, - top: y, - menuWidth: this.popoverWidth, - menuHeight: this.popoverHeight, - element: this._getStickerpickerContent(), - onFinished: this._onFinished, - menuPaddingTop: 0, - menuPaddingLeft: 0, - menuPaddingRight: 0, + + this.setState({ + showStickers: true, + stickerPickerX: x, + stickerPickerY: y, }); - - - this.setState({showStickers: true}); } /** @@ -231,7 +223,14 @@ export default class Stickerpicker extends React.Component { * @param {Event} ev Event that triggered the function call */ _onHideStickersClick(ev) { - setTimeout(() => this.stickersMenu.close()); + this.setState({showStickers: false}); + } + + /** + * Called when the window is resized + */ + _onResize() { + this.setState({showStickers: false}); } /** @@ -250,20 +249,37 @@ export default class Stickerpicker extends React.Component { this.scalarClient.getScalarInterfaceUrlForRoom( this.props.room, 'type_' + widgetType, - this.widgetId, + this.state.widgetId, ) : null; Modal.createTrackedDialog('Integrations Manager', '', IntegrationsManager, { src: src, }, "mx_IntegrationsManager"); - // Wrap this in a timeout in order to avoid the DOM node from being pulled from under its feet - setTimeout(() => this.stickersMenu.close()); + this.setState({showStickers: false}); } render() { const TintableSvg = sdk.getComponent("elements.TintableSvg"); + const ContextualMenu = sdk.getComponent('structures.ContextualMenu'); + const GenericElementContextMenu = sdk.getComponent('context_menus.GenericElementContextMenu'); let stickersButton; + + const stickerPicker = ; + if (this.state.showStickers) { // Show hide-stickers button stickersButton = @@ -288,6 +304,9 @@ export default class Stickerpicker extends React.Component {
; } - return stickersButton; + return
+ {stickersButton} + {this.state.showStickers && stickerPicker} +
; } } From fee480289ce4ab31173f55f3a4eec30521e39e0b Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 14:49:50 +0100 Subject: [PATCH 16/44] Use correct CSS selector in message composer to stop any last div from having its right-padding removed --- res/css/views/rooms/_MessageComposer.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 2e8f07b7ef..0a708a8edc 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -34,7 +34,7 @@ limitations under the License. width: 100%; } -.mx_MessageComposer_row div:last-child{ +.mx_MessageComposer_row > div:last-child{ padding-right: 0; } From 42c59b59239bacd4a6652986f2338a80d8bd9c5e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 15:07:51 +0100 Subject: [PATCH 17/44] Make AppTile in Stickerpicker persistent using PersistedElement --- .../views/elements/PersistedElement.js | 116 ++++++++++++++++++ src/components/views/rooms/Stickerpicker.js | 7 ++ 2 files changed, 123 insertions(+) create mode 100644 src/components/views/elements/PersistedElement.js diff --git a/src/components/views/elements/PersistedElement.js b/src/components/views/elements/PersistedElement.js new file mode 100644 index 0000000000..4d8cd4140e --- /dev/null +++ b/src/components/views/elements/PersistedElement.js @@ -0,0 +1,116 @@ +/* +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. +*/ + +const classNames = require('classnames'); +const React = require('react'); +const ReactDOM = require('react-dom'); +import PropTypes from 'prop-types'; + +// Shamelessly ripped off Modal.js. There's probably a better way +// of doing reusable widgets like dialog boxes & menus where we go and +// pass in a custom control as the actual body. + +const ContainerId = "mx_PersistedElement"; + +function getOrCreateContainer() { + let container = document.getElementById(ContainerId); + + if (!container) { + container = document.createElement("div"); + container.id = ContainerId; + document.body.appendChild(container); + } + + return container; +} + +// Greater than that of the ContextualMenu +const PE_Z_INDEX = 3000; + +/* + * Class of component that renders its children in a separate ReactDOM virtual tree + * in a container element appended to document.body. + * + * This prevents the children from being unmounted when the parent of PersistedElement + * unmounts, allowing them to persist. + * + * When PE is unmounted, it hides the children using CSS. When mounted or updated, the + * children are made visible and are positioned into a div that is given the same + * bounding rect as the parent of PE. + */ +export default class PersistedElement extends React.Component { + constructor() { + super(); + this.collectChildContainer = this.collectChildContainer.bind(this); + this.collectChild = this.collectChild.bind(this); + } + + collectChildContainer(ref) { + this.childContainer = ref; + } + + collectChild(ref) { + this.child = ref; + this.updateChild(); + } + + componentDidMount() { + this.updateChild(); + } + + componentDidUpdate() { + this.updateChild(); + } + + componentWillUnmount() { + this.updateChildVisibility(this.child, false); + } + + updateChild() { + this.updateChildPosition(this.child, this.childContainer); + this.updateChildVisibility(this.child, true); + } + + updateChildVisibility(child, visible) { + if (!child) return; + child.style.display = visible ? 'block' : 'none'; + } + + updateChildPosition(child, parent) { + if (!child || !parent) return; + + const parentRect = parent.getBoundingClientRect(); + Object.assign(child.style, { + position: 'absolute', + top: parentRect.top + 'px', + left: parentRect.left + 'px', + width: parentRect.width + 'px', + height: parentRect.height + 'px', + zIndex: PE_Z_INDEX, + }); + } + + render() { + const content =
+ {this.props.children} +
; + + ReactDOM.render(content, getOrCreateContainer()); + + return
; + } +} + diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index a252c0c886..5c411aa56e 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -150,6 +150,11 @@ export default class Stickerpicker extends React.Component { const stickerpickerWidget = this.state.stickerpickerWidget; let stickersContent; + // Use a separate ReactDOM tree to render the AppTile separately so that it persists and does + // not unmount when we (a) close the sticker picker (b) switch rooms. It's properties are still + // updated. + const PersistedElement = sdk.getComponent("elements.PersistedElement"); + // Load stickerpack content if (stickerpickerWidget && stickerpickerWidget.content && stickerpickerWidget.content.url) { // Set default name @@ -166,6 +171,7 @@ export default class Stickerpicker extends React.Component { width: this.popoverWidth, }} > + + ); From bd0301c666686e389b966f9038a494f8f061390e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 16:22:54 +0100 Subject: [PATCH 18/44] Add API to send visibiliy actions to widgets --- src/WidgetMessaging.js | 10 ++++++++++ src/components/views/elements/AppTile.js | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index effd96dacf..86eaa0b59b 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -94,6 +94,16 @@ export default class WidgetMessaging { }); } + sendVisibility(visible) { + return this.messageToWidget({ + api: OUTBOUND_API_NAME, + action: "visibility", + visible, + }) + .catch((error) => { + console.error("Failed to send visibility: ", error); + }); + } start() { this.fromWidget.addEndpoint(this.widgetId, this.widgetUrl); diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 7c4ab13c5a..e1be5b11ee 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -389,6 +389,10 @@ export default class AppTile extends React.Component { }).catch((err) => { console.log(`Failed to get capabilities for widget type ${this.props.type}`, this.props.id, err); }); + + // Allow parents to access widget messaging + if (this.props.collectWidgetMessaging) this.props.collectWidgetMessaging(this.widgetMessaging); + this.setState({loading: false}); } From 06919e22d633a7f0c12b1f91870d2cbe8a1b7126 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 16:23:18 +0100 Subject: [PATCH 19/44] When stickerpicker made visible, send visibility over postMessage --- src/components/views/elements/AppTile.js | 19 ++++++++++++++++--- src/components/views/rooms/Stickerpicker.js | 19 ++++++++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index e1be5b11ee..5bcb418242 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -167,6 +167,19 @@ export default class AppTile extends React.Component { // Widget action listeners this.dispatcherRef = dis.register(this._onWidgetAction); + + } + + componentDidUpdate() { + // Allow parents to access widget messaging + if (this.props.collectWidgetMessaging) { + this.props.collectWidgetMessaging(new Promise((resolve) => { + if (this.widgetMessaging) resolve(this.widgetMessaging); + + // Expect this to be resolved later + this._exposeWidgetMessaging = resolve; + })); + } } componentWillUnmount() { @@ -352,6 +365,9 @@ export default class AppTile extends React.Component { if (!this.widgetMessaging) { this._onInitialLoad(); } + if (this._exposeWidgetMessaging) { + this._exposeWidgetMessaging(this.widgetMessaging); + } } /** @@ -390,9 +406,6 @@ export default class AppTile extends React.Component { console.log(`Failed to get capabilities for widget type ${this.props.type}`, this.props.id, err); }); - // Allow parents to access widget messaging - if (this.props.collectWidgetMessaging) this.props.collectWidgetMessaging(this.widgetMessaging); - this.setState({loading: false}); } diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 5c411aa56e..0bdf5fe5df 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -38,6 +38,8 @@ export default class Stickerpicker extends React.Component { this._onResize = this._onResize.bind(this); this._onFinished = this._onFinished.bind(this); + this._collectWidgetMessaging = this._collectWidgetMessaging.bind(this); + this.popoverWidth = 300; this.popoverHeight = 300; @@ -102,6 +104,14 @@ export default class Stickerpicker extends React.Component { } } + componentDidUpdate(prevProps, prevState) { + if (this._appWidgetMessaging && + prevState.showStickers !== this.state.showStickers + ) { + this._appWidgetMessaging.sendVisibility(this.state.showStickers); + } + } + _imError(errorMsg, e) { console.error(errorMsg, e); this.setState({ @@ -137,6 +147,12 @@ export default class Stickerpicker extends React.Component { ); } + async _collectWidgetMessaging(prom) { + const widgetMessaging = await prom; + this._appWidgetMessaging = widgetMessaging; + this._appWidgetMessaging.sendVisibility(true); + } + _getStickerpickerContent() { // Handle Integration Manager errors if (this.state._imError) { @@ -173,6 +189,7 @@ export default class Stickerpicker extends React.Component { > From a4190560405f96e14913103ac258f0ac09a91e61 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 17:28:12 +0100 Subject: [PATCH 20/44] Delinting --- src/components/structures/ContextualMenu.js | 5 +++-- src/components/views/elements/AppTile.js | 1 - src/components/views/elements/PersistedElement.js | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/structures/ContextualMenu.js b/src/components/structures/ContextualMenu.js index 17f1a23e14..daac294d12 100644 --- a/src/components/structures/ContextualMenu.js +++ b/src/components/structures/ContextualMenu.js @@ -173,12 +173,13 @@ export function createMenu(ElementClass, props) { } }; + // We only reference closeMenu once per call to createMenu const menu = ; ReactDOM.render(menu, getOrCreateContainer()); diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 5bcb418242..b345adcc1d 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -167,7 +167,6 @@ export default class AppTile extends React.Component { // Widget action listeners this.dispatcherRef = dis.register(this._onWidgetAction); - } componentDidUpdate() { diff --git a/src/components/views/elements/PersistedElement.js b/src/components/views/elements/PersistedElement.js index 4d8cd4140e..c4bac27b4e 100644 --- a/src/components/views/elements/PersistedElement.js +++ b/src/components/views/elements/PersistedElement.js @@ -14,10 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -const classNames = require('classnames'); const React = require('react'); const ReactDOM = require('react-dom'); -import PropTypes from 'prop-types'; // Shamelessly ripped off Modal.js. There's probably a better way // of doing reusable widgets like dialog boxes & menus where we go and From 9c5c5e282b619a726af57b0f3207d80451b2dff8 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 18:06:58 +0100 Subject: [PATCH 21/44] Send visibility only when changed, and messaging is available --- src/components/views/elements/AppTile.js | 7 +------ src/components/views/rooms/Stickerpicker.js | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index b345adcc1d..cd0eb1ce68 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -172,12 +172,7 @@ export default class AppTile extends React.Component { componentDidUpdate() { // Allow parents to access widget messaging if (this.props.collectWidgetMessaging) { - this.props.collectWidgetMessaging(new Promise((resolve) => { - if (this.widgetMessaging) resolve(this.widgetMessaging); - - // Expect this to be resolved later - this._exposeWidgetMessaging = resolve; - })); + this.props.collectWidgetMessaging(this.widgetMessaging); } } diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 0bdf5fe5df..40ce6e6b39 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -105,11 +105,7 @@ export default class Stickerpicker extends React.Component { } componentDidUpdate(prevProps, prevState) { - if (this._appWidgetMessaging && - prevState.showStickers !== this.state.showStickers - ) { - this._appWidgetMessaging.sendVisibility(this.state.showStickers); - } + this._sendVisibilityToWidget(this.state.showStickers); } _imError(errorMsg, e) { @@ -147,10 +143,19 @@ export default class Stickerpicker extends React.Component { ); } - async _collectWidgetMessaging(prom) { - const widgetMessaging = await prom; + _collectWidgetMessaging(widgetMessaging) { this._appWidgetMessaging = widgetMessaging; - this._appWidgetMessaging.sendVisibility(true); + + // Do this now instead of in componentDidMount because we might not have had the + // reference to widgetMessaging when mounting + this._sendVisibilityToWidget(true); + } + + _sendVisibilityToWidget(visible) { + if (this._appWidgetMessaging && visible !== this._prevSentVisibility) { + this._appWidgetMessaging.sendVisibility(visible); + this._prevSentVisibility = visible; + } } _getStickerpickerContent() { From a0bde2939ed4480110b02a6d9e81ee3c2a6cb94a Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 18:26:35 +0100 Subject: [PATCH 22/44] Prepare changelog for v0.12.4-rc.3 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f8e89250e..89f3741535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +Changes in [0.12.4-rc.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.12.4-rc.3) (2018-05-11) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.12.4-rc.2...v0.12.4-rc.3) + + * Instant Sticker Picker :zap: + [\#1888](https://github.com/matrix-org/matrix-react-sdk/pull/1888) + Changes in [0.12.4-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.12.4-rc.2) (2018-05-09) =============================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.12.4-rc.1...v0.12.4-rc.2) From d90292c6f15ce8fc5b07d8ab3a2a3c0d0635f6ae Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 11 May 2018 18:26:35 +0100 Subject: [PATCH 23/44] v0.12.4-rc.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3958e1b3d0..1125dd3980 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.12.4-rc.2", + "version": "0.12.4-rc.3", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From e856e49fff6dffcb065b93887cfe8b7031f57711 Mon Sep 17 00:00:00 2001 From: Kenneth Larsson Date: Fri, 11 May 2018 23:04:09 +0000 Subject: [PATCH 24/44] Translated using Weblate (Swedish) Currently translated at 64.0% (752 of 1174 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sv/ --- src/i18n/strings/sv.json | 78 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json index b2d6ac9ad9..e987ed29e2 100644 --- a/src/i18n/strings/sv.json +++ b/src/i18n/strings/sv.json @@ -19,7 +19,7 @@ "Advanced": "Avancerat", "Algorithm": "Algoritm", "Always show message timestamps": "Visa alltid tidsstämpel för meddelanden", - "Hide removed messages": "Göm raderade meddelanden", + "Hide removed messages": "Dölj borttagna meddelanden", "Authentication": "Autentisering", "%(items)s and %(lastItem)s": "%(items)s och %(lastItem)s", "and %(count)s others...|other": "och %(count)s andra...", @@ -301,7 +301,7 @@ "%(senderName)s requested a VoIP conference.": "%(senderName)s begärde en VoIP-konferens.", "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Om du återställer ditt lösenord kommer alla krypteringsnycklar på alla enheter att återställas, vilket gör krypterad meddelandehistorik oläsbar om du inte först exporterar dina rumsnycklar och sedan importerar dem igen. I framtiden kommer det här att förbättras.", "Results from DuckDuckGo": "Resultat från DuckDuckGo", - "Return to login screen": "TIllbaka till login-skärmen", + "Return to login screen": "Tillbaka till login-skärmen", "Riot does not have permission to send you notifications - please check your browser settings": "Riot har inte tillstånd att skicka aviseringar - kontrollera webbläsarens inställningar", "Riot was not given permission to send notifications - please try again": "Riot fick inte tillstånd att skicka aviseringar - försök igen", "riot-web version:": "riot-web -version:", @@ -649,7 +649,7 @@ "(~%(count)s results)|one": "(~%(count)s resultat)", "Upload avatar": "Ladda upp profilbild", "Remove avatar": "Ta bort profilbild", - "This invitation was sent to an email address which is not associated with this account:": "Den här inbjudan skickades till en emailadress som inte är kopplad till detta konto:", + "This invitation was sent to an email address which is not associated with this account:": "Den här inbjudan skickades till en epostadress som inte är kopplad till detta konto:", "To link to a room it must have an address.": "För att länka till ett rum behöver det en adress.", "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (nivå %(powerLevelNumber)s)", "Unknown Address": "Okänd adress", @@ -682,5 +682,75 @@ "Riot bugs are tracked on GitHub: create a GitHub issue.": "Riot-buggar hanteras på GitHub: skapa en GitHub-issue.", "GitHub issue link:": "Länk till GitHub-issue:", "Notes:": "Noteringar:", - "Start new chat": "Starta ny chatt" + "Start new chat": "Starta ny chatt", + "Default server": "Standardserver", + "Custom server": "Anpassad server", + "Home server URL": "Hemserver-URL", + "Identity server URL": "Identitetsserver-URL", + "What does this mean?": "Vad betyder det här?", + "User name": "Användarnamn", + "Username on %(hs)s": "Användarnamn på %(hs)s", + "An email has been sent to %(emailAddress)s": "Ett epostmeddelande har skickats till %(emailAddress)s", + "To continue, please enter your password.": "För att fortsätta, vänligen ange ditt lösenord.", + "Please check your email to continue registration.": "Vänligen kolla din epost för att fortsätta registreringen.", + "Token incorrect": "Ogiltig token", + "A text message has been sent to %(msisdn)s": "Ett textmeddelande har skickats till %(msisdn)s", + "Please enter the code it contains:": "Vänligen ange koden det innehåller:", + "Code": "Kod", + "I already have an account": "Jag har redan ett konto", + "Sign in to get started": "Logga in för att komma igång", + "Set a display name:": "Ange ett visningsnamn:", + "Upload an avatar:": "Ladda upp en avatar:", + "This server does not support authentication with a phone number.": "Denna server har inte support för autentisering via telefonnummer.", + "Missing password.": "Lösenord saknas.", + "Passwords don't match.": "Lösenorden matchar inte.", + "Password too short (min %(MIN_PASSWORD_LENGTH)s).": "Lösenordet är för kort (min %(MIN_PASSWORD_LENGTH)s).", + "This doesn't look like a valid email address.": "Det här ser inte ut vara en giltig epostadress.", + "This doesn't look like a valid phone number.": "Det här ser inte ut att vara ett giltigt telefonnummer.", + "You need to enter a user name.": "Du måste ange ett användarnamn.", + "An unknown error occurred.": "Ett okänt fel uppstod.", + "Hide avatar changes": "Dölj avatarändringar", + "Hide display name changes": "Dölj visningsnamnsändringar", + "Uploading %(filename)s and %(count)s others|other": "Laddar upp %(filename)s och %(count)s andra", + "Uploading %(filename)s and %(count)s others|zero": "Laddar upp %(filename)s", + "Uploading %(filename)s and %(count)s others|one": "Laddar upp %(filename)s och %(count)s annan", + "Light theme": "Ljust tema", + "Dark theme": "Mörkt tema", + "Status.im theme": "Status.im-tema", + "You already have existing direct chats with this user:": "Du har redan existerande direkt-chattar med den här användaren:", + "Start chatting": "Börja chatta", + "Click on the button below to start chatting!": "Klicka på knappen nedanför för att börja chatta!", + "Start Chatting": "Börja chatta", + "This doesn't appear to be a valid email address": "Det här verkar inte vara en giltig epostadress", + "Verification Pending": "Avvaktar verifiering", + "Unable to add email address": "Det gick inte att lägga till epostadress", + "Unable to verify email address.": "Det gick inte att verifiera epostadressen.", + "Skip": "Hoppa över", + "User names may only contain letters, numbers, dots, hyphens and underscores.": "Användarnamn får endast innehålla bokstäver, siffror, punkter, bindestreck och understreck.", + "Username not available": "Användarnamn inte tillgängligt", + "Username invalid: %(errMessage)s": "Ogiltigt användarnamn: %(errMessage)s", + "An error occurred: %(error_string)s": "Ett fel uppstod: %(error_string)s", + "Username available": "Användarnamn tillgängligt", + "To get started, please pick a username!": "För att komma igång, vänligen välj ett användarnamn!", + "This will be your account name on the homeserver, or you can pick a different server.": "Det här kommer bli ditt kontonamn på hemservern , eller så kan du välja en annan server.", + "If you already have a Matrix account you can log in instead.": "Om du redan har ett Matrix-konto kan du logga in istället.", + "Please install Chrome or Firefox for the best experience.": "Vänligen installera Chrome eller Firefox för den bästa upplevelsen.", + "Safari and Opera work too.": "Safari och Opera funkar också.", + "Topic": "Ämne", + "Make this room private": "Gör det här rummet privat", + "Share message history with new users": "Dela meddelandehistoriken med nya användare", + "Encrypt room": "Kryptera rum", + "You must register to use this functionality": "Du måste registrera dig för att använda den här funktionaliteten", + "You must join the room to see its files": "Du måste gå med i rummet för att se tillhörande filer", + "There are no visible files in this room": "Det finns inga synliga filer i det här rummet", + "Your password has been reset": "Ditt lösenord har återställts", + "To reset your password, enter the email address linked to your account": "För att återställa ditt lösenord, ange epostadressen som är kopplad till ditt konto", + "This Home Server does not support login using email address.": "Den här hemservern har inte support för inloggning med epostadress.", + "Desktop specific": "Skrivbordsspecifikt", + "Start automatically after system login": "Starta automatiskt vid systeminloggning", + "User Interface": "Användargränssnitt", + "This will allow you to reset your password and receive notifications.": "Det här låter dig återställa lösenordet och ta emot aviseringar.", + "You have no visible notifications": "Du har inga synliga aviseringar", + "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Ditt lösenord har ändrats. Du kommer inte att få push-aviseringar på andra enheter förrän du har loggat in på dem igen", + "Failed to upload image": "Det gick inte att ladda upp bild" } From 9e1172019182131ead40560015e06e30bf943072 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 12 May 2018 14:29:37 -0600 Subject: [PATCH 25/44] Add setting to enable widget screenshots (if widgets declare support) Fixes the remainder of https://github.com/vector-im/riot-web/issues/6708 Signed-off-by: Travis Ralston --- src/components/structures/UserSettings.js | 1 + src/components/views/elements/AppTile.js | 6 +++--- src/components/views/rooms/AppsDrawer.js | 3 +++ src/i18n/strings/en_EN.json | 1 + src/settings/Settings.js | 5 +++++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 3bef4e41bb..35a55284fd 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -80,6 +80,7 @@ const SIMPLE_SETTINGS = [ { id: "TextualBody.disableBigEmoji" }, { id: "VideoView.flipVideoHorizontally" }, { id: "TagPanel.disableTagPanel" }, + { id: "enableWidgetScreenshots" }, ]; // These settings must be defined in SettingsStore diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 38b6fc200b..2923d6dceb 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -85,7 +85,7 @@ export default class AppTile extends React.Component { /** * Does the widget support a given capability - * @param {[type]} capability Capability to check for + * @param {string} capability Capability to check for * @return {Boolean} True if capability supported */ _hasCapability(capability) { @@ -607,7 +607,7 @@ export default class AppTile extends React.Component { } // Picture snapshot - only show button when apps are maximised. - const showPictureSnapshotButton = this._hasCapability('screenshot') && this.props.show; + const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show; const showPictureSnapshotIcon = 'img/camera_green.svg'; const popoutWidgetIcon = 'img/button-new-window.svg'; const windowStateIcon = (this.props.show ? 'img/minimize.svg' : 'img/maximize.svg'); @@ -711,7 +711,7 @@ AppTile.propTypes = { showDelete: PropTypes.bool, // Optionally hide the popout widget icon showPopout: PropTypes.bool, - // Widget apabilities to allow by default (without user confirmation) + // Widget capabilities to allow by default (without user confirmation) // NOTE -- Use with caution. This is intended to aid better integration / UX // basic widget capabilities, e.g. injecting sticker message events. whitelistCapabilities: PropTypes.array, diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js index 9f57ca51e9..8763ea3d7f 100644 --- a/src/components/views/rooms/AppsDrawer.js +++ b/src/components/views/rooms/AppsDrawer.js @@ -227,6 +227,8 @@ module.exports = React.createClass({ }, render: function() { + const enableScreenshots = SettingsStore.getValue("enableWidgetScreenshots", this.props.room.room_id); + const apps = this.state.apps.map( (app, index, arr) => { return (); }); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4adca0cc72..9b932ef2b6 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -217,6 +217,7 @@ "Enable URL previews for this room (only affects you)": "Enable URL previews for this room (only affects you)", "Enable URL previews by default for participants in this room": "Enable URL previews by default for participants in this room", "Room Colour": "Room Colour", + "Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", "Uploading report": "Uploading report", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 89a12580d6..663318f990 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -265,4 +265,9 @@ export const SETTINGS = { default: true, controller: new AudioNotificationsEnabledController(), }, + "enableWidgetScreenshots": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Enable widget screenshots on supported widgets'), + default: false, + }, }; From 0522ab8fcd2d5e91f91fd698a023d399189d6d3d Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 12 May 2018 13:18:43 -0600 Subject: [PATCH 26/44] Expose the requestId fully in the toWidget postMessage API This field is flagged as required in the proposal. Addresses part of https://github.com/vector-im/riot-web/issues/6708 Signed-off-by: Travis Ralston --- src/ToWidgetPostMessageApi.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ToWidgetPostMessageApi.js b/src/ToWidgetPostMessageApi.js index ccaa0207c1..def4af56ae 100644 --- a/src/ToWidgetPostMessageApi.js +++ b/src/ToWidgetPostMessageApi.js @@ -51,11 +51,11 @@ export default class ToWidgetPostMessageApi { if (payload.response === undefined) { return; } - const promise = this._requestMap[payload._id]; + const promise = this._requestMap[payload.requestId]; if (!promise) { return; } - delete this._requestMap[payload._id]; + delete this._requestMap[payload.requestId]; promise.resolve(payload); } @@ -64,21 +64,21 @@ export default class ToWidgetPostMessageApi { targetWindow = targetWindow || window.parent; // default to parent window targetOrigin = targetOrigin || "*"; this._counter += 1; - action._id = Date.now() + "-" + Math.random().toString(36) + "-" + this._counter; + action.requestId = Date.now() + "-" + Math.random().toString(36) + "-" + this._counter; return new Promise((resolve, reject) => { - this._requestMap[action._id] = {resolve, reject}; + this._requestMap[action.requestId] = {resolve, reject}; targetWindow.postMessage(action, targetOrigin); if (this._timeoutMs > 0) { setTimeout(() => { - if (!this._requestMap[action._id]) { + if (!this._requestMap[action.requestId]) { return; } console.error("postMessage request timed out. Sent object: " + JSON.stringify(action), this._requestMap); - this._requestMap[action._id].reject(new Error("Timed out")); - delete this._requestMap[action._id]; + this._requestMap[action.requestId].reject(new Error("Timed out")); + delete this._requestMap[action.requestId]; }, this._timeoutMs); } }); From 1515ca11a8be49e9a000afcc1c94e778faae57b5 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 12 May 2018 13:21:27 -0600 Subject: [PATCH 27/44] Add a warning for widget developers when their postMessage is missing a requestId Signed-off-by: Travis Ralston --- src/FromWidgetPostMessageApi.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/FromWidgetPostMessageApi.js b/src/FromWidgetPostMessageApi.js index 13ffb4a74b..792fd73733 100644 --- a/src/FromWidgetPostMessageApi.js +++ b/src/FromWidgetPostMessageApi.js @@ -116,6 +116,12 @@ export default class FromWidgetPostMessageApi { return; // don't log this - debugging APIs like to spam postMessage which floods the log otherwise } + // Although the requestId is required, we don't use it. We'll be nice and process the message + // if the property is missing, but with a warning for widget developers. + if (!event.data.requestId) { + console.warn("fromWidget action '" + event.data.action + "' does not have a requestId"); + } + const action = event.data.action; const widgetId = event.data.widgetId; if (action === 'content_loaded') { From 98da8b35755e2bf00115f3b194de803808795746 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 12 May 2018 13:49:43 -0600 Subject: [PATCH 28/44] Send the widgetId as part of all toWidget requests Addresses part of https://github.com/vector-im/riot-web/issues/6708 Signed-off-by: Travis Ralston --- src/WidgetMessaging.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index 86eaa0b59b..5b722df65f 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -44,6 +44,8 @@ export default class WidgetMessaging { } messageToWidget(action) { + action.widgetId = this.widgetId; // Required to be sent for all outbound requests + return this.toWidget.exec(action, this.target).then((data) => { // Check for errors and reject if found if (data.response === undefined) { // null is valid From 210fcf0d52219f767896f242783becaffab9f329 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sun, 13 May 2018 16:41:19 -0600 Subject: [PATCH 29/44] Correctly identify sticker picker widgets Widgets added to account data have the `type` of "m.widget", meaning we have to look at the `content.type` which will tell us what it is. This also fixes a bug where all user widgets become sticker picker widgets under the right conditions. Signed-off-by: Travis Ralston --- src/utils/widgets.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/utils/widgets.js b/src/utils/widgets.js index 0d7f5dbf3f..338df184e2 100644 --- a/src/utils/widgets.js +++ b/src/utils/widgets.js @@ -58,8 +58,7 @@ function getUserWidgetsArray() { */ function getStickerpickerWidgets() { const widgets = getUserWidgetsArray(); - const stickerpickerWidgets = widgets.filter((widget) => widget.type='m.stickerpicker'); - return stickerpickerWidgets; + return widgets.filter((widget) => widget.content && widget.content.type === "m.stickerpicker"); } /** @@ -73,7 +72,7 @@ function removeStickerpickerWidgets() { } const userWidgets = client.getAccountData('m.widgets').getContent() || {}; Object.entries(userWidgets).forEach(([key, widget]) => { - if (widget.type === 'm.stickerpicker') { + if (widget.content && widget.content.type === 'm.stickerpicker') { delete userWidgets[key]; } }); From cd034d3c2acc401947cc9f1b55ef275ba2e39531 Mon Sep 17 00:00:00 2001 From: RainSlide Date: Sun, 13 May 2018 12:58:50 +0000 Subject: [PATCH 30/44] Translated using Weblate (Chinese (Simplified)) Currently translated at 97.7% (1148 of 1174 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hans/ --- src/i18n/strings/zh_Hans.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/zh_Hans.json b/src/i18n/strings/zh_Hans.json index 2bbb5b1cc8..91d80993e4 100644 --- a/src/i18n/strings/zh_Hans.json +++ b/src/i18n/strings/zh_Hans.json @@ -358,7 +358,7 @@ "Device Name": "设备名称", "Device key": "设备密钥", "Verify device": "验证设备", - "I verify that the keys match": "我验证密钥匹配", + "I verify that the keys match": "我验证此密钥匹配", "Unable to restore session": "无法恢复会话", "Continue anyway": "无论如何都继续", "Blacklist": "列入黑名单", @@ -409,7 +409,7 @@ "Remove Contact Information?": "移除联系人信息?", "Remove %(threePid)s?": "移除 %(threePid)s?", "Results from DuckDuckGo": "来自 DuckDuckGo 的结果", - "Room contains unknown devices": "聊天室有未知设备", + "Room contains unknown devices": "聊天室包含未知设备", "%(roomName)s does not exist.": "%(roomName)s 不存在。", "Save": "保存", "Send anyway": "无论任何都发送", From d5d653e37515f65ffebbfb091fea76505da4c5ca Mon Sep 17 00:00:00 2001 From: Sven Thomsen Date: Tue, 8 May 2018 20:59:27 +0000 Subject: [PATCH 31/44] Translated using Weblate (German) Currently translated at 100.0% (1175 of 1175 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index 21d40dd86d..4464940c69 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -1176,5 +1176,6 @@ "We encountered an error trying to restore your previous session.": "Wir haben ein Problem beim Wiederherstellen deiner vorherigen Sitzung festgestellt.", "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Den Browser-Speicher zu löschen kann das Problem lösen, wird dich aber abmelden und verschlüsselte Chats unlesbar machen.", "Collapse Reply Thread": "Antwort-Thread zusammenklappen", - "At this time it is not possible to reply with an emote.": "An dieser Stelle ist es nicht möglich mit einer Umschreibung zu antworten." + "At this time it is not possible to reply with an emote.": "An dieser Stelle ist es nicht möglich mit einer Umschreibung zu antworten.", + "Enable widget screenshots on supported widgets": "Widget-Screenshots bei unterstützten Widgets aktivieren" } From 9cc89054438d8c25f43f2224843ad24c1707456b Mon Sep 17 00:00:00 2001 From: Szimszon Date: Mon, 7 May 2018 12:21:26 +0000 Subject: [PATCH 32/44] Translated using Weblate (Hungarian) Currently translated at 100.0% (1175 of 1175 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 c2b8af12ee..b7d0561c34 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1176,5 +1176,6 @@ "Unable to reply": "Nem lehet válaszolni", "At this time it is not possible to reply with an emote.": "Jelenleg nem lehet emodzsival válaszolni.", "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Nem lehet betölteni azt az eseményt amire válaszoltál, mert vagy nem létezik, vagy nincs jogod megnézni.", - "Collapse Reply Thread": "Beszélgetés szál becsukása" + "Collapse Reply Thread": "Beszélgetés szál becsukása", + "Enable widget screenshots on supported widgets": "Ahol az a kisalkalmazásban támogatott ott képernyőkép készítés engedélyezése" } From 98c06315cf44121779125a98f7025436c72f11af Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 14 May 2018 11:14:49 +0100 Subject: [PATCH 33/44] Update widget state when account data changes --- src/components/views/rooms/Stickerpicker.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 40ce6e6b39..51d4816e59 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -34,6 +34,7 @@ export default class Stickerpicker extends React.Component { this._onHideStickersClick = this._onHideStickersClick.bind(this); this._launchManageIntegrations = this._launchManageIntegrations.bind(this); this._removeStickerpickerWidgets = this._removeStickerpickerWidgets.bind(this); + this._updateWidget = this._updateWidget.bind(this); this._onWidgetAction = this._onWidgetAction.bind(this); this._onResize = this._onResize.bind(this); this._onFinished = this._onFinished.bind(this); @@ -90,11 +91,12 @@ export default class Stickerpicker extends React.Component { if (!this.state.imError) { this.dispatcherRef = dis.register(this._onWidgetAction); } - const stickerpickerWidget = Widgets.getStickerpickerWidgets()[0]; - this.setState({ - stickerpickerWidget, - widgetId: stickerpickerWidget ? stickerpickerWidget.id : null, - }); + + // Track updates to widget state in account data + MatrixClientPeg.get().on('accountData', this._updateWidget); + + // Initialise widget state from current account data + this._updateWidget(); } componentWillUnmount() { @@ -116,6 +118,14 @@ export default class Stickerpicker extends React.Component { }); } + _updateWidget() { + const stickerpickerWidget = Widgets.getStickerpickerWidgets()[0]; + this.setState({ + stickerpickerWidget, + widgetId: stickerpickerWidget ? stickerpickerWidget.id : null, + }); + } + _onWidgetAction(payload) { if (payload.action === "user_widget_updated") { this.forceUpdate(); From cc16961b438f2267a59dc28598a657530ef7c7b9 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 14 May 2018 09:34:31 +0000 Subject: [PATCH 34/44] Translated using Weblate (Russian) Currently translated at 99.8% (1173 of 1175 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/ru/ --- src/i18n/strings/ru.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 2e6bdf45f0..f766069b16 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -1173,5 +1173,7 @@ "We encountered an error trying to restore your previous session.": "Произошла ошибка при попытке восстановить предыдущий сеанс.", "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Очистка хранилища вашего браузера может устранить проблему, но при этом ваша сессия будет завершена и зашифрованная история чата станет нечитаемой.", "Unable to reply": "Не удается ответить", - "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Не удается загрузить событие, на которое был дан ответ, либо оно не существует, либо у вас нет разрешения на его просмотр." + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Не удается загрузить событие, на которое был дан ответ, либо оно не существует, либо у вас нет разрешения на его просмотр.", + "Enable widget screenshots on supported widgets": "Включить скриншоты виджета в поддерживаемых виджетах", + "Collapse Reply Thread": "Ответить с цитированием" } From 6345e474f5fea44a5246a264c09a4c6322aabe56 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 14 May 2018 11:38:17 +0100 Subject: [PATCH 35/44] Remove unused conditional --- src/components/views/elements/AppTile.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index cd0eb1ce68..cdd77227dc 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -359,9 +359,6 @@ export default class AppTile extends React.Component { if (!this.widgetMessaging) { this._onInitialLoad(); } - if (this._exposeWidgetMessaging) { - this._exposeWidgetMessaging(this.widgetMessaging); - } } /** From cf8077e60577d766bd93a7f659a09c6d3ab091f9 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 14 May 2018 11:42:38 +0100 Subject: [PATCH 36/44] Set loading: false when iFrame finishes loading --- src/components/views/elements/AppTile.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index cdd77227dc..55e2b93920 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -359,6 +359,7 @@ export default class AppTile extends React.Component { if (!this.widgetMessaging) { this._onInitialLoad(); } + this.setState({loading: false}); } /** @@ -396,8 +397,6 @@ export default class AppTile extends React.Component { }).catch((err) => { console.log(`Failed to get capabilities for widget type ${this.props.type}`, this.props.id, err); }); - - this.setState({loading: false}); } _onWidgetAction(payload) { From f384c465fd402a6c750aebee625396238364848e Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Thu, 3 May 2018 23:55:48 +0000 Subject: [PATCH 37/44] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1175 of 1175 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 6f5ef68735..3e8123dd78 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1176,5 +1176,6 @@ "Refresh": "重新整理", "We encountered an error trying to restore your previous session.": "我們在嘗試復原您先前的工作階段時遇到了一點錯誤。", "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "清除您瀏覽器的儲存的東西也許可以修復問題,但會將您登出並造成任何已加密的聊天都無法讀取。", - "Collapse Reply Thread": "摺疊回覆討論串" + "Collapse Reply Thread": "摺疊回覆討論串", + "Enable widget screenshots on supported widgets": "在支援的小工具上啟用小工具螢幕快照" } From b6e317647a847041c216bfaf3fc88b82c3b64442 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 14 May 2018 13:41:41 +0100 Subject: [PATCH 38/44] Fix stickers briefly being 2x the size fixupHeight was the only thing actually fixing the size of the sticker image to be the size we want it rather than the pixel size of the image, and this was only getting run after the image loaded, causing a flash of 2x image. --- src/components/views/messages/MStickerBody.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/components/views/messages/MStickerBody.js b/src/components/views/messages/MStickerBody.js index 501db5e22b..3a412fc2e2 100644 --- a/src/components/views/messages/MStickerBody.js +++ b/src/components/views/messages/MStickerBody.js @@ -107,6 +107,16 @@ export default class MStickerBody extends MImageBody { placeholderFixupHeight = content.info.h + 'px'; } + // The pixel size of sticker images is generally larger than their intended display + // size so they render at native reolution on HiDPI displays. We therefore need to + // explicity set the size so they render at the intended size. + // XXX: This will be clobberred when we run fixupHeight(), but we need to do it + // here otherwise the stickers are momentarily displayed at the pixel size. + const imageStyle = { + height: content.info.h, + // leave the browser the calculate the width automatically + }; + placeholderSize = placeholderSize + 'px'; // Body 'ref' required by MImageBody @@ -132,6 +142,7 @@ export default class MStickerBody extends MImageBody { {content.body} Date: Mon, 14 May 2018 13:56:39 +0100 Subject: [PATCH 39/44] Remove redundant logging (currently shown on every render when no stickerpicker is present). --- src/components/views/rooms/Stickerpicker.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 0584cd6b0a..1bb972f67f 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -223,7 +223,6 @@ export default class Stickerpicker extends React.Component { ); } else { // Default content to show if stickerpicker widget not added - console.warn("No available sticker picker widgets"); stickersContent = this._defaultStickerpickerContent(); } return stickersContent; From dddd1c43cc6648846934d316ad38762bacf3a83e Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Mon, 14 May 2018 14:23:26 +0100 Subject: [PATCH 40/44] Remove redundant logging (currently shown on every render when no stickerpicker is present). --- src/components/views/rooms/Stickerpicker.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 51d4816e59..2a523e5e82 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -232,7 +232,6 @@ export default class Stickerpicker extends React.Component { ); } else { // Default content to show if stickerpicker widget not added - console.warn("No available sticker picker widgets"); stickersContent = this._defaultStickerpickerContent(); } return stickersContent; From 3761cd405446891d4c5d0b7319fb163cbe469fcc Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 14 May 2018 16:35:12 +0100 Subject: [PATCH 41/44] When panels are shown/hidden, hide sticker picker --- src/components/views/rooms/Stickerpicker.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 2a523e5e82..1ea5639688 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -127,10 +127,19 @@ export default class Stickerpicker extends React.Component { } _onWidgetAction(payload) { - if (payload.action === "user_widget_updated") { - this.forceUpdate(); - } else if (payload.action === "stickerpicker_close") { - this.setState({showStickers: false}); + switch (payload.action) { + case "user_widget_updated": + this.forceUpdate(); + break; + case "stickerpicker_close": + this.setState({showStickers: false}); + break; + case "show_right_panel": + case "hide_right_panel": + case "show_left_panel": + case "hide_left_panel": + this.setState({showStickers: false}); + break; } } From 0591963cc1d8920b868ef0af37ddfb5e7c5871d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Wed, 2 May 2018 20:08:49 +0000 Subject: [PATCH 42/44] Translated using Weblate (French) Currently translated at 100.0% (1175 of 1175 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 9c0f3f98e8..4ff8900965 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1176,5 +1176,6 @@ "Unable to reply": "Impossible de répondre", "At this time it is not possible to reply with an emote.": "Pour le moment il n'est pas possible de répondre avec un émoji.", "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Impossible de charger l'événement auquel il a été répondu, soit il n'existe pas, soit vous n'avez pas l'autorisation de le voir.", - "Collapse Reply Thread": "Dévoiler le fil de réponse" + "Collapse Reply Thread": "Dévoiler le fil de réponse", + "Enable widget screenshots on supported widgets": "Activer les captures d'écran des widgets pris en charge" } From e0236c3d3e4f832ab3b1adbc23c15ef64eab7dfa Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 14 May 2018 17:05:23 +0100 Subject: [PATCH 43/44] Fix issue with sticker picker rendering off-screen when the RightPanel is collapsed on a small monitor and the sticker picker is opened. --- src/components/views/rooms/Stickerpicker.js | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 1ea5639688..8f9e96dd3b 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -252,16 +252,33 @@ export default class Stickerpicker extends React.Component { * @param {Event} e Event that triggered the function */ _onShowStickersClick(e) { + // XXX: Simplify by using a context menu that is positioned relative to the sticker picker button + const buttonRect = e.target.getBoundingClientRect(); // The window X and Y offsets are to adjust position when zoomed in to page - const x = buttonRect.right + window.pageXOffset - 42; + let x = buttonRect.right + window.pageXOffset - 41; + + // Amount of horizontal space between the right of menu and the right of the viewport + // (10 = amount needed to make chevron centrally aligned) + const rightPad = 10; + + // When the sticker picker would be displayed off of the viewport, adjust x + // (302 = width of context menu, including borders) + x = Math.min(x, document.body.clientWidth - (302 + rightPad)); + + // Offset the chevron location, which is relative to the left of the context menu + // (10 = offset when context menu would not be displayed off viewport) + // (8 = value required in practice (possibly 10 - 2 where the 2 = context menu borders) + const stickerPickerChevronOffset = Math.max(10, 8 + window.pageXOffset + buttonRect.left - x); + const y = (buttonRect.top + (buttonRect.height / 2) + window.pageYOffset) - 19; this.setState({ showStickers: true, stickerPickerX: x, stickerPickerY: y, + stickerPickerChevronOffset, }); } @@ -314,7 +331,7 @@ export default class Stickerpicker extends React.Component { const stickerPicker = Date: Mon, 14 May 2018 14:57:30 +0000 Subject: [PATCH 44/44] Translated using Weblate (Bulgarian) Currently translated at 99.1% (1165 of 1175 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index dc48b0ba59..2a2b90f59f 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -62,9 +62,9 @@ "Whether or not you're logged in (we don't record your user name)": "Независимо дали сте влезли с профила си или не (не записваме Вашето потребителско име)", "Your language of choice": "Вашият език по избор", "Which officially provided instance you are using, if any": "Кой официално-предоставен сървър използвате, ако има такъв", - "Whether or not you're using the Richtext mode of the Rich Text Editor": "Независимо дали използвате Richtext режим на Rich Text Editor", - "Your homeserver's URL": "Адрес на Вашия Home сървър", - "Your identity server's URL": "Адрес на Вашия сървър за самоличност", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "Дали използвате Richtext режим на Rich Text Editor", + "Your homeserver's URL": "Адресът на Вашия Home сървър", + "Your identity server's URL": "Адресът на Вашия сървър за самоличност", "Analytics": "Статистика", "The information being sent to us to help make Riot.im better includes:": "За да направим Riot по-добър, информацията изпратена до нас включва:", "Call Failed": "Неуспешно повикване", @@ -796,7 +796,7 @@ "%(count)s new messages|one": "%(count)s ново съобщение", "Active call": "Активен разговор", "Use with caution": "Внимавайте при използване", - "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Няма никой друг тук! Желаете ли да поканите други или да изключите предупреждението, че стаята е празна?", + "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Няма никой друг тук! Поканете други или изключете предупреждението, че стаята е празна?", "You seem to be uploading files, are you sure you want to quit?": "Изглежда, че качвате файлове. Сигурни ли сте, че искате да затворите програмата?", "You seem to be in a call, are you sure you want to quit?": "Изглежда, че сте в разговор. Сигурни ли сте, че искате да излезете от програмата?", "Failed to upload file": "Неуспешно качване на файлове", @@ -1158,5 +1158,14 @@ "Checking for an update...": "Проверяване за нова версия...", "There are advanced notifications which are not shown here": "Съществуват разширени настройки за известия, които не са показани тук", "Missing roomId.": "Липсва идентификатор на стая.", - "Picture": "Изображение" + "Picture": "Изображение", + "Every page you use in the app": "Всяка използвана страница от приложението", + "e.g. ": "например: ", + "Your User Agent": "Вашият браузър", + "Your device resolution": "Разделителната способност на устройството Ви", + "Always show encryption icons": "Винаги показвай икони за шифроване", + "At this time it is not possible to reply with a file so this will be sent without being a reply.": "В момента не може да се отговаря с файл, така че това ще се изпрати без да бъде отговор.", + "Unable to reply": "Не може да се отговори", + "At this time it is not possible to reply with an emote.": "В момента не може да се отговори с емотикона.", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Не може да се зареди събитието, на което е отговорено. Или не съществува или нямате достъп да го видите." }