Skip to content

Commit 47deeb4

Browse files
authored
Add option to open in new tab or window (#105)
1 parent 6f3a55e commit 47deeb4

12 files changed

+167
-8
lines changed

Diff for: package-lock.json

+63
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"devDependencies": {
5353
"@rollup/plugin-commonjs": "^24.0.1",
5454
"@rollup/plugin-node-resolve": "^15.0.1",
55+
"@types/chrome": "^0.0.234",
5556
"eslint": "^8.35.0",
5657
"eslint-config-prettier": "^8.6.0",
5758
"eslint-config-xo": "^0.43.1",

Diff for: rollup.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const config = {
1010
input: {
1111
main: 'source/main.js',
1212
'options/options': 'source/options/options.js',
13+
background: 'source/background.js',
1314
},
1415
output: {
1516
sourcemap: !production,

Diff for: source/App.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@
2323
showExtras = true;
2424
}
2525
26-
if (width.trim()) {
27-
const cleanWidth = /[a-z]/i.test(width) ? width : width.trim() + 'px';
28-
document.body.style.width = cleanWidth;
26+
if (new URLSearchParams(location.search).get('type') !== 'window') {
27+
document.body.style.width = (width || 400) + 'px';
2928
}
3029
});
3130
$: {

Diff for: source/background.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import optionsStorage, {matchOptions} from './options-storage';
2+
3+
// TODO: https://github.com/fregante/webext-options-sync/issues/63
4+
chrome.storage.onChanged.addListener(async (changes, areaName) => {
5+
if (areaName === 'sync' && 'options' in changes) {
6+
matchOptions();
7+
}
8+
});
9+
10+
// Must be registered on the top level
11+
chrome.action.onClicked.addListener(async () => {
12+
let {position, width} = await optionsStorage.getAll();
13+
if (position === 'popup') {
14+
return;
15+
}
16+
17+
if (position === 'tab') {
18+
chrome.tabs.create({url: chrome.runtime.getURL('index.html?type=tab')});
19+
return;
20+
}
21+
22+
if (position === 'window') {
23+
width = width === '' ? 400 : Number.parseInt(width, 10); // Must be an integer
24+
const height = 600;
25+
const currentWindow = await chrome.windows.getCurrent();
26+
await chrome.windows.create({
27+
type: 'popup',
28+
url: chrome.runtime.getURL('index.html?type=window'),
29+
width,
30+
height,
31+
top: currentWindow.top + Math.round((currentWindow.height - height) / 2),
32+
left: currentWindow.left + Math.round((currentWindow.width - width) / 2),
33+
});
34+
}
35+
});
36+
37+
matchOptions();

Diff for: source/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<!DOCTYPE html>
2-
<title>Extension Manager</title>
2+
<title>One Click Extensions Manager</title>
33
<link href="style.css" rel="stylesheet" />
44
<script type="module" src="main.js"></script>

Diff for: source/lib/fit-window.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
function fitWindowToContentHeight() {
2+
// Sigh, the innerHeight is wildly off while loading
3+
const uiHeight = Math.min(50, window.outerHeight - window.innerHeight);
4+
const height = document.body.scrollHeight + uiHeight;
5+
window.resizeTo(window.outerWidth, height);
6+
}
7+
8+
export default function fitWindow() {
9+
new ResizeObserver(fitWindowToContentHeight).observe(document.body);
10+
}

Diff for: source/main.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import App from './App.svelte';
2+
import fitWindow from './lib/fit-window';
23

34
new App({
45
target: document.body,
56
});
67

7-
// Move to App.svelte once this is supported: https://github.com/sveltejs/svelte/issues/3105
8-
document.body.dataset.type = new URLSearchParams(location.search).get('type');
8+
const type = new URLSearchParams(location.search).get('type');
9+
document.body.dataset.type = type;
10+
if (type === 'window') {
11+
fitWindow();
12+
}

Diff for: source/manifest.json

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
"options_ui": {
1919
"page": "options/options.html"
2020
},
21+
"background": {
22+
"service_worker": "background.js",
23+
"type": "module"
24+
},
2125
"commands": {
2226
"_execute_action": {}
2327
}

Diff for: source/options-storage.js

+22
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,31 @@ import OptionsSync from 'webext-options-sync';
22

33
const optionsStorage = new OptionsSync({
44
defaults: {
5+
position: 'popup',
56
showButtons: 'on-demand', // Or 'always'
67
width: '',
78
},
9+
migrations: [
10+
options => {
11+
let {width} = options;
12+
// Ignore if unset
13+
if (!width) {
14+
return;
15+
}
16+
17+
// Parse them and clamp the value
18+
width = Math.min(Math.max(250, Number.parseInt(width, 10)), 1000);
19+
20+
options.width = Number.isNaN(width) ? '' : width;
21+
},
22+
],
823
});
924

1025
export default optionsStorage;
26+
27+
const defaultPopup = chrome.runtime.getManifest().action.default_popup;
28+
29+
export async function matchOptions() {
30+
const {position} = await optionsStorage.getAll();
31+
chrome.action.setPopup({popup: position === 'popup' ? defaultPopup : ''});
32+
}

Diff for: source/options/options.html

+11-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<title>One Click Extension Manager options</title>
55
<style>
66
@import './webext-base.css';
7+
input[type='number'],
78
input[type='text'] {
89
border: solid 1px;
910
border-radius: 2px;
@@ -19,16 +20,24 @@
1920
}
2021
</style>
2122
<form id="options-form">
23+
<p>
24+
<label for="position">Position</label>
25+
<select name="position" id="position">
26+
<option value="popup">Menu (default)</option>
27+
<option value="window">Popup window</option>
28+
<option value="tab">Tab</option>
29+
</select>
30+
</p>
2231
<p>
2332
<label for="showButtons">Show buttons</label>
2433
<select name="showButtons" id="showButtons">
25-
<option value="on-demand">On demand (default)</option>
34+
<option value="on-demand">On right click (default)</option>
2635
<option value="always">Always</option>
2736
</select>
2837
</p>
2938
<p>
3039
<label for="width"
31-
>List width <small>(CSS value or leave empty)</small></label
40+
>List width <small>(in pixels, or leave empty)</small></label
3241
>
3342
<input type="text" name="width" id="width" placeholder="400px" />
3443
</p>

Diff for: source/style.css

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ body[data-type='popup'] {
1616
width: 320px;
1717
}
1818

19+
body[data-type='tab'],
20+
body[data-type='window'] {
21+
width: auto;
22+
}
23+
24+
body[data-type='tab'] {
25+
max-width: 800px;
26+
}
27+
1928
input {
2029
box-sizing: border-box;
2130
width: 100%;

0 commit comments

Comments
 (0)