commit
68673957ed
11 changed files with 4115 additions and 1377 deletions
7
QA.md
7
QA.md
|
@ -20,10 +20,8 @@ The behaviors of the console are tested in [Console section](#consoles).
|
||||||
|
|
||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
- [ ] Configure custom hint character by `:set hintchars=012345678`
|
- [ ] Toggle smooth scroll by `:set smoothscroll` and `:set nosmoothscroll`
|
||||||
- [ ] Smooth scroll by `:set smoothscroll`
|
- [ ] Configure smooth scroll by settings `"smoothscroll": true` and `"smoothscroll": false`
|
||||||
- [ ] Non-smooth scroll by `:set nosmoothscroll`
|
|
||||||
- [ ] Configure smooth scroll by settings `"smoothscroll": true`, `"smoothscroll": false`
|
|
||||||
|
|
||||||
### Settings
|
### Settings
|
||||||
|
|
||||||
|
@ -45,7 +43,6 @@ The behaviors of the console are tested in [Console section](#consoles).
|
||||||
##### Updating
|
##### Updating
|
||||||
|
|
||||||
- [ ] changes are updated on textarea blure when no errors
|
- [ ] changes are updated on textarea blure when no errors
|
||||||
- [ ] changes are not updated on textarea blure when errors occurs
|
|
||||||
- [ ] keymap settings are applied to open tabs without reload
|
- [ ] keymap settings are applied to open tabs without reload
|
||||||
- [ ] search settings are applied to open tabs without reload
|
- [ ] search settings are applied to open tabs without reload
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ const lanthan = require('lanthan');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const eventually = require('./eventually');
|
const eventually = require('./eventually');
|
||||||
|
const Console = require('./lib/Console');
|
||||||
|
|
||||||
const Key = lanthan.Key;
|
const Key = lanthan.Key;
|
||||||
|
|
||||||
|
@ -114,7 +115,6 @@ describe('follow properties test', () => {
|
||||||
assert.equal(await hints[2].getStyle('display'), 'block');
|
assert.equal(await hints[2].getStyle('display'), 'block');
|
||||||
assert.equal(await hints[3].getStyle('display'), 'block');
|
assert.equal(await hints[3].getStyle('display'), 'block');
|
||||||
assert.equal(await hints[4].getStyle('display'), 'none');
|
assert.equal(await hints[4].getStyle('display'), 'none');
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -147,4 +147,36 @@ describe('follow properties test', () => {
|
||||||
assert.equal(tabs[1].active, false);
|
assert.equal(tabs[1].active, false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should show hints with hintchars by settings', async () => {
|
||||||
|
let c = new Console(session);
|
||||||
|
|
||||||
|
await body.sendKeys(':');
|
||||||
|
await session.switchToFrame(0);
|
||||||
|
await c.sendKeys('set hintchars=abc', Key.Enter);
|
||||||
|
await session.switchToParentFrame();
|
||||||
|
|
||||||
|
await body.sendKeys('f');
|
||||||
|
await eventually(async() => {
|
||||||
|
let hints = await session.findElementsByCSS('.vimvixen-hint');
|
||||||
|
assert.equal(hints.length, 5);
|
||||||
|
|
||||||
|
assert.equal(await hints[0].getText(), 'A');
|
||||||
|
assert.equal(await hints[1].getText(), 'B');
|
||||||
|
assert.equal(await hints[2].getText(), 'C');
|
||||||
|
assert.equal(await hints[3].getText(), 'AA');
|
||||||
|
assert.equal(await hints[4].getText(), 'AB');
|
||||||
|
});
|
||||||
|
|
||||||
|
await body.sendKeys('a');
|
||||||
|
await eventually(async() => {
|
||||||
|
let hints = await session.findElementsByCSS('.vimvixen-hint');
|
||||||
|
|
||||||
|
assert.equal(await hints[0].getStyle('display'), 'block');
|
||||||
|
assert.equal(await hints[1].getStyle('display'), 'none');
|
||||||
|
assert.equal(await hints[2].getStyle('display'), 'none');
|
||||||
|
assert.equal(await hints[3].getStyle('display'), 'block');
|
||||||
|
assert.equal(await hints[4].getStyle('display'), 'block');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
5371
package-lock.json
generated
5371
package-lock.json
generated
File diff suppressed because it is too large
Load diff
12
package.json
12
package.json
|
@ -24,16 +24,16 @@
|
||||||
"@types/chai": "^4.1.7",
|
"@types/chai": "^4.1.7",
|
||||||
"@types/mocha": "^5.2.6",
|
"@types/mocha": "^5.2.6",
|
||||||
"@types/prop-types": "^15.7.1",
|
"@types/prop-types": "^15.7.1",
|
||||||
"@types/react": "^16.8.15",
|
"@types/react": "^16.8.18",
|
||||||
"@types/react-dom": "^16.8.4",
|
"@types/react-dom": "^16.8.4",
|
||||||
"@types/react-redux": "^7.0.8",
|
"@types/react-redux": "^7.0.9",
|
||||||
"@types/redux-promise": "^0.5.28",
|
"@types/redux-promise": "^0.5.28",
|
||||||
"@types/sinon": "^7.0.11",
|
"@types/sinon": "^7.0.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^1.9.0",
|
"@typescript-eslint/eslint-plugin": "^1.9.0",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"css-loader": "^2.1.1",
|
"css-loader": "^2.1.1",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-plugin-react": "^7.12.4",
|
"eslint-plugin-react": "^7.13.0",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"jszip": "^3.2.1",
|
"jszip": "^3.2.1",
|
||||||
"karma": "^4.1.0",
|
"karma": "^4.1.0",
|
||||||
|
@ -62,8 +62,8 @@
|
||||||
"tsyringe": "^3.2.0",
|
"tsyringe": "^3.2.0",
|
||||||
"typescript": "^3.4.5",
|
"typescript": "^3.4.5",
|
||||||
"web-ext-types": "^3.1.0",
|
"web-ext-types": "^3.1.0",
|
||||||
"webextensions-api-fake": "^0.7.4",
|
"webextensions-api-fake": "^0.8.0",
|
||||||
"webpack": "^4.30.0",
|
"webpack": "^4.32.2",
|
||||||
"webpack-cli": "^3.3.1"
|
"webpack-cli": "^3.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@ export default class CompletionsUseCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
async queryOpen(name: string, keywords: string): Promise<CompletionGroup[]> {
|
async queryOpen(name: string, keywords: string): Promise<CompletionGroup[]> {
|
||||||
|
// TODO This logic contains view entities. They should be defined on
|
||||||
|
// content script
|
||||||
|
|
||||||
let settings = await this.settingRepository.get();
|
let settings = await this.settingRepository.get();
|
||||||
let groups: CompletionGroup[] = [];
|
let groups: CompletionGroup[] = [];
|
||||||
|
|
||||||
|
@ -195,7 +198,7 @@ export default class CompletionsUseCase {
|
||||||
.map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT))
|
.map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT))
|
||||||
.map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0]
|
.map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0]
|
||||||
.sort((x: HistoryItem, y: HistoryItem): number => {
|
.sort((x: HistoryItem, y: HistoryItem): number => {
|
||||||
return Number(x.visitCount) - Number(y.visitCount);
|
return Number(y.visitCount) - Number(x.visitCount);
|
||||||
})
|
})
|
||||||
.slice(0, COMPLETION_ITEM_LIMIT);
|
.slice(0, COMPLETION_ITEM_LIMIT);
|
||||||
return histories.map(page => ({
|
return histories.map(page => ({
|
||||||
|
|
|
@ -63,16 +63,16 @@ export default class FollowSlaveUseCase {
|
||||||
|
|
||||||
if (hint instanceof LinkHint) {
|
if (hint instanceof LinkHint) {
|
||||||
let url = hint.getLink();
|
let url = hint.getLink();
|
||||||
// ignore taget='_blank'
|
let openNewTab = newTab;
|
||||||
if (!newTab && hint.getLinkTarget() === '_blank') {
|
// Open link by background script in order to prevent a popup block
|
||||||
hint.click();
|
if (hint.getLinkTarget() === '_blank') {
|
||||||
return;
|
openNewTab = true;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-script-url
|
// eslint-disable-next-line no-script-url
|
||||||
if (!url || url === '#' || url.toLowerCase().startsWith('javascript:')) {
|
if (!url || url === '#' || url.toLowerCase().startsWith('javascript:')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.tabsClient.openUrl(url, newTab, background);
|
await this.tabsClient.openUrl(url, openNewTab, background);
|
||||||
} else if (hint instanceof InputHint) {
|
} else if (hint instanceof InputHint) {
|
||||||
hint.activate();
|
hint.activate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ class SearchForm extends React.Component<Props> {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-statements
|
||||||
bindValue(e: any) {
|
bindValue(e: any) {
|
||||||
let value = this.props.value.toJSON();
|
let value = this.props.value.toJSON();
|
||||||
let name = e.target.name;
|
let name = e.target.name;
|
||||||
|
@ -72,8 +73,12 @@ class SearchForm extends React.Component<Props> {
|
||||||
next.default = value.engines[index][0];
|
next.default = value.engines[index][0];
|
||||||
} else if (name === 'add') {
|
} else if (name === 'add') {
|
||||||
next.engines.push(['', '']);
|
next.engines.push(['', '']);
|
||||||
} else if (name === 'delete') {
|
} else if (name === 'delete' && value.engines.length > 1) {
|
||||||
next.engines.splice(index, 1);
|
next.engines.splice(index, 1);
|
||||||
|
if (value.engines[index][0] === value.default) {
|
||||||
|
let nextIndex = Math.min(index, next.engines.length - 1);
|
||||||
|
next.default = next.engines[nextIndex][0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onChange(FormSearch.valueOf(next));
|
this.props.onChange(FormSearch.valueOf(next));
|
||||||
|
|
|
@ -175,6 +175,7 @@ class SettingsComponent extends React.Component<Props> {
|
||||||
if (from === 'form' && value === 'json') {
|
if (from === 'form' && value === 'json') {
|
||||||
this.props.dispatch(settingActions.switchToJson(
|
this.props.dispatch(settingActions.switchToJson(
|
||||||
this.props.form as FormSettings));
|
this.props.form as FormSettings));
|
||||||
|
this.save();
|
||||||
} else if (from === 'json' && value === 'form') {
|
} else if (from === 'json' && value === 'form') {
|
||||||
let b = window.confirm(DO_YOU_WANT_TO_CONTINUE);
|
let b = window.confirm(DO_YOU_WANT_TO_CONTINUE);
|
||||||
if (!b) {
|
if (!b) {
|
||||||
|
@ -183,6 +184,7 @@ class SettingsComponent extends React.Component<Props> {
|
||||||
}
|
}
|
||||||
this.props.dispatch(
|
this.props.dispatch(
|
||||||
settingActions.switchToForm(this.props.json as JSONSettings));
|
settingActions.switchToForm(this.props.json as JSONSettings));
|
||||||
|
this.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable max-len */
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
[
|
[
|
||||||
['scroll.vertically?{"count":1}', 'Scroll down'],
|
['scroll.vertically?{"count":1}', 'Scroll down'],
|
||||||
|
@ -19,8 +21,8 @@ const fields = [
|
||||||
['tabs.close', 'Close a tab'],
|
['tabs.close', 'Close a tab'],
|
||||||
['tabs.close.right', 'Close tabs to the right'],
|
['tabs.close.right', 'Close tabs to the right'],
|
||||||
['tabs.reopen', 'Reopen closed tab'],
|
['tabs.reopen', 'Reopen closed tab'],
|
||||||
['tabs.next?{"count":1}', 'Select next Tab'],
|
['tabs.next', 'Select next Tab'],
|
||||||
['tabs.prev?{"count":1}', 'Select prev Tab'],
|
['tabs.prev', 'Select prev Tab'],
|
||||||
['tabs.first', 'Select first tab'],
|
['tabs.first', 'Select first tab'],
|
||||||
['tabs.last', 'Select last tab'],
|
['tabs.last', 'Select last tab'],
|
||||||
['tabs.reload?{"cache":false}', 'Reload current tab'],
|
['tabs.reload?{"cache":false}', 'Reload current tab'],
|
||||||
|
@ -28,8 +30,8 @@ const fields = [
|
||||||
['tabs.pin.toggle', 'Toggle pinned state'],
|
['tabs.pin.toggle', 'Toggle pinned state'],
|
||||||
['tabs.duplicate', 'Duplicate a tab'],
|
['tabs.duplicate', 'Duplicate a tab'],
|
||||||
], [
|
], [
|
||||||
['follow.start?{"newTab":false}', 'Follow a link'],
|
['follow.start?{"newTab":false,"background":false}', 'Follow a link'],
|
||||||
['follow.start?{"newTab":true}', 'Follow a link in new tab'],
|
['follow.start?{"newTab":true,"background":false}', 'Follow a link in new tab'],
|
||||||
['navigate.history.prev', 'Go back in histories'],
|
['navigate.history.prev', 'Go back in histories'],
|
||||||
['navigate.history.next', 'Go forward in histories'],
|
['navigate.history.next', 'Go forward in histories'],
|
||||||
['navigate.link.next', 'Open next link'],
|
['navigate.link.next', 'Open next link'],
|
||||||
|
@ -37,7 +39,7 @@ const fields = [
|
||||||
['navigate.parent', 'Go to parent directory'],
|
['navigate.parent', 'Go to parent directory'],
|
||||||
['navigate.root', 'Go to root directory'],
|
['navigate.root', 'Go to root directory'],
|
||||||
['page.source', 'Open page source'],
|
['page.source', 'Open page source'],
|
||||||
['page.home', 'Open start page to current tab'],
|
['page.home?{"newTab":false}', 'Open start page to current tab'],
|
||||||
['page.home?{"newTab":true}', 'Open start page in new tab'],
|
['page.home?{"newTab":true}', 'Open start page in new tab'],
|
||||||
['focus.input', 'Focus input'],
|
['focus.input', 'Focus input'],
|
||||||
], [
|
], [
|
||||||
|
|
|
@ -101,17 +101,23 @@ export const blacklistValueOf = (o: any): string[] => {
|
||||||
|
|
||||||
export const valueOf = (o: any): Settings => {
|
export const valueOf = (o: any): Settings => {
|
||||||
let settings = { ...DefaultSetting };
|
let settings = { ...DefaultSetting };
|
||||||
if (Object.prototype.hasOwnProperty.call(o, 'keymaps')) {
|
for (let key of Object.keys(o)) {
|
||||||
|
switch (key) {
|
||||||
|
case 'keymaps':
|
||||||
settings.keymaps = keymapsValueOf(o.keymaps);
|
settings.keymaps = keymapsValueOf(o.keymaps);
|
||||||
}
|
break;
|
||||||
if (Object.prototype.hasOwnProperty.call(o, 'search')) {
|
case 'search':
|
||||||
settings.search = searchValueOf(o.search);
|
settings.search = searchValueOf(o.search);
|
||||||
}
|
break;
|
||||||
if (Object.prototype.hasOwnProperty.call(o, 'properties')) {
|
case 'properties':
|
||||||
settings.properties = propertiesValueOf(o.properties);
|
settings.properties = propertiesValueOf(o.properties);
|
||||||
}
|
break;
|
||||||
if (Object.prototype.hasOwnProperty.call(o, 'blacklist')) {
|
case 'blacklist':
|
||||||
settings.blacklist = blacklistValueOf(o.blacklist);
|
settings.blacklist = blacklistValueOf(o.blacklist);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new TypeError('unknown setting: ' + key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return settings;
|
return settings;
|
||||||
};
|
};
|
||||||
|
|
|
@ -186,5 +186,9 @@ describe('Settings', () => {
|
||||||
expect(value.search.engines).to.be.an('object');
|
expect(value.search.engines).to.be.an('object');
|
||||||
expect(value.blacklist).to.be.empty;
|
expect(value.blacklist).to.be.empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws a TypeError with an unknown field', () => {
|
||||||
|
expect(() => settings.valueOf({ name: 'alice' })).to.throw(TypeError)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Reference in a new issue