Add an option to close the current tab and select the tab to the left

Add an option to tabs.close to close the current tab
and select the tab to the left.

Bound to `D` by default, which replaces the tabs.close.right
command, which is rarely-used. [1]

The old `D` behavior has been moved to `gd`.

+ update the README and fix some lint errors

[1] https://tinyurl.com/y4mj7hjy
This commit is contained in:
chocolateboy 2019-07-28 05:35:07 +01:00
parent 3db11041c5
commit 6605d3ea99
10 changed files with 163 additions and 120 deletions

View file

@ -32,7 +32,7 @@ export default class OperationController {
doOperation(operation: operations.Operation): Promise<any> {
switch (operation.type) {
case operations.TAB_CLOSE:
return this.tabUseCase.close(false);
return this.tabUseCase.close(false, operation.selectLeft);
case operations.TAB_CLOSE_RIGHT:
return this.tabUseCase.closeRight();
case operations.TAB_CLOSE_FORCE:

View file

@ -12,11 +12,15 @@ export default class TabUseCase {
) {
}
async close(force: boolean): Promise<any> {
async close(force: boolean, selectLeft = false): Promise<any> {
let tab = await this.tabPresenter.getCurrent();
if (!force && tab.pinned) {
return Promise.resolve();
}
if (selectLeft && tab.index > 0) {
let tabs = await this.tabPresenter.getAll();
await this.tabPresenter.select(tabs[tab.index - 1].id as number);
}
return this.tabPresenter.remove([tab.id as number]);
}

View file

@ -90,7 +90,7 @@ class Scroller {
clearTimeout(lastTimeoutId);
lastTimeoutId = null;
}
lastTimeoutId = setTimeout(resetScrolling, 100);
lastTimeoutId = window.setTimeout(resetScrolling, 100);
}
}

View file

@ -18,11 +18,11 @@ const fields = [
['mark.set.prefix', 'Set mark at current position'],
['mark.jump.prefix', 'Jump to the mark'],
], [
['tabs.close', 'Close a tab'],
['tabs.close.right', 'Close tabs to the right'],
['tabs.close?{"selectLeft":false}', 'Close a tab'],
['tabs.close.right', 'Close all tabs to the right'],
['tabs.reopen', 'Reopen closed tab'],
['tabs.next', 'Select next Tab'],
['tabs.prev', 'Select prev Tab'],
['tabs.next', 'Select next tab'],
['tabs.prev', 'Select prev tab'],
['tabs.first', 'Select first tab'],
['tabs.last', 'Select last tab'],
['tabs.reload?{"cache":false}', 'Reload current tab'],
@ -50,8 +50,8 @@ const fields = [
['command.show', 'Open console'],
['command.show.open?{"alter":false}', 'Open URL'],
['command.show.open?{"alter":true}', 'Alter URL'],
['command.show.tabopen?{"alter":false}', 'Open URL in new Tab'],
['command.show.tabopen?{"alter":true}', 'Alter URL in new Tab'],
['command.show.tabopen?{"alter":false}', 'Open URL in new tab'],
['command.show.tabopen?{"alter":true}', 'Alter URL in new tab'],
['command.show.winopen?{"alter":false}', 'Open URL in new window'],
['command.show.winopen?{"alter":true}', 'Alter URL in new window'],
['command.show.buffer', 'Open buffer command'],

View file

@ -353,7 +353,8 @@ export const DefaultSettingData: SettingData = SettingData.valueOf({
"G": { "type": "scroll.bottom" },
"$": { "type": "scroll.end" },
"d": { "type": "tabs.close" },
"D": { "type": "tabs.close.right" },
"D": { "type": "tabs.close", "selectLeft": true },
"gd": { "type": "tabs.close.right" },
"!d": { "type": "tabs.close.force" },
"u": { "type": "tabs.reopen" },
"K": { "type": "tabs.prev" },

View file

@ -146,7 +146,8 @@ export const DefaultSetting: Settings = {
'G': { 'type': 'scroll.bottom' },
'$': { 'type': 'scroll.end' },
'd': { 'type': 'tabs.close' },
'D': { 'type': 'tabs.close.right' },
'D': { 'type': 'tabs.close', 'selectLeft': true },
'gd': { 'type': 'tabs.close.right' },
'!d': { 'type': 'tabs.close.force' },
'u': { 'type': 'tabs.reopen' },
'K': { 'type': 'tabs.prev' },

View file

@ -201,6 +201,7 @@ export interface PageHomeOperation {
export interface TabCloseOperation {
type: typeof TAB_CLOSE;
selectLeft?: boolean;
}
export interface TabCloseForceOperation {
@ -367,28 +368,28 @@ export type Operation =
const assertOptionalBoolean = (obj: any, name: string) => {
if (Object.prototype.hasOwnProperty.call(obj, name) &&
typeof obj[name] !== 'boolean') {
throw new TypeError(`Not a boolean parameter '${name}'`);
throw new TypeError(`Not a boolean parameter: '${name}'`);
}
};
const assertRequiredNumber = (obj: any, name: string) => {
if (!Object.prototype.hasOwnProperty.call(obj, name) ||
typeof obj[name] !== 'number') {
throw new TypeError(`Missing number parameter '${name}`);
throw new TypeError(`Missing number parameter: '${name}`);
}
};
const assertRequiredString = (obj: any, name: string) => {
if (!Object.prototype.hasOwnProperty.call(obj, name) ||
typeof obj[name] !== 'string') {
throw new TypeError(`Missing string parameter '${name}`);
throw new TypeError(`Missing string parameter: '${name}`);
}
};
// eslint-disable-next-line complexity, max-lines-per-function
export const valueOf = (o: any): Operation => {
if (!Object.prototype.hasOwnProperty.call(o, 'type')) {
throw new TypeError(`missing 'type' field`);
throw new TypeError(`Missing 'type' field`);
}
switch (o.type) {
case COMMAND_SHOW_OPEN:
@ -416,6 +417,12 @@ export const valueOf = (o: any): Operation => {
type: PAGE_HOME,
newTab: Boolean(typeof o.newTab === undefined ? false : o.newTab),
};
case TAB_CLOSE:
assertOptionalBoolean(o, 'selectLeft');
return {
type: TAB_CLOSE,
selectLeft: Boolean(typeof o.selectLeft === undefined ? false : o.selectLeft), // eslint-disable-line max-len
};
case TAB_RELOAD:
assertOptionalBoolean(o, 'cache');
return {
@ -458,7 +465,6 @@ export const valueOf = (o: any): Operation => {
case NAVIGATE_ROOT:
case FOCUS_INPUT:
case PAGE_SOURCE:
case TAB_CLOSE:
case TAB_CLOSE_FORCE:
case TAB_CLOSE_RIGHT:
case TAB_REOPEN:
@ -483,5 +489,5 @@ export const valueOf = (o: any): Operation => {
case REPEAT_LAST:
return { type: o.type };
}
throw new TypeError('unknown operation type: ' + o.type);
throw new TypeError('Unknown operation type: ' + o.type);
};