0

The extension is designed so that when you click a pinned tab, it moves it to the rightmost position out of all the pinned tabs. It works a few times before I keep getting the issue:

Error during tabs.move: Tabs cannot be edited right now (user may be dragging a tab). chromeHidden.handleResponse

When I use the debugger though, it works every single time.

Code:

chrome.tabs.onActivated.addListener(function(tab) {
    chrome.windows.getAll({"populate":true}, function(windows) {
        var tabs = [];
        for (var i = 0; i < windows.length; i++) {
            var win = windows[i];
            if (win.id == tab.windowId) {
                tabs = win.tabs;
                for (var k = 0; k < tabs.length; k++) {
                    var tempTab = tabs[k];
                    if (tempTab.id == tab.tabId && tempTab.pinned == true) {
                        for (var j = k; tabs[j+1] && tabs[j+1].pinned; j++) {
                            chrome.tabs.move(tab.tabId, {"index":j+1});
                        }
                        break;
                    }
                }
            }
        }
    });
});
vturlington
  • 55
  • 1
  • 9
  • possible duplicate of [After calling chrome.tabs.query, the results are not available](http://stackoverflow.com/questions/11688171/after-calling-chrome-tabs-query-the-results-are-not-available) – Rob W Apr 20 '13 at 20:10
  • @RobW I see. The issue has to due with me misunderstanding asynchronous and synchronous. Thank you. – vturlington Apr 20 '13 at 20:29
  • @RobW I still seem to be failing with a full fix though, sadly. – vturlington Apr 20 '13 at 20:45
  • When you have more than one window, you'll be walking through the tabs of the last window only. To solve this, you need to move the second loop inside the first loop. There are more issues with your code, especially the names of the properties. Make sure that you correctly read the [documentation of `chrome.tabs`](https://developer.chrome.com/extensions/tabs.html), in particular the [Tab type](https://developer.chrome.com/extensions/tabs.html#type-Tab). – Rob W Apr 20 '13 at 20:48
  • @RobW I think I fixed the names of the properties, and I moved the second loop inside the first. Now it works a few times before I get a new issue. – vturlington Apr 20 '13 at 21:02
  • What are you trying to achieve? The current code will only move the currently active tab to the next pinned position. Not sure if it matches your intentions. By the way, you should not drastically change your question whenever I offer the solution to the previous question. The question & answer should be of benefit to more than one persion. – Rob W Apr 20 '13 at 21:08
  • @RobW My apologies. I guess I'm not really familiar with etiquette here. Here's what I'm trying to achieve: I click a pinned tab, and it moves it to become the rightmost pinned tab. When I use the debugger and walk through, it always does exactly that, every time. When I don't use the debugger though, it works randomly, but usually it just throws the error. What do you think I should leave my question as (what do you think would help the most people from what we've done so far)? – vturlington Apr 20 '13 at 21:12
  • I suggest to ask the literal question: "How to move a tab after the last pinned tab?" It's practical, and you do have code that suggests that you've done sufficient efforts to solve the problem yourself. Then, an answer can be posted and marked as "accepted" (provided that it did solve the problem). See this faq entry: http://stackoverflow.com/faq#howtoask – Rob W Apr 20 '13 at 21:16
  • @RobW Done. Thanks a lot for your patience, and the faq link. – vturlington Apr 20 '13 at 21:21

1 Answers1

2

Your current code has some flaws:

  1. Inefficiency: You select all windows and tabs, while only the pinned tabs in the current window are needed.
  2. Incorrect use of the asynchronous chrome.tabs.move method: You're moving the single tab after the last pinned tab by repeatedly moving the tab to the right. As I said, chrome.tabs.move is asynchronous, so when you call chrome.tabs.move again, the previous "move request" might not have finished yet. Hence your error.

To get more efficient, use the chrome.tabs.query method with the relevant filters:

chrome.tabs.onActivated.addListener(function(activeInfo) {
    var tabId = activeInfo.tabId;
    chrome.tabs.query({
        currentWindow: true,
        pinned: true
    }, function(tabs) {
        // Only move the tab if at least one tab is pinned
        if (tabs.length > 0) {
            var lastTab = tabs[ tabs.length - 1 ];
            var tabIndex = lastTab.index + 1;
            for (var i=0; i<tabs.length; ++i) {
                if (tabs[i].id == tabId) {
                    // Current tab is pinned, so decrement the tabIndex by one.
                    --tabIndex;
                    break;
                }
            }
            chrome.tabs.move(tabId, {index: tabIndex});
        }
    }); // End of chrome.tabs.query
});  // End of chrome.tabs.onActivated.addListener

If you want to do something else after moving the tab, pass a callback to chrome.tabs.move:

chrome.tabs.move(tabId, {index: tabIndex}, function() {
    console.log('Moved tab!');
});

Note: The tab won't move if you keep the mouse pressed. Also, always moving the tab when a tab is focused is a bit unfriendly in terms of user experience. You'd better use a browser action button to activate this feature. Yes, it's one additional click to move the tab, but at least the user will have a choice to not move tabs if they want to.

chrome.browserAction.onClicked.addListener(function(tab) {
    var tabId = tab.id;
    chrome.tabs.query({currentWindow: true, pinned: true}, ...);
});
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • Thanks for the answer. Two issues though, which I've failed to solve one of them. 1) tab.id in the call to tabs.move should be tab.tabId. Easily fixed. 2) !tab.pinned isn't a good idea because in this scope, tab is just an activeInfo object with only the properties "tabId" and "windowId" (see [here](http://developer.chrome.com/extensions/tabs.html#event-onActivated)). I tried using a for loop to move through the tabs and find the proper tab to move that way (and check the pinned state on it) but I still ended up with my original error. – vturlington Apr 20 '13 at 22:20
  • @TwilitSoul You're right about the type, updated (and tested) answer. – Rob W Apr 20 '13 at 22:25
  • Alas, we are closer but [for me at least] not quite there. I tested this as well, and I am still getting the same errors. It consistently moves newly created tabs to the correct position. In fact, amusingly (for I had not thought about this and do not like this), when I use ctrl-tab or shift-ctrl-tab to swap tabs, the tab I move to always changes position correctly. However, when I click a tab, it does not move the tab. I think it might be acting so quickly that I still have the mouse button held down and it thinks I'm holding the tab in place. – vturlington Apr 20 '13 at 22:38
  • 1
    I think I was correct in my assumption that it was trying to act too fast. I would answer my own question, but my rep is too low =) Feel free to update yours with the fix and I'll choose your answer. Fix: setTimeout(moveTab, 100); function moveTab() { chrome.tabs.move(tabId, {index: tabIndex}); } – vturlington Apr 20 '13 at 23:02
  • Gotcha. I've also modified the code further now, so that I can ctrl-tab and shift-ctrl-tab without making the tabs shuffle. I did that by adding a check to be sure I wasn't only moving one space away. If I was only moving one space away, no shuffle. Edit: I also changed the code to allow a similar effect when no tabs are pinned. – vturlington Apr 20 '13 at 23:44
  • @TwilitSoul Check the revised answer. I've included a more general version of your observation, and added a new tip (see note at the end). – Rob W Apr 21 '13 at 09:00