diff --git a/app/BTAppNode.js b/app/BTAppNode.js index 7f6c20a..bcf115c 100644 --- a/app/BTAppNode.js +++ b/app/BTAppNode.js @@ -983,7 +983,7 @@ const Handlers = { "tabJoinedTG" : tabJoinedTG, // a tab was dragged or moved into a TG "tabLeftTG" : tabLeftTG, // a tab was dragged out of a TG "tabNavigated": tabNavigated, // User navigated a tab to a new url - "tabOpened" : tabOpened, // New tab opened + "tabOpened" : tabOpened, // New tab opened by bg on our behalf "tabMoved" : tabMoved, // user moved a tab "tabPositioned": tabPositioned, // tab moved by extension "tabClosed" : tabClosed, // tab closed diff --git a/app/bt.js b/app/bt.js index e67dc4a..f0fd538 100644 --- a/app/bt.js +++ b/app/bt.js @@ -949,28 +949,28 @@ function tabGroupUpdated(data){ function tabJoinedTG(data) { // tab joined TG, update associated topic as appropriate + // NB Get here when an existing page is opened in its TG as well as page dropping into TG. Former is no-op + // known TG but unknown node => unmanaged tab dropped into managed TG => save it to the topic const tabId = data.tabId; const tgId = data.groupId; + const tabNode = BTAppNode.findFromTab(tabId); + const topicNode = BTAppNode.findFromGroup(tgId); + if (tabNode || !topicNode) return; // n/a || don't care const tab = data.tab; const index = data.tabIndex; const indices = data.tabIndices; const winId = data.windowId; - let tabNode = BTAppNode.findFromTab(tabId); - const topicNode = BTAppNode.findFromGroup(tgId); - if (!topicNode) return; // don't care - if (!tabNode) { - // known TG but unknown node => unmanaged tab dropped into managed TG => save it to the topic - tabNode = new BTAppNode(`[[${tab.url}][${tab.title}]]`, topicNode.id, + + tabNode = new BTAppNode(`[[${tab.url}][${tab.title}]]`, topicNode.id, "", topicNode.level + 1); - tabNode.tabId = tabId; - tabNode.tabGroupId = tgId; - tabNode.faviconUrl = tab.favIconUrl; - $("table.treetable").treetable("loadBranch", topicNode.getTTNode(), tabNode.HTML()); - tabNode.populateFavicon(); - initializeUI(); - changeSelected(tabNode); - } + tabNode.tabId = tabId; + tabNode.tabGroupId = tgId; + tabNode.faviconUrl = tab.favIconUrl; + $("table.treetable").treetable("loadBranch", topicNode.getTTNode(), tabNode.HTML()); + tabNode.populateFavicon(); + initializeUI(); + changeSelected(tabNode); positionInTopic(topicNode, tabNode, index, indices, winId); } @@ -1022,7 +1022,11 @@ function tabMoved(data) { function positionInTopic(topicNode, tabNode, index, indices, winId) { // Position tab node under topic node as per tab ordering in browser - // first find where tabNode should go under topicNode. + // first update indices and find where tabNode should go under topicNode. + for (let [tabId, tabData] of Object.entries(indices)) { + let n = BTAppNode.findFromTab(tabId); + if (n) n.tabIndex = tabData.index; + } let dropUnderNode = topicNode; const leftIndex = topicNode.leftmostOpenTabIndex(); if (index > leftIndex) { diff --git a/app/gDriveFileManager.js b/app/gDriveFileManager.js index 55279fc..abd23e7 100644 --- a/app/gDriveFileManager.js +++ b/app/gDriveFileManager.js @@ -419,6 +419,7 @@ const gDriveFileManager = (() => { SaveUnderway = false; alert("BT - Error accessing GDrive."); console.log("Error in writeBTFile: ", JSON.stringify(err)); + _renewTokenAndRetryWrite(); return; }); } @@ -429,6 +430,19 @@ const gDriveFileManager = (() => { return; } } + + function _renewTokenAndRetryWrite() { + // The access token is missing, invalid, or expired, or not yet existed, prompt for user consent to obtain one. + if (confirm("BT - Error accessing GDrive. Would you like to renew the token and try again?")) { + renewToken().then(() => { + // Retry the current function here. + _writeBTFile(); + }).catch((error) => { + // Clean up aisle five!!! Tell user to reconnect or something. + console.error("Failed to renew token: ", error); + }); + } + } } async function getBTModifiedTime() { diff --git a/extension/background.js b/extension/background.js index 5e6ec06..a635054 100644 --- a/extension/background.js +++ b/extension/background.js @@ -528,7 +528,7 @@ function openTabGroups(msg, sender) { }); } -function groupAndPositionTabs(msg, sender) { +async function groupAndPositionTabs(msg, sender) { // array of {nodeId, tabId, tabIndex} to group in tabGroupId and order const tabGroupId = msg.tabGroupId; @@ -541,12 +541,13 @@ function groupAndPositionTabs(msg, sender) { const tabIds = tabInfo.map(t => t.tabId); const groupArgs = tabGroupId ? {'tabIds': tabIds, 'groupId': tabGroupId} : windowId ? - {'tabIds': tabIds, 'createProperties': {'windowId': windowId}} : - {'tabIds': tabIds}; + {'tabIds': tabIds, 'createProperties': {'windowId': windowId}} : {'tabIds': tabIds}; console.log(`groupAndposition.groupArgs: ${JSON.stringify(groupArgs)}`); if (!tabIds.length) return; // shouldn't happen, but safe - chrome.tabs.move(tabIds, {'index': tabInfo[0].tabIndex}, tabs => { + const firstTab = await chrome.tabs.get(tabIds[0]); + const tabIndex = tabInfo[0].tabIndex || firstTab.index; + chrome.tabs.move(tabIds, {'index': tabIndex}, tabs => { // first move tabs into place check('groupAndPositionTabs-move'); chrome.tabs.group(groupArgs, groupId => { @@ -823,7 +824,7 @@ async function saveTabs(msg, sender) { tabsToSave.push(tab); } }); - // Send save msg to BT. NB reverse tabs array cos push operations above reversed the displayed tab order in the browser + // Send save msg to BT. if (tabsToSave.length) btSendMessage(BTTab, {'function': 'saveTabs', 'saveType':saveType, 'tabs': tabsToSave, 'note': msg.note, 'close': msg.close}); btSendMessage(BTTab, {'function': 'tabActivated', 'tabId': currentTab.id }); // ensure BT selects the current tab diff --git a/extension/manifest.json b/extension/manifest.json index d07ed19..31581c1 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -14,7 +14,7 @@ "othermatches": ["https://BrainTool.org/app/*"], "matches": ["http://localhost:8000/*"], "run_at" : "document_idle", - "js": ["btContentScript.test.js"] + "js": ["btContentScript.js"] } ], "action": { diff --git a/versions/Release-Candidate/app/BTAppNode.js b/versions/Release-Candidate/app/BTAppNode.js index 7f6c20a..bcf115c 100644 --- a/versions/Release-Candidate/app/BTAppNode.js +++ b/versions/Release-Candidate/app/BTAppNode.js @@ -983,7 +983,7 @@ const Handlers = { "tabJoinedTG" : tabJoinedTG, // a tab was dragged or moved into a TG "tabLeftTG" : tabLeftTG, // a tab was dragged out of a TG "tabNavigated": tabNavigated, // User navigated a tab to a new url - "tabOpened" : tabOpened, // New tab opened + "tabOpened" : tabOpened, // New tab opened by bg on our behalf "tabMoved" : tabMoved, // user moved a tab "tabPositioned": tabPositioned, // tab moved by extension "tabClosed" : tabClosed, // tab closed diff --git a/versions/Release-Candidate/app/bt.js b/versions/Release-Candidate/app/bt.js index e67dc4a..f0fd538 100644 --- a/versions/Release-Candidate/app/bt.js +++ b/versions/Release-Candidate/app/bt.js @@ -949,28 +949,28 @@ function tabGroupUpdated(data){ function tabJoinedTG(data) { // tab joined TG, update associated topic as appropriate + // NB Get here when an existing page is opened in its TG as well as page dropping into TG. Former is no-op + // known TG but unknown node => unmanaged tab dropped into managed TG => save it to the topic const tabId = data.tabId; const tgId = data.groupId; + const tabNode = BTAppNode.findFromTab(tabId); + const topicNode = BTAppNode.findFromGroup(tgId); + if (tabNode || !topicNode) return; // n/a || don't care const tab = data.tab; const index = data.tabIndex; const indices = data.tabIndices; const winId = data.windowId; - let tabNode = BTAppNode.findFromTab(tabId); - const topicNode = BTAppNode.findFromGroup(tgId); - if (!topicNode) return; // don't care - if (!tabNode) { - // known TG but unknown node => unmanaged tab dropped into managed TG => save it to the topic - tabNode = new BTAppNode(`[[${tab.url}][${tab.title}]]`, topicNode.id, + + tabNode = new BTAppNode(`[[${tab.url}][${tab.title}]]`, topicNode.id, "", topicNode.level + 1); - tabNode.tabId = tabId; - tabNode.tabGroupId = tgId; - tabNode.faviconUrl = tab.favIconUrl; - $("table.treetable").treetable("loadBranch", topicNode.getTTNode(), tabNode.HTML()); - tabNode.populateFavicon(); - initializeUI(); - changeSelected(tabNode); - } + tabNode.tabId = tabId; + tabNode.tabGroupId = tgId; + tabNode.faviconUrl = tab.favIconUrl; + $("table.treetable").treetable("loadBranch", topicNode.getTTNode(), tabNode.HTML()); + tabNode.populateFavicon(); + initializeUI(); + changeSelected(tabNode); positionInTopic(topicNode, tabNode, index, indices, winId); } @@ -1022,7 +1022,11 @@ function tabMoved(data) { function positionInTopic(topicNode, tabNode, index, indices, winId) { // Position tab node under topic node as per tab ordering in browser - // first find where tabNode should go under topicNode. + // first update indices and find where tabNode should go under topicNode. + for (let [tabId, tabData] of Object.entries(indices)) { + let n = BTAppNode.findFromTab(tabId); + if (n) n.tabIndex = tabData.index; + } let dropUnderNode = topicNode; const leftIndex = topicNode.leftmostOpenTabIndex(); if (index > leftIndex) { diff --git a/versions/Release-Candidate/app/gDriveFileManager.js b/versions/Release-Candidate/app/gDriveFileManager.js index 55279fc..abd23e7 100644 --- a/versions/Release-Candidate/app/gDriveFileManager.js +++ b/versions/Release-Candidate/app/gDriveFileManager.js @@ -419,6 +419,7 @@ const gDriveFileManager = (() => { SaveUnderway = false; alert("BT - Error accessing GDrive."); console.log("Error in writeBTFile: ", JSON.stringify(err)); + _renewTokenAndRetryWrite(); return; }); } @@ -429,6 +430,19 @@ const gDriveFileManager = (() => { return; } } + + function _renewTokenAndRetryWrite() { + // The access token is missing, invalid, or expired, or not yet existed, prompt for user consent to obtain one. + if (confirm("BT - Error accessing GDrive. Would you like to renew the token and try again?")) { + renewToken().then(() => { + // Retry the current function here. + _writeBTFile(); + }).catch((error) => { + // Clean up aisle five!!! Tell user to reconnect or something. + console.error("Failed to renew token: ", error); + }); + } + } } async function getBTModifiedTime() { diff --git a/versions/Release-Candidate/extension/background.js b/versions/Release-Candidate/extension/background.js index 5e6ec06..a635054 100644 --- a/versions/Release-Candidate/extension/background.js +++ b/versions/Release-Candidate/extension/background.js @@ -528,7 +528,7 @@ function openTabGroups(msg, sender) { }); } -function groupAndPositionTabs(msg, sender) { +async function groupAndPositionTabs(msg, sender) { // array of {nodeId, tabId, tabIndex} to group in tabGroupId and order const tabGroupId = msg.tabGroupId; @@ -541,12 +541,13 @@ function groupAndPositionTabs(msg, sender) { const tabIds = tabInfo.map(t => t.tabId); const groupArgs = tabGroupId ? {'tabIds': tabIds, 'groupId': tabGroupId} : windowId ? - {'tabIds': tabIds, 'createProperties': {'windowId': windowId}} : - {'tabIds': tabIds}; + {'tabIds': tabIds, 'createProperties': {'windowId': windowId}} : {'tabIds': tabIds}; console.log(`groupAndposition.groupArgs: ${JSON.stringify(groupArgs)}`); if (!tabIds.length) return; // shouldn't happen, but safe - chrome.tabs.move(tabIds, {'index': tabInfo[0].tabIndex}, tabs => { + const firstTab = await chrome.tabs.get(tabIds[0]); + const tabIndex = tabInfo[0].tabIndex || firstTab.index; + chrome.tabs.move(tabIds, {'index': tabIndex}, tabs => { // first move tabs into place check('groupAndPositionTabs-move'); chrome.tabs.group(groupArgs, groupId => { @@ -823,7 +824,7 @@ async function saveTabs(msg, sender) { tabsToSave.push(tab); } }); - // Send save msg to BT. NB reverse tabs array cos push operations above reversed the displayed tab order in the browser + // Send save msg to BT. if (tabsToSave.length) btSendMessage(BTTab, {'function': 'saveTabs', 'saveType':saveType, 'tabs': tabsToSave, 'note': msg.note, 'close': msg.close}); btSendMessage(BTTab, {'function': 'tabActivated', 'tabId': currentTab.id }); // ensure BT selects the current tab