forked from jonathanKingston/merge-windows
-
Notifications
You must be signed in to change notification settings - Fork 1
/
background.js
92 lines (89 loc) · 3.19 KB
/
background.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
'use strict'
let focusOrder = []
browser.windows.onRemoved.addListener(removedId => {
focusOrder.filter(id => removedId !== id)
browser.contextMenus.remove('merge_' + removedId)
getWindowsSorted().then(windows => windows.length < 2 && browser.contextMenus.removeAll())
})
browser.windows.onFocusChanged.addListener(focusedId => {
if (focusedId === browser.windows.WINDOW_ID_NONE) return
focusOrder = [...new Set([focusedId].concat(focusOrder))]
Promise.all([
getWindowsSorted(),
browser.contextMenus.removeAll()
]).then(([windows]) => {
if (windows.length < 2) return
const parentId = browser.contextMenus.create({
title: 'Merge Windows'
})
browser.contextMenus.create({
title: 'Merge all windows into this one',
id: 'merge_all',
parentId
})
browser.contextMenus.create({
type: 'separator',
parentId
})
windows
.splice(1)
.forEach(window => {
browser.contextMenus.create({
title: 'Merge tabs from ' + window.title,
id: 'merge_' + window.id,
parentId
})
})
})
})
browser.contextMenus.onClicked.addListener((menuItem, currentTab) => {
if (menuItem.menuItemId === 'merge_all') {
getWindowsSorted(true)
.then(windows => merge(windows.splice(1), currentTab.windowId, currentTab.id))
} else if (menuItem.menuItemId.substr(0, 6) === 'merge_') {
browser.windows.get(parseInt(menuItem.menuItemId.substr(6)), { populate: true })
.then(subject => merge([subject], currentTab.windowId, currentTab.id))
}
})
browser.commands.onCommand.addListener(command => {
Promise.all([
browser.tabs.query({ active: true, currentWindow: true }),
getWindowsSorted(true)
]).then(command === 'merge-all-windows'
? ([[tab], windows]) => merge(windows.splice(1), tab.windowId, tab.id)
: ([[tab], windows]) => merge(windows.splice(1, 1), tab.windowId, tab.id)
)
})
/**
* @param {bool} [populate=false] Whether to populate windows.Window objects with tab information
*/
function getWindowsSorted (populate = false) {
return new Promise(function (resolve, reject) {
browser.windows.getAll({ windowTypes: ['normal'], populate })
.then(windows => resolve(
windows
.sort((a, b) => [focusOrder.indexOf(a.id), focusOrder.indexOf(b.id)]
.map(i => i < 0 ? Infinity : i)
.reduce((a, b) => a === b ? 0 : a - b)
)
.filter((window, index, sorted) => window.incognito === sorted[0].incognito)
), reject)
})
}
/**
* @param {windows.Window[]} subjects Array of populated windows.Window objects
* @param {number} target Window ID to merge all subjects’ tabs into
* @param {number} active Tab ID of the active tab after merge
*/
function merge (subjects, target, active) {
const tabs = subjects.flatMap(window => window.tabs)
Promise
.all(tabs.filter(tab => tab.pinned).map(tab => browser.tabs.update(tab.id, { pinned: false })))
.then(unpinned => {
browser.tabs.move(tabs.map(tab => tab.id), { windowId: target, index: -1 })
.then(() => {
browser.tabs.update(active, { active: true })
unpinned.forEach(tab => browser.tabs.update(tab.id, { pinned: true }))
})
})
}