From aab738d07619900482e1065c2f23d04bb24f69a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Fri, 18 Jan 2019 21:09:17 +0100 Subject: [PATCH 01/18] Added requested feature When a chat is archived the selection is switched to the next one. Also added some fixes using `elementReady()` since some elements are requested before page is loaded. --- browser.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/browser.js b/browser.js index 13e7ca458..5e856235d 100644 --- a/browser.js +++ b/browser.js @@ -98,7 +98,9 @@ ipc.on('delete-conversation', () => { }); ipc.on('archive-conversation', () => { + const index = getNextIndex(true); openArchiveModal(); + jumpToConversation(index); }); function setSidebarVisibility() { @@ -256,8 +258,8 @@ function jumpToConversation(key) { } // Focus on the conversation with the given index -function selectConversation(index) { - document.querySelector(listSelector).children[index].firstChild.firstChild.click(); +async function selectConversation(index) { + (await elementReady(listSelector)).children[index].firstChild.firstChild.click(); } // Returns the index of the selected conversation. @@ -332,7 +334,7 @@ function openDeleteModal() { async function openPreferences() { // Create the menu for the below - (await elementReady('._30yy._2fug._p')).click(); + showSettingsMenu(); selectMenuItem(1); } @@ -347,7 +349,7 @@ function closePreferences() { } async function sendConversationList() { const conversations = await Promise.all( - [...document.querySelector(listSelector).children] + [...(await elementReady(listSelector)).children] .splice(0, 10) .map(async el => { const profilePic = el.querySelector('._55lt img'); From d41973a7da2705ea6525f29a32184f84e4f3ad26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Fri, 18 Jan 2019 21:27:39 +0100 Subject: [PATCH 02/18] Fixed #590 Also fixed leaving group conversations issue. --- browser.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/browser.js b/browser.js index 5e856235d..715489604 100644 --- a/browser.js +++ b/browser.js @@ -321,7 +321,11 @@ function openArchiveModal() { return; } - selectMenuItem(3); + // Check if selected conversation is a group + // In case it is we need to click on 4th element of conversation menu, otherwise 3rd + const isGroup = document.querySelector('._54nq._2i-c._150g._558b._2n_z li:nth-child(3) a span span').innerHTML === 'Leave Group'; + + selectMenuItem(isGroup ? 4 : 3); } function openDeleteModal() { From 9ce7550f6eb78fddb256e258d179fc4aacc538f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Fri, 18 Jan 2019 23:05:25 +0100 Subject: [PATCH 03/18] Turned required non-async functions to async Non-async functions that call async functions are now turned to async. --- browser.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/browser.js b/browser.js index 715489604..d3749b5f6 100644 --- a/browser.js +++ b/browser.js @@ -97,10 +97,10 @@ ipc.on('delete-conversation', () => { openDeleteModal(); }); -ipc.on('archive-conversation', () => { +ipc.on('archive-conversation', async () => { const index = getNextIndex(true); openArchiveModal(); - jumpToConversation(index); + await jumpToConversation(index); }); function setSidebarVisibility() { @@ -238,23 +238,23 @@ ipc.on('zoom-out', () => { } }); -ipc.on('jump-to-conversation', (event, index) => { - jumpToConversation(index); +ipc.on('jump-to-conversation', async (event, index) => { + await jumpToConversation(index); }); -function nextConversation() { +async function nextConversation() { const index = getNextIndex(true); - selectConversation(index); + await selectConversation(index); } -function previousConversation() { +async function previousConversation() { const index = getNextIndex(false); - selectConversation(index); + await selectConversation(index); } -function jumpToConversation(key) { +async function jumpToConversation(key) { const index = key - 1; - selectConversation(index); + await selectConversation(index); } // Focus on the conversation with the given index @@ -499,7 +499,7 @@ window.addEventListener('load', () => { // It's not possible to add multiple accelerators // so this needs to be done the old-school way -document.addEventListener('keydown', event => { +document.addEventListener('keydown', async event => { // The `!event.altKey` part is a workaround for https://github.com/electron/electron/issues/13895 const combineKey = is.macos ? event.metaKey : (event.ctrlKey && !event.altKey); @@ -508,17 +508,17 @@ document.addEventListener('keydown', event => { } if (event.key === ']') { - nextConversation(); + await nextConversation(); } if (event.key === '[') { - previousConversation(); + await previousConversation(); } const num = parseInt(event.code.slice(-1), 10); if (num >= 1 && num <= 9) { - jumpToConversation(num); + await jumpToConversation(num); } }); From 5636e7fe6227e3646e1a5d48688c7bf76b789d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Fri, 18 Jan 2019 23:18:39 +0100 Subject: [PATCH 04/18] Fixed checking chat type over menu Fixed that check for chat type via chat options menu. Also explained the process in the comment. --- browser.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/browser.js b/browser.js index d3749b5f6..a5c4f78a5 100644 --- a/browser.js +++ b/browser.js @@ -322,8 +322,10 @@ function openArchiveModal() { } // Check if selected conversation is a group + // We are checking the type of fifth element in the menu + // If it's a separator its private chat and if it's a button it's group chat // In case it is we need to click on 4th element of conversation menu, otherwise 3rd - const isGroup = document.querySelector('._54nq._2i-c._150g._558b._2n_z li:nth-child(3) a span span').innerHTML === 'Leave Group'; + const isGroup = Boolean(document.querySelector('._54nq._2i-c._150g._558b._2n_z li:nth-child(5)[role=presentation]')); selectMenuItem(isGroup ? 4 : 3); } From 985a945c9c59fcad9aabf7a749ef940e2364fa64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Fri, 18 Jan 2019 23:21:54 +0100 Subject: [PATCH 05/18] Reverted to elementReady in openPreferences Reverting to use of elementReady for getting element. --- browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser.js b/browser.js index a5c4f78a5..6ba4fdf3d 100644 --- a/browser.js +++ b/browser.js @@ -340,7 +340,7 @@ function openDeleteModal() { async function openPreferences() { // Create the menu for the below - showSettingsMenu(); + (await elementReady('._30yy._2fug._p')).click(); selectMenuItem(1); } From ea4336bf54cba3272b607747ed97f05682282e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Sat, 19 Jan 2019 03:13:04 +0100 Subject: [PATCH 06/18] Made showSettingsMenu function async showSettingsMenu is used in a cuple of places and in one place it needs to wait for element to be created to show the menu. In that place so far we've been using a custom function elementReady instead of document.querySelector. Now showSettingsMenu is made async so it can now use elementReady. --- browser.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/browser.js b/browser.js index 6ba4fdf3d..8cbb9378c 100644 --- a/browser.js +++ b/browser.js @@ -11,8 +11,8 @@ const conversationSelector = '._4u-c._1wfr > ._5f0v.uiScrollableArea'; const selectedConversationSelector = '._5l-3._1ht1._1ht2'; const preferencesSelector = '._10._4ebx.uiLayer._4-hy'; -function showSettingsMenu() { - document.querySelector('._30yy._2fug._p').click(); +async function showSettingsMenu() { + (await elementReady('._30yy._2fug._p')).click(); } function selectMenuItem(itemNumber) { @@ -20,12 +20,12 @@ function selectMenuItem(itemNumber) { selector.click(); } -function selectOtherListViews(itemNumber) { +async function selectOtherListViews(itemNumber) { // In case one of other views is shown clickBackButton(); // Create the menu for the below - showSettingsMenu(); + await showSettingsMenu(); selectMenuItem(itemNumber); } @@ -49,7 +49,7 @@ ipc.on('new-conversation', () => { document.querySelector('._30yy[data-href$=\'/new\']').click(); }); -ipc.on('log-out', () => { +ipc.on('log-out', async () => { if (config.get('useWorkChat')) { // Create the menu for the below document.querySelector('._5lxs._3qct._p').click(); @@ -59,7 +59,7 @@ ipc.on('log-out', () => { nodes[nodes.length - 1].click(); }, 250); } else { - showSettingsMenu(); + await showSettingsMenu(); const nodes = document.querySelectorAll('._54nq._2i-c._558b._2n_z li:last-child a'); nodes[nodes.length - 1].click(); } @@ -340,7 +340,7 @@ function openDeleteModal() { async function openPreferences() { // Create the menu for the below - (await elementReady('._30yy._2fug._p')).click(); + await showSettingsMenu(); selectMenuItem(1); } From 9eff9b222e0f4f31507bbf4fdf90c76534038643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Sat, 19 Jan 2019 04:16:55 +0100 Subject: [PATCH 07/18] Work around for settings menu always visible Here's a work around. It's ugly, it's not foolproof but it works. --- browser.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/browser.js b/browser.js index 8cbb9378c..4ed32cfe8 100644 --- a/browser.js +++ b/browser.js @@ -16,8 +16,9 @@ async function showSettingsMenu() { } function selectMenuItem(itemNumber) { - const selector = document.querySelector(`._54nq._2i-c._558b._2n_z li:nth-child(${itemNumber}) a`); - selector.click(); + // Work around for settings menu element always existing + const selector = document.querySelectorAll(`._54nq._2i-c._558b._2n_z li:nth-child(${itemNumber}) a`); + selector[selector.length - 1].click(); } async function selectOtherListViews(itemNumber) { @@ -322,10 +323,13 @@ function openArchiveModal() { } // Check if selected conversation is a group - // We are checking the type of fifth element in the menu - // If it's a separator its private chat and if it's a button it's group chat + // We are checking the type of fifth element in the menu and getting list of all menus + // If it's a separator on the fifth element it's private chat and if it's a button it's group chat + // The comparison of menu list lengths is a work around for 'settings menu always exists' issue // In case it is we need to click on 4th element of conversation menu, otherwise 3rd - const isGroup = Boolean(document.querySelector('._54nq._2i-c._150g._558b._2n_z li:nth-child(5)[role=presentation]')); + const firstElements = document.querySelectorAll('._54nq._2i-c._150g._558b._2n_z li:first-child'); + const fifthElements = document.querySelectorAll('._54nq._2i-c._150g._558b._2n_z li:nth-child(5)[role=presentation]'); + const isGroup = Boolean(firstElements.length === fifthElements.length); selectMenuItem(isGroup ? 4 : 3); } From ad5c13aa2f0d899d8e4466fc8ede495ea44393e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Sat, 19 Jan 2019 15:57:45 +0100 Subject: [PATCH 08/18] Merged with archive-fix and new openArvhiceModal Merged the branch with CvX's arvhice-fix branch that contains new mechanism for querying menus and clicking on menu items. Also used that new mechanism for openArchiveModal function. Great work by @CvX. --- browser.css | 12 +++--- browser.js | 105 +++++++++++++++++++++++++++++++--------------------- 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/browser.css b/browser.css index 4c5a66992..5856733bb 100644 --- a/browser.css +++ b/browser.css @@ -70,6 +70,11 @@ html.sidebar-hidden ._1enh { display: none; } +/* A utility class for temporarily hiding all dropdown menus */ +html.hide-dropdowns .uiContextualLayerPositioner { + visibility: hidden !important; +} + /* Hide footer at login view */ ._210n { display: none; @@ -90,14 +95,9 @@ html.sidebar-hidden ._1enh { border-left: 1px solid rgba(0, 0, 0, 0.1) !important; } -/* Hide settings menu */ -.uiContextualLayerBelowLeft ._5v-0._53il { - display: none !important; -} - /* Hide settings icon */ ._30yy._2fug._p { - display: none !important; + visibility: hidden !important; } /* Hide title */ diff --git a/browser.js b/browser.js index 4ed32cfe8..8811cb6c3 100644 --- a/browser.js +++ b/browser.js @@ -11,24 +11,40 @@ const conversationSelector = '._4u-c._1wfr > ._5f0v.uiScrollableArea'; const selectedConversationSelector = '._5l-3._1ht1._1ht2'; const preferencesSelector = '._10._4ebx.uiLayer._4-hy'; -async function showSettingsMenu() { +async function withSettingsMenu(callback) { + const {classList} = document.documentElement; + + // Prevent the dropdown menu from displaying + classList.add('hide-dropdowns'); + + // Click the Settings icon (await elementReady('._30yy._2fug._p')).click(); + + // Wait for the menu to close before removing the 'hide-dropdowns' class + const menuLayer = document.querySelector('.uiContextualLayerPositioner:not(.hidden_elem)'); + const observer = new MutationObserver(() => { + if (menuLayer.classList.contains('hidden_elem')) { + classList.remove('hide-dropdowns'); + observer.disconnect(); + } + }); + observer.observe(menuLayer, {attributes: true, attributeFilter: ['class']}); + + await callback(); } function selectMenuItem(itemNumber) { - // Work around for settings menu element always existing - const selector = document.querySelectorAll(`._54nq._2i-c._558b._2n_z li:nth-child(${itemNumber}) a`); - selector[selector.length - 1].click(); + const selector = document.querySelector(`.uiLayer:not(.hidden_elem) ._54nq._2i-c._558b._2n_z li:nth-child(${itemNumber}) a`); + selector.click(); } async function selectOtherListViews(itemNumber) { // In case one of other views is shown clickBackButton(); - // Create the menu for the below - await showSettingsMenu(); - - selectMenuItem(itemNumber); + await withSettingsMenu(() => { + selectMenuItem(itemNumber); + }); } function clickBackButton() { @@ -60,9 +76,10 @@ ipc.on('log-out', async () => { nodes[nodes.length - 1].click(); }, 250); } else { - await showSettingsMenu(); - const nodes = document.querySelectorAll('._54nq._2i-c._558b._2n_z li:last-child a'); - nodes[nodes.length - 1].click(); + await withSettingsMenu(() => { + const nodes = document.querySelectorAll('._54nq._2i-c._558b._2n_z li:last-child a'); + nodes[nodes.length - 1].click(); + }); } }); @@ -296,57 +313,61 @@ function setZoom(zoomFactor) { config.set('zoomFactor', zoomFactor); } -function openConversationMenu() { +async function withConversationMenu(callback) { const index = getIndex(); if (index === null) { - return false; + return; } + const {classList} = document.documentElement; + + // Prevent the dropdown menu from displaying + classList.add('hide-dropdowns'); // Open and close the menu for the below const menu = document.querySelectorAll('._2j6._5l-3 ._3d85')[index].firstChild; menu.click(); - return true; + // Wait for the menu to close before removing the 'hide-dropdowns' class + const menuLayer = document.querySelector('.uiContextualLayerPositioner:not(.hidden_elem)'); + const observer = new MutationObserver(() => { + if (menuLayer.classList.contains('hidden_elem')) { + classList.remove('hide-dropdowns'); + observer.disconnect(); + } + }); + observer.observe(menuLayer, {attributes: true, attributeFilter: ['class']}); + + await callback(); } function openMuteModal() { - if (!openConversationMenu()) { - return; - } - - selectMenuItem(1); + withConversationMenu(() => { + selectMenuItem(1); + }); } function openArchiveModal() { - if (!openConversationMenu()) { - return; - } - - // Check if selected conversation is a group - // We are checking the type of fifth element in the menu and getting list of all menus - // If it's a separator on the fifth element it's private chat and if it's a button it's group chat - // The comparison of menu list lengths is a work around for 'settings menu always exists' issue - // In case it is we need to click on 4th element of conversation menu, otherwise 3rd - const firstElements = document.querySelectorAll('._54nq._2i-c._150g._558b._2n_z li:first-child'); - const fifthElements = document.querySelectorAll('._54nq._2i-c._150g._558b._2n_z li:nth-child(5)[role=presentation]'); - const isGroup = Boolean(firstElements.length === fifthElements.length); - - selectMenuItem(isGroup ? 4 : 3); + withConversationMenu(() => { + // Check if selected conversation is a group + // We are checking the type of fifth element in the menu + // If it's a separator its private chat and if it's a button it's group chat + // In case it is we need to click on 4th element of conversation menu, otherwise 3rd + const isGroup = Boolean(document.querySelector('.uiLayer:not(.hidden_elem) ._54nq._2i-c._558b._2n_z li:nth-child(5)[role=presentation]')); + + selectMenuItem(isGroup ? 4 : 3); + }); } function openDeleteModal() { - if (!openConversationMenu()) { - return; - } - - selectMenuItem(4); + withConversationMenu(() => { + selectMenuItem(4); + }); } async function openPreferences() { - // Create the menu for the below - await showSettingsMenu(); - - selectMenuItem(1); + await withSettingsMenu(() => { + selectMenuItem(1); + }); } function isPreferencesOpen() { From eba450469d95553523e6674b371b672ac945fc10 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 20:30:14 +0100 Subject: [PATCH 09/18] Extract a `withMenu` function. --- browser.js | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/browser.js b/browser.js index 8811cb6c3..09ecc62a4 100644 --- a/browser.js +++ b/browser.js @@ -11,14 +11,14 @@ const conversationSelector = '._4u-c._1wfr > ._5f0v.uiScrollableArea'; const selectedConversationSelector = '._5l-3._1ht1._1ht2'; const preferencesSelector = '._10._4ebx.uiLayer._4-hy'; -async function withSettingsMenu(callback) { +async function withMenu(menuButtonElement, callback) { const {classList} = document.documentElement; // Prevent the dropdown menu from displaying classList.add('hide-dropdowns'); - // Click the Settings icon - (await elementReady('._30yy._2fug._p')).click(); + // Click the menu button + menuButtonElement.click(); // Wait for the menu to close before removing the 'hide-dropdowns' class const menuLayer = document.querySelector('.uiContextualLayerPositioner:not(.hidden_elem)'); @@ -33,6 +33,10 @@ async function withSettingsMenu(callback) { await callback(); } +async function withSettingsMenu(callback) { + await withMenu(await elementReady('._30yy._2fug._p'), callback); +} + function selectMenuItem(itemNumber) { const selector = document.querySelector(`.uiLayer:not(.hidden_elem) ._54nq._2i-c._558b._2n_z li:nth-child(${itemNumber}) a`); selector.click(); @@ -318,26 +322,9 @@ async function withConversationMenu(callback) { if (index === null) { return; } - const {classList} = document.documentElement; - - // Prevent the dropdown menu from displaying - classList.add('hide-dropdowns'); - - // Open and close the menu for the below - const menu = document.querySelectorAll('._2j6._5l-3 ._3d85')[index].firstChild; - menu.click(); - - // Wait for the menu to close before removing the 'hide-dropdowns' class - const menuLayer = document.querySelector('.uiContextualLayerPositioner:not(.hidden_elem)'); - const observer = new MutationObserver(() => { - if (menuLayer.classList.contains('hidden_elem')) { - classList.remove('hide-dropdowns'); - observer.disconnect(); - } - }); - observer.observe(menuLayer, {attributes: true, attributeFilter: ['class']}); - await callback(); + const menuButton = document.querySelectorAll('._2j6._5l-3 ._3d85')[index].firstChild; + await withMenu(menuButton, callback); } function openMuteModal() { From 6d29c90ae73c14bee084ecbf2709cf1709252086 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 20:30:58 +0100 Subject: [PATCH 10/18] Simplify the `withConversationMenu` function. --- browser.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/browser.js b/browser.js index 09ecc62a4..e905ad105 100644 --- a/browser.js +++ b/browser.js @@ -318,13 +318,11 @@ function setZoom(zoomFactor) { } async function withConversationMenu(callback) { - const index = getIndex(); - if (index === null) { - return; - } + const menuButton = document.querySelector(`${selectedConversationSelector} ._5blh._4-0h`); - const menuButton = document.querySelectorAll('._2j6._5l-3 ._3d85')[index].firstChild; - await withMenu(menuButton, callback); + if (menuButton) { + await withMenu(menuButton, callback); + } } function openMuteModal() { From 32f0059ccb411bdd352ad1174714a0270980ecb2 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 20:34:13 +0100 Subject: [PATCH 11/18] Simplify the `openArchiveModal` function. --- browser.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/browser.js b/browser.js index e905ad105..89486a9a8 100644 --- a/browser.js +++ b/browser.js @@ -332,14 +332,11 @@ function openMuteModal() { } function openArchiveModal() { - withConversationMenu(() => { - // Check if selected conversation is a group - // We are checking the type of fifth element in the menu - // If it's a separator its private chat and if it's a button it's group chat - // In case it is we need to click on 4th element of conversation menu, otherwise 3rd - const isGroup = Boolean(document.querySelector('.uiLayer:not(.hidden_elem) ._54nq._2i-c._558b._2n_z li:nth-child(5)[role=presentation]')); + const groupConversationProfilePicture = document.querySelector(`${selectedConversationSelector} ._55lu`); + const isGroupConversation = Boolean(groupConversationProfilePicture); - selectMenuItem(isGroup ? 4 : 3); + withConversationMenu(() => { + selectMenuItem(isGroupConversation ? 4 : 3); }); } From 23ef5cd3361ae69d0d767584140801a835f7cadc Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 20:45:08 +0100 Subject: [PATCH 12/18] Remove an unused function `getIndex`. --- browser.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/browser.js b/browser.js index 89486a9a8..b9efa2913 100644 --- a/browser.js +++ b/browser.js @@ -284,19 +284,6 @@ async function selectConversation(index) { (await elementReady(listSelector)).children[index].firstChild.firstChild.click(); } -// Returns the index of the selected conversation. -// If no conversation is selected, returns null. -function getIndex() { - const selected = document.querySelector(selectedConversationSelector); - if (!selected) { - return null; - } - - const list = [...selected.parentNode.children]; - - return list.indexOf(selected); -} - // Return the index for next node if next is true, // else returns index for the previous node function getNextIndex(next) { @@ -360,6 +347,7 @@ function closePreferences() { const doneButton = document.querySelector('._3quh._30yy._2t_._5ixy'); doneButton.click(); } + async function sendConversationList() { const conversations = await Promise.all( [...(await elementReady(listSelector)).children] From 78c306bb318fe7bdd084abe24312321cc6995004 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 22:32:31 +0100 Subject: [PATCH 13/18] Rename `openArchiveModal` to `archiveSelectedConversation`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since that’s what this function does. There’s no modal. --- browser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser.js b/browser.js index b9efa2913..b40009f0e 100644 --- a/browser.js +++ b/browser.js @@ -121,7 +121,7 @@ ipc.on('delete-conversation', () => { ipc.on('archive-conversation', async () => { const index = getNextIndex(true); - openArchiveModal(); + archiveSelectedConversation(); await jumpToConversation(index); }); @@ -318,7 +318,7 @@ function openMuteModal() { }); } -function openArchiveModal() { +function archiveSelectedConversation() { const groupConversationProfilePicture = document.querySelector(`${selectedConversationSelector} ._55lu`); const isGroupConversation = Boolean(groupConversationProfilePicture); From ddf89d3e16be4a18012ca04670a9718764e0bb47 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 22:37:13 +0100 Subject: [PATCH 14/18] =?UTF-8?q?Don=E2=80=99t=20try=20to=20select=20non-e?= =?UTF-8?q?xistent=20conversations.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/browser.js b/browser.js index b40009f0e..6c0dc6ad4 100644 --- a/browser.js +++ b/browser.js @@ -281,7 +281,11 @@ async function jumpToConversation(key) { // Focus on the conversation with the given index async function selectConversation(index) { - (await elementReady(listSelector)).children[index].firstChild.firstChild.click(); + const conversationElement = (await elementReady(listSelector)).children[index]; + + if (conversationElement) { + conversationElement.firstChild.firstChild.click(); + } } // Return the index for next node if next is true, From 7d681b0f4cbf05a1af9df861309671d3b6647fa3 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 22:40:01 +0100 Subject: [PATCH 15/18] Rename `index` to `key`. That argument is 1-based, it later gets converted to a 0-based index. --- browser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser.js b/browser.js index 6c0dc6ad4..ae6e1c2ee 100644 --- a/browser.js +++ b/browser.js @@ -260,8 +260,8 @@ ipc.on('zoom-out', () => { } }); -ipc.on('jump-to-conversation', async (event, index) => { - await jumpToConversation(index); +ipc.on('jump-to-conversation', async (event, key) => { + await jumpToConversation(key); }); async function nextConversation() { From 9b1712a03211644f4b931b799cda2bccc76ada4d Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 22:54:28 +0100 Subject: [PATCH 16/18] Replace `getNextIndex` with `selectedConversationIndex`. --- browser.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/browser.js b/browser.js index ae6e1c2ee..cc7a99404 100644 --- a/browser.js +++ b/browser.js @@ -120,9 +120,11 @@ ipc.on('delete-conversation', () => { }); ipc.on('archive-conversation', async () => { - const index = getNextIndex(true); + const index = selectedConversationIndex(); archiveSelectedConversation(); - await jumpToConversation(index); + + const key = index + 1; + await jumpToConversation(key); }); function setSidebarVisibility() { @@ -265,12 +267,12 @@ ipc.on('jump-to-conversation', async (event, key) => { }); async function nextConversation() { - const index = getNextIndex(true); + const index = selectedConversationIndex(1); await selectConversation(index); } async function previousConversation() { - const index = getNextIndex(false); + const index = selectedConversationIndex(-1); await selectConversation(index); } @@ -288,16 +290,17 @@ async function selectConversation(index) { } } -// Return the index for next node if next is true, -// else returns index for the previous node -function getNextIndex(next) { +function selectedConversationIndex(offset = 0) { const selected = document.querySelector(selectedConversationSelector); + + // TODO: return -1 if there are no conversations at all? if (!selected) { + // TODO: return -1 in this situation? return 0; } const list = [...selected.parentNode.children]; - const index = list.indexOf(selected) + (next ? 1 : -1); + const index = list.indexOf(selected) + offset; return ((index % list.length) + list.length) % list.length; } From 8fa203e681e471a519273cfa38ead6a245febc7e Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sat, 19 Jan 2019 23:06:14 +0100 Subject: [PATCH 17/18] =?UTF-8?q?Don=E2=80=99t=20try=20to=20change=20conve?= =?UTF-8?q?rsation=20if=20none=20is=20selected.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents errors in situations where conversation list is replaced with another view. --- browser.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/browser.js b/browser.js index cc7a99404..fe3429731 100644 --- a/browser.js +++ b/browser.js @@ -121,10 +121,13 @@ ipc.on('delete-conversation', () => { ipc.on('archive-conversation', async () => { const index = selectedConversationIndex(); - archiveSelectedConversation(); - const key = index + 1; - await jumpToConversation(key); + if (index !== -1) { + archiveSelectedConversation(); + + const key = index + 1; + await jumpToConversation(key); + } }); function setSidebarVisibility() { @@ -268,12 +271,18 @@ ipc.on('jump-to-conversation', async (event, key) => { async function nextConversation() { const index = selectedConversationIndex(1); - await selectConversation(index); + + if (index !== -1) { + await selectConversation(index); + } } async function previousConversation() { const index = selectedConversationIndex(-1); - await selectConversation(index); + + if (index !== -1) { + await selectConversation(index); + } } async function jumpToConversation(key) { @@ -293,10 +302,8 @@ async function selectConversation(index) { function selectedConversationIndex(offset = 0) { const selected = document.querySelector(selectedConversationSelector); - // TODO: return -1 if there are no conversations at all? if (!selected) { - // TODO: return -1 in this situation? - return 0; + return -1; } const list = [...selected.parentNode.children]; From ae18598454890a8c85da9786d2228ce368a67365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Sat, 19 Jan 2019 23:40:01 +0100 Subject: [PATCH 18/18] Update openDeleteModal Function `openDeleteModal` was renamed to `deleteSelectedConverastion` and is now after delete selecting next conversation so chat panel wont be empty. --- browser.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/browser.js b/browser.js index fe3429731..cb3464f16 100644 --- a/browser.js +++ b/browser.js @@ -116,7 +116,7 @@ ipc.on('mute-conversation', () => { }); ipc.on('delete-conversation', () => { - openDeleteModal(); + deleteSelectedConversation(); }); ipc.on('archive-conversation', async () => { @@ -341,9 +341,12 @@ function archiveSelectedConversation() { }); } -function openDeleteModal() { +function deleteSelectedConversation() { + const groupConversationProfilePicture = document.querySelector(`${selectedConversationSelector} ._55lu`); + const isGroupConversation = Boolean(groupConversationProfilePicture); + withConversationMenu(() => { - selectMenuItem(4); + selectMenuItem(isGroupConversation ? 5 : 4); }); }