diff --git a/QA.md b/QA.md
index 98b8239..8676d06 100644
--- a/QA.md
+++ b/QA.md
@@ -4,10 +4,6 @@
Test operations with default key maps.
-#### Console
-
-The behaviors of the console are tested in [Console section](#consoles).
-
#### Misc
- [ ] Toggle enabled/disabled of plugin bu Shift+Esc
@@ -27,10 +23,6 @@ The behaviors of the console are tested in [Console section](#consoles).
#### Form Settings
-##### `"blacklist"` section
-
-- [ ] `github.com/a` blocks `github.com/a`, and not blocks `github.com/aa`
-
##### Updating
- [ ] keymap settings are applied to open tabs without reload
diff --git a/docs/blacklist.md b/docs/blacklist.md
index b854c07..6fede63 100644
--- a/docs/blacklist.md
+++ b/docs/blacklist.md
@@ -4,6 +4,8 @@ title: Blacklist
# Blacklist
+## Blacklist
+
The blacklist allows you to disable the plugin for certain pages by URL patterns.
For instance, you could use `"*.slack.com"` to disable the plugin on all Slack channels.
In addition, you can also specify path patterns, such as `"example.com/mail/*"`.
@@ -19,3 +21,20 @@ In addition, you can also specify path patterns, such as `"example.com/mail/*"`.
You can toggle Vim Vixen between disabled and enabled with
shift+Esc.
+
+## Partial Blacklist
+
+The partial blacklist disables certain keys for each webpage separately.
+This is enabled by describing object with `"url"` and `"keys"` instead of a string in the blacklist.
+To disable j and k keys (scroll down and up) on github.com as an example, describe target url and disabled keys as the following:
+
+```json
+{
+ "blacklist" [
+ { "url": "github.com", "keys": ["j", "k"] }
+ ]
+}
+```
+
+The partial blacklist blocks all operations starting with the keys but not exactly-matched.
+That means if the g described in "keys" field, it block all operation starting with g, such as gg, gt, and gT.
diff --git a/docs/console_commands.md b/docs/console_commands.md
index 272ea0e..bf8f424 100644
--- a/docs/console_commands.md
+++ b/docs/console_commands.md
@@ -10,6 +10,10 @@ Open the console with :. Or populate it with initial values using
o/O, t/T, or
w/W.
+## `:help`
+
+Open a [Vim Vixen official document](https://ueokande.github.io/vim-vixen/) in a new tab.
+
## `:open`
The `:open` command operates two different ways, depending on the parameter.
diff --git a/e2e/lib/FormOptionPage.ts b/e2e/lib/FormOptionPage.ts
index c49a44f..7d981f4 100644
--- a/e2e/lib/FormOptionPage.ts
+++ b/e2e/lib/FormOptionPage.ts
@@ -8,13 +8,31 @@ export default class FormOptionPage {
this.webdriver = lanthan.getWebDriver();
}
- async setBlacklist(nth: number, value: string): Promise {
+ async setBlacklist(nth: number, url: string): Promise {
let selector = '.form-blacklist-form-row > .column-url';
let inputs = await this.webdriver.findElements(By.css(selector));
if (inputs.length <= nth) {
throw new RangeError('Index out of range to set a blacklist')
}
- await inputs[nth].sendKeys(value);
+ await inputs[nth].sendKeys(url);
+ await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`);
+ }
+
+ async setPartialBlacklist(nth: number, url: string, keys: string): Promise {
+ let selector = '.form-partial-blacklist-form-row > .column-url';
+ let inputs = await this.webdriver.findElements(By.css(selector));
+ if (inputs.length <= nth) {
+ throw new RangeError('Index out of range to set a partial blacklist')
+ }
+ await inputs[nth].sendKeys(url);
+ await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`);
+
+ selector = '.form-partial-blacklist-form-row > .column-keys';
+ inputs = await this.webdriver.findElements(By.css(selector));
+ if (inputs.length <= nth) {
+ throw new RangeError('Index out of range to set a partial blacklist')
+ }
+ await inputs[nth].sendKeys(keys);
await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`);
}
@@ -43,6 +61,13 @@ export default class FormOptionPage {
await this.webdriver.wait(until.elementLocated(By.css(`.form-blacklist-form-row:nth-child(${rows.length + 1})`)));
}
+ async addPartialBlacklist(): Promise {
+ let rows = await this.webdriver.findElements(By.css(`.form-partial-blacklist-form-row`));
+ let button = await this.webdriver.findElement(By.css('.form-partial-blacklist-form .ui-add-button'))
+ await button.click();
+ await this.webdriver.wait(until.elementLocated(By.css(`.form-partial-blacklist-form-row:nth-child(${rows.length + 2})`)));
+ }
+
async removeBlackList(nth: number): Promise {
let buttons = await this.webdriver.findElements(By.css('.form-blacklist-form-row .ui-delete-button'));
if (buttons.length <= nth) {
@@ -51,6 +76,14 @@ export default class FormOptionPage {
await buttons[nth].click()
}
+ async removePartialBlackList(nth: number): Promise {
+ let buttons = await this.webdriver.findElements(By.css('.form-partial-blacklist-form-row .ui-delete-button'));
+ if (buttons.length <= nth) {
+ throw new RangeError('Index out of range to remove partial blacklist')
+ }
+ await buttons[nth].click()
+ }
+
async addSearchEngine(): Promise {
let rows = await this.webdriver.findElements(By.css(`.form-search-form-row > .column-name`));
let button = await this.webdriver.findElement(By.css('.form-search-form > .ui-add-button'))
diff --git a/e2e/options_form.test.ts b/e2e/options_form.test.ts
index 6023f9c..c3dc5fb 100644
--- a/e2e/options_form.test.ts
+++ b/e2e/options_form.test.ts
@@ -35,7 +35,7 @@ describe("options form page", () => {
assert.strictEqual(settings.source, 'form')
});
- it('add blacklist', async () => {
+ it('add blacklist item', async () => {
let page = await OptionPage.open(lanthan);
let forms = await page.switchToForm();
// Scroll is required to click a button on Firefox 60
@@ -64,6 +64,53 @@ describe("options form page", () => {
assert.deepStrictEqual(settings.form.blacklist, ['yahoo.com'])
});
+ it('add a partial blacklist item', async () => {
+ let page = await OptionPage.open(lanthan);
+ let forms = await page.switchToForm();
+ // Scroll is required to click a button on Firefox 60
+ await page.scrollTo(0, 1000);
+
+ // assert default
+ let settings = (await browser.storage.local.get('settings')).settings;
+ assert.deepStrictEqual(settings.form.blacklist, []);
+
+ // add blacklist items
+ await forms.addPartialBlacklist();
+ await forms.setPartialBlacklist(0, 'google.com', 'j,k,');
+
+ settings = (await browser.storage.local.get('settings')).settings;
+ assert.deepStrictEqual(settings.form.blacklist, [
+ { url: 'google.com', keys: ['j', 'k', ''] },
+ ]);
+
+ await forms.addPartialBlacklist();
+ await forms.setPartialBlacklist(1, 'yahoo.com', 'g,G');
+
+ settings = (await browser.storage.local.get('settings')).settings;
+ assert.deepStrictEqual(settings.form.blacklist, [
+ { url: 'google.com', keys: ['j', 'k', ''] },
+ { url: 'yahoo.com', keys: ['g', 'G'] },
+ ]);
+
+ await forms.addBlacklist();
+ await forms.setBlacklist(0, 'bing.com');
+
+ settings = (await browser.storage.local.get('settings')).settings;
+ assert.deepStrictEqual(settings.form.blacklist, [
+ { url: 'google.com', keys: ['j', 'k', ''] },
+ { url: 'yahoo.com', keys: ['g', 'G'] },
+ 'bing.com',
+ ]);
+
+ // delete first item
+ await forms.removePartialBlackList(0);
+ settings = (await browser.storage.local.get('settings')).settings;
+ assert.deepStrictEqual(settings.form.blacklist, [
+ { url: 'yahoo.com', keys: ['g', 'G'] },
+ 'bing.com',
+ ])
+ });
+
it('add search engines', async () => {
let page = await OptionPage.open(lanthan);
let forms = await page.switchToForm();