diff --git a/app/bg/background.js b/app/bg/background.js
index f60a333d..e00387ee 100644
--- a/app/bg/background.js
+++ b/app/bg/background.js
@@ -127,6 +127,37 @@ let onCommandListener = function(cmd) {
} //onCommandListener()
chrome.commands.onCommand.addListener(onCommandListener);
+// When a window is created
+chrome.windows.onCreated.addListener(function(window){
+ // Leave TabFern window alone...
+ if (window.id === me.viewWindowID) return;
+
+ if (S.getBool(S.FIXED_WINDOW_SIZE) && window.type === 'normal') {
+ let windowSize = S.getString(S.S_WINDOW_SIZE);
+ [windowWidth, windowHeight] = windowSize.split('x').map((value) => parseInt(value));
+ chrome.windows.update(window.id, {width: windowWidth, height: windowHeight});
+ }
+ if (S.getBool(S.PREFERRED_WINDOW_POSITION_OFFSET) && window.type === 'normal') {
+ let fixedOffsetFormat = RegExp(/^([0-9]+):([0-9]+)$/)
+ let fixedOffsetValues = S.getString(S.S_WINDOW_POSITION_OFFSET_VALUES).match(fixedOffsetFormat);
+ if(fixedOffsetValues) {
+ topOffset = parseInt(fixedOffsetValues[1]);
+ leftOffset = parseInt(fixedOffsetValues[2]);
+ chrome.windows.update(window.id, {top:topOffset, left:leftOffset});
+ }
+ let relativeOffsetFormat = RegExp(/^\+([0-9]+):\+([0-9]+)$/)
+ let relativeOffsetValues = S.getString(S.S_WINDOW_POSITION_OFFSET_VALUES).match(relativeOffsetFormat);
+ if(relativeOffsetValues) {
+ // According to Window features documentation default new window offset is 22px
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features
+ // If user has a preferred relative offset preference we need to discount the default offset
+ topOffset = window.top + parseInt(relativeOffsetValues[1])-22;
+ leftOffset = window.left + parseInt(relativeOffsetValues[2])-22;
+ chrome.windows.update(window.id, {top:topOffset, left:leftOffset});
+ }
+ }
+});
+
// When a window is closed
chrome.windows.onRemoved.addListener(function(windowId) {
// If the window getting closed is the popup we created
diff --git a/app/common/setting-definitions.js b/app/common/setting-definitions.js
index d10585cd..4dfb69d9 100644
--- a/app/common/setting-definitions.js
+++ b/app/common/setting-definitions.js
@@ -105,6 +105,14 @@ _NAM.CFG_TITLE_IN_TOOLTIP = 'tooltip-has-title';
_DEF[_NAM.CFG_TITLE_IN_TOOLTIP] = false;
_VAL[_NAM.CFG_TITLE_IN_TOOLTIP] = _vbool;
+_NAM.CFG_FIXED_WINDOW_SIZE = 'window-size-is-fixed';
+_DEF[_NAM.CFG_FIXED_WINDOW_SIZE] = false;
+_VAL[_NAM.CFG_FIXED_WINDOW_SIZE] = _vbool;
+
+_NAM.CFG_PREFERRED_WINDOW_POSITION_OFFSET = 'window-position-offset-is-fixed';
+_DEF[_NAM.CFG_PREFERRED_WINDOW_POSITION_OFFSET] = false;
+_VAL[_NAM.CFG_PREFERRED_WINDOW_POSITION_OFFSET] = _vbool;
+
/// Not actually a setting, but an indicator that we loaded settings OK.
/// Used by src/settings/main.js.
_NAM.SETTINGS_LOADED_OK = '__settings_loaded_OK';
@@ -168,6 +176,20 @@ _VAL[_NAM.CFGS_FAVICON_SOURCE] = (v)=>{
return (( v === FAVICON_SITE || v === FAVICON_CHROME || v === FAVICON_DDG ) ? v : undefined);
};
+_NAM.CFGS_WINDOW_SIZE = 'window-size';
+_DEF[_NAM.CFGS_WINDOW_SIZE] = '800x600';
+_VAL[_NAM.CFGS_WINDOW_SIZE] = (v)=>{
+ let regex = RegExp(/^[0-9]+[xX][0-9]+$/);
+ return (( v.match(regex) ) ? v : undefined);
+};
+
+_NAM.CFGS_WINDOW_POSITION_OFFSET_VALUES = 'window-position-offset-values';
+_DEF[_NAM.CFGS_WINDOW_POSITION_OFFSET_VALUES] = '+36:+36';
+_VAL[_NAM.CFGS_WINDOW_POSITION_OFFSET_VALUES] = (v)=>{
+ let regex = RegExp(/^\+?[0-9]+:\+?[0-9]+$/);
+ return (( v.match(regex) ) ? v : undefined);
+};
+
// }}}2
/// The default values for the configuration settings.
diff --git a/app/settings/manifest.js b/app/settings/manifest.js
index 1248972a..c5412217 100644
--- a/app/settings/manifest.js
+++ b/app/settings/manifest.js
@@ -143,6 +143,77 @@ vote at ${issue(125,true)}.
"type": "checkbox",
"label": future_i18n('Sort open windows to the top, scroll to the top of the list'),
},
+ {
+ "tab": future_i18n("Behaviour"),
+ "group": future_i18n("When I..."),
+ "name": S.FIXED_WINDOW_SIZE,
+ "type": "checkbox",
+ "label": future_i18n('Open a window, always open it with a preferred fixed size'),
+ },
+ { // some extra descriptive text for S.FIXED_WINDOW_SIZE
+ "tab": future_i18n("Behaviour"),
+ "group": future_i18n("When I..."),
+ "type": "description",
+ "text": future_i18n(`If you change this value please refresh Settings
+ page (this page) to reveal preferred window size parameter`)
+ },
+ ];
+
+ if(S.getBool(S.FIXED_WINDOW_SIZE)) setting_definitions.push(
+ {
+ "tab": future_i18n("Behaviour"),
+ "group": future_i18n("When I..."),
+ "name": S.S_WINDOW_SIZE,
+ "type": "text",
+ "label": future_i18n('Window size'),
+ },
+ { // some extra descriptive text for S.FIXED_WINDOW_SIZE
+ "tab": future_i18n("Behaviour"),
+ "group": future_i18n("When I..."),
+ "type": "description",
+ "text": future_i18n(`The format of the window size parameter is [width]x[height]
+ e.g. 800x600`)
+ },
+ );
+
+ setting_definitions.push(
+ {
+ "tab": future_i18n("Behaviour"),
+ "group": future_i18n("When I..."),
+ "name": S.PREFERRED_WINDOW_POSITION_OFFSET,
+ "type": "checkbox",
+ "label": future_i18n('Open a window, use preferred window position offset'),
+ },
+ { // some extra descriptive text for S.PREFERRED_WINDOW_POSITION_OFFSET
+ "tab": future_i18n("Behaviour"),
+ "group": future_i18n("When I..."),
+ "type": "description",
+ "text": future_i18n(`Refresh Settings page (this page) when changed
+ to reveal preferred window position offset parameter`)
+ },
+ )
+
+ if(S.getBool(S.PREFERRED_WINDOW_POSITION_OFFSET)) setting_definitions.push(
+ {
+ "tab": future_i18n("Behaviour"),
+ "group": future_i18n("When I..."),
+ "name": S.S_WINDOW_POSITION_OFFSET_VALUES,
+ "type": "text",
+ "label": future_i18n('Window position offset'),
+ },
+ { // some extra descriptive text for S.FIXED_WINDOW_SIZE
+ "tab": future_i18n("Behaviour"),
+ "group": future_i18n("When I..."),
+ "type": "description",
+ "text": future_i18n(
+ `If format is [top]:[left] e.g. 16:16 the offset is relative to screen
+ If format is +[top]:+[left] e.g. +36:+36 the offset is relative to last focused window
+ +0:+0 opens new window exactly on top of previously focused window
+ 0:0 opens new window exactly positioned top left corner of screen
`)
+ },
+ );
+
+ setting_definitions.push(
{
"tab": future_i18n("Behaviour"),
"group": future_i18n("When I..."),
@@ -159,8 +230,7 @@ vote at ${issue(125,true)}.
TabFern window, even if you didn't check the "Sort
open windows" box above.`
},
-
-]; //setting_definitions
+);
if(S.ISSUE35) setting_definitions.push(
{
diff --git a/package-lock.json b/package-lock.json
index e97c71cf..89bef1ae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1128,9 +1128,9 @@
},
"dependencies": {
"lodash": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
- "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
"dev": true
}
}
@@ -2417,9 +2417,9 @@
"dev": true
},
"elliptic": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
- "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
+ "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"dev": true,
"requires": {
"bn.js": "^4.4.0",
@@ -2912,19 +2912,13 @@
"rimraf": "2"
},
"dependencies": {
- "minimist": {
- "version": "0.0.8",
- "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true
- },
"mkdirp": {
- "version": "0.5.1",
- "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"requires": {
- "minimist": "0.0.8"
+ "minimist": "^1.2.5"
}
}
}
@@ -3684,9 +3678,9 @@
"integrity": "sha512-PQpeWxG6vNuTT0Gq20LyAzqSpeBWtQ6DTYIJB7JMJEetgF730Om9e6y82GdEv06o1iaJiH1hh2JpSOXK3zIAdA=="
},
"kind-of": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
- "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true
},
"lazystream": {
@@ -3741,9 +3735,9 @@
}
},
"lodash": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
- "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
"dev": true
},
"lodash.assign": {
@@ -4133,19 +4127,13 @@
"brace-expansion": "^1.1.7"
}
},
- "minimist": {
- "version": "0.0.8",
- "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true
- },
"mkdirp": {
- "version": "0.5.1",
- "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"requires": {
- "minimist": "0.0.8"
+ "minimist": "^1.2.5"
}
},
"semver": {
@@ -4259,19 +4247,13 @@
"brace-expansion": "^1.1.7"
}
},
- "minimist": {
- "version": "0.0.8",
- "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true
- },
"mkdirp": {
- "version": "0.5.1",
- "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"requires": {
- "minimist": "0.0.8"
+ "minimist": "^1.2.5"
}
},
"supports-color": {
@@ -5951,19 +5933,13 @@
"rimraf": "2"
}
},
- "minimist": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true
- },
"mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"requires": {
- "minimist": "0.0.8"
+ "minimist": "^1.2.5"
}
}
}
@@ -6189,38 +6165,15 @@
"dev": true
},
"union-value": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
- "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
- "set-value": "^0.4.3"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "set-value": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
- "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
- "dev": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-extendable": "^0.1.1",
- "is-plain-object": "^2.0.1",
- "to-object-path": "^0.3.0"
- }
- }
+ "set-value": "^2.0.1"
}
},
"universal-path": {