From 764d7a34bda121f97e947861c41722a12af37b15 Mon Sep 17 00:00:00 2001 From: usk Date: Sun, 5 Nov 2017 10:06:26 +0900 Subject: [PATCH 001/178] add support for following some buttons on mobile.twitter.com The buttons are: * reply * retweet * favorite * direct message * drop down menu --- src/content/components/common/follow.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content/components/common/follow.js b/src/content/components/common/follow.js index 83aeb0a..15b2a98 100644 --- a/src/content/components/common/follow.js +++ b/src/content/components/common/follow.js @@ -4,7 +4,8 @@ import * as dom from 'shared/utils/dom'; const TARGET_SELECTOR = [ 'a', 'button', 'input', 'textarea', 'area', - '[contenteditable=true]', '[contenteditable=""]', '[tabindex]' + '[contenteditable=true]', '[contenteditable=""]', '[tabindex]', + '[role="button"]' ].join(','); From b1d186b66216106329f1301e29892c1cac0fd9d2 Mon Sep 17 00:00:00 2001 From: Shinya Ohyanagi Date: Wed, 15 Nov 2017 22:42:09 +0900 Subject: [PATCH 002/178] Add c-n, c-p, c-m to console Add `c-n`, `c-j` for select next item. Add `c-p`, `c-k` for select previous item. Add `c-m` for select item. Above console keybinds are same as Vim(Vimperator)'s completion selector. --- src/console/components/console.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/console/components/console.js b/src/console/components/console.js index 7bc3364..cabd229 100644 --- a/src/console/components/console.js +++ b/src/console/components/console.js @@ -48,6 +48,34 @@ export default class ConsoleComponent { e.stopPropagation(); e.preventDefault(); break; + case KeyboardEvent.DOM_VK_OPEN_BRACKET: + if (e.ctrlKey) { + return this.hideCommand(); + } + break; + case KeyboardEvent.DOM_VK_M: + if (e.ctrlKey) { + e.stopPropagation(); + e.preventDefault(); + return this.onEntered(e.target.value); + } + break; + case KeyboardEvent.DOM_VK_N: + case KeyboardEvent.DOM_VK_J: + if (e.ctrlKey) { + this.store.dispatch(consoleActions.completionNext()); + e.stopPropagation(); + e.preventDefault(); + } + break; + case KeyboardEvent.DOM_VK_P: + case KeyboardEvent.DOM_VK_K: + if (e.ctrlKey) { + this.store.dispatch(consoleActions.completionPrev()); + e.stopPropagation(); + e.preventDefault(); + } + break; } } From f32dce829c90f67776c6827a8f7e493615a88aaf Mon Sep 17 00:00:00 2001 From: Shinya Ohyanagi Date: Thu, 16 Nov 2017 21:50:44 +0900 Subject: [PATCH 003/178] Add allow up and down to move cursor Also refactor methods. --- src/console/components/console.js | 40 +++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/console/components/console.js b/src/console/components/console.js index cabd229..7c1976e 100644 --- a/src/console/components/console.js +++ b/src/console/components/console.js @@ -31,14 +31,30 @@ export default class ConsoleComponent { } } + doEnter(e) { + e.stopPropagation(); + e.preventDefault(); + return this.onEntered(e.target.value); + } + + selectNext(e) { + this.store.dispatch(consoleActions.completionNext()); + e.stopPropagation(); + e.preventDefault(); + } + + selectPrev(e) { + this.store.dispatch(consoleActions.completionPrev()); + e.stopPropagation(); + e.preventDefault(); + } + onKeyDown(e) { switch (e.keyCode) { case KeyboardEvent.DOM_VK_ESCAPE: return this.hideCommand(); case KeyboardEvent.DOM_VK_RETURN: - e.stopPropagation(); - e.preventDefault(); - return this.onEntered(e.target.value); + return this.doEnter(e); case KeyboardEvent.DOM_VK_TAB: if (e.shiftKey) { this.store.dispatch(consoleActions.completionPrev()); @@ -55,25 +71,25 @@ export default class ConsoleComponent { break; case KeyboardEvent.DOM_VK_M: if (e.ctrlKey) { - e.stopPropagation(); - e.preventDefault(); - return this.onEntered(e.target.value); + this.doEnter(e); } break; + case KeyboardEvent.DOM_VK_DOWN: + this.selectNext(e); + break; case KeyboardEvent.DOM_VK_N: case KeyboardEvent.DOM_VK_J: if (e.ctrlKey) { - this.store.dispatch(consoleActions.completionNext()); - e.stopPropagation(); - e.preventDefault(); + this.selectNext(e); } break; + case KeyboardEvent.DOM_VK_UP: + this.selectPrev(e); + break; case KeyboardEvent.DOM_VK_P: case KeyboardEvent.DOM_VK_K: if (e.ctrlKey) { - this.store.dispatch(consoleActions.completionPrev()); - e.stopPropagation(); - e.preventDefault(); + this.selectPrev(e); } break; } From 177940981ed9c4f096ad7db20f0b7ee044fd7b17 Mon Sep 17 00:00:00 2001 From: Erwan Ameil Date: Thu, 16 Nov 2017 13:03:38 +0000 Subject: [PATCH 004/178] Open adjacent tabs and background tabs --- src/background/actions/tab.js | 6 +----- src/background/components/background.js | 3 ++- src/content/actions/follow-controller.js | 3 ++- src/content/actions/operation.js | 3 ++- src/content/components/common/follow.js | 8 ++++++-- .../top-content/follow-controller.js | 3 ++- src/content/reducers/follow-controller.js | 2 ++ src/shared/commands.js | 20 +++++++++++++++---- src/shared/default-settings.js | 7 ++++--- src/shared/validators/setting.js | 2 +- 10 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/background/actions/tab.js b/src/background/actions/tab.js index e512b6f..d996b9f 100644 --- a/src/background/actions/tab.js +++ b/src/background/actions/tab.js @@ -1,9 +1,5 @@ -const openNewTab = (url) => { - return browser.tabs.create({ url: url }); -}; - const openToTab = (url, tab) => { return browser.tabs.update(tab.id, { url: url }); }; -export { openToTab, openNewTab }; +export { openToTab }; diff --git a/src/background/components/background.js b/src/background/components/background.js index 2d94310..6026684 100644 --- a/src/background/components/background.js +++ b/src/background/components/background.js @@ -30,7 +30,8 @@ export default class BackgroundComponent { case messages.OPEN_URL: if (message.newTab) { return this.store.dispatch( - tabActions.openNewTab(message.url), sender); + commands.tabopenCommand(message.url, message.background, + settings.value.openAdjacentTabs), sender); } return this.store.dispatch( tabActions.openToTab(message.url, sender.tab), sender); diff --git a/src/content/actions/follow-controller.js b/src/content/actions/follow-controller.js index 3fd4dce..006b248 100644 --- a/src/content/actions/follow-controller.js +++ b/src/content/actions/follow-controller.js @@ -1,9 +1,10 @@ import actions from 'content/actions'; -const enable = (newTab) => { +const enable = (newTab, background) => { return { type: actions.FOLLOW_CONTROLLER_ENABLE, newTab, + background, }; }; diff --git a/src/content/actions/operation.js b/src/content/actions/operation.js index 767f14b..5c8fe83 100644 --- a/src/content/actions/operation.js +++ b/src/content/actions/operation.js @@ -40,7 +40,8 @@ const exec = (operation) => { case operations.FOLLOW_START: return window.top.postMessage(JSON.stringify({ type: messages.FOLLOW_START, - newTab: operation.newTab + newTab: operation.newTab, + background: operation.background, }), '*'); case operations.NAVIGATE_HISTORY_PREV: return navigates.historyPrev(window); diff --git a/src/content/components/common/follow.js b/src/content/components/common/follow.js index 7a35105..43f2ea1 100644 --- a/src/content/components/common/follow.js +++ b/src/content/components/common/follow.js @@ -34,6 +34,7 @@ export default class Follow { this.win = win; this.store = store; this.newTab = false; + this.background = false; this.hints = {}; this.targets = []; @@ -68,6 +69,7 @@ export default class Follow { type: messages.OPEN_URL, url: element.href, newTab: true, + background: this.background, }); } @@ -79,12 +81,13 @@ export default class Follow { }), '*'); } - createHints(keysArray, newTab) { + createHints(keysArray, newTab, background) { if (keysArray.length !== this.targets.length) { throw new Error('illegal hint count'); } this.newTab = newTab; + this.background = background; this.hints = {}; for (let i = 0; i < keysArray.length; ++i) { let keys = keysArray[i]; @@ -150,7 +153,8 @@ export default class Follow { case messages.FOLLOW_REQUEST_COUNT_TARGETS: return this.countHints(sender, message.viewSize, message.framePosition); case messages.FOLLOW_CREATE_HINTS: - return this.createHints(message.keysArray, message.newTab); + return this.createHints( + message.keysArray, message.newTab, message.background); case messages.FOLLOW_SHOW_HINTS: return this.showHints(message.keys); case messages.FOLLOW_ACTIVATE: diff --git a/src/content/components/top-content/follow-controller.js b/src/content/components/top-content/follow-controller.js index d373177..f759c8c 100644 --- a/src/content/components/top-content/follow-controller.js +++ b/src/content/components/top-content/follow-controller.js @@ -29,7 +29,7 @@ export default class FollowController { switch (message.type) { case messages.FOLLOW_START: return this.store.dispatch( - followControllerActions.enable(message.newTab)); + followControllerActions.enable(message.newTab, message.background)); case messages.FOLLOW_RESPONSE_COUNT_TARGETS: return this.create(message.count, sender); case messages.FOLLOW_KEY_PRESS: @@ -126,6 +126,7 @@ export default class FollowController { type: messages.FOLLOW_CREATE_HINTS, keysArray: produced, newTab: this.state.newTab, + background: this.state.background, }), '*'); } diff --git a/src/content/reducers/follow-controller.js b/src/content/reducers/follow-controller.js index 2afb232..78fd848 100644 --- a/src/content/reducers/follow-controller.js +++ b/src/content/reducers/follow-controller.js @@ -3,6 +3,7 @@ import actions from 'content/actions'; const defaultState = { enabled: false, newTab: false, + background: false, keys: '', }; @@ -12,6 +13,7 @@ export default function reducer(state = defaultState, action = {}) { return Object.assign({}, state, { enabled: true, newTab: action.newTab, + background: action.background, keys: '', }); case actions.FOLLOW_CONTROLLER_DISABLE: diff --git a/src/shared/commands.js b/src/shared/commands.js index 8edeb5c..bcad313 100644 --- a/src/shared/commands.js +++ b/src/shared/commands.js @@ -33,8 +33,19 @@ const openCommand = (url) => { }); }; -const tabopenCommand = (url) => { - return browser.tabs.create({ url: url }); +const tabopenCommand = (url, background = false, adjacent = false) => { + if (adjacent) { + return browser.tabs.query({ + active: true, currentWindow: true + }).then((gotTabs) => { + return browser.tabs.create({ + url: url, + active: !background, + index: gotTabs[0].index + 1 + }); + }); + } + return browser.tabs.create({ url: url, active: !background }); }; const winopenCommand = (url) => { @@ -102,7 +113,8 @@ const doCommand = (line, settings) => { return openCommand(normalizeUrl(words, settings.search)); case 't': case 'tabopen': - return tabopenCommand(normalizeUrl(words, settings.search)); + return tabopenCommand( + normalizeUrl(words, settings.search), false, settings.openAdjacentTabs); case 'w': case 'winopen': return winopenCommand(normalizeUrl(words, settings.search)); @@ -166,4 +178,4 @@ const complete = (line, settings) => { return getCompletions(line, settings); }; -export { exec, complete }; +export { exec, complete, tabopenCommand }; diff --git a/src/shared/default-settings.js b/src/shared/default-settings.js index 608890b..d691859 100644 --- a/src/shared/default-settings.js +++ b/src/shared/default-settings.js @@ -37,8 +37,8 @@ export default { "zi": { "type": "zoom.in" }, "zo": { "type": "zoom.out" }, "zz": { "type": "zoom.neutral" }, - "f": { "type": "follow.start", "newTab": false }, - "F": { "type": "follow.start", "newTab": true }, + "f": { "type": "follow.start", "newTab": false, "background": false }, + "F": { "type": "follow.start", "newTab": true, "background": false }, "H": { "type": "navigate.history.prev" }, "L": { "type": "navigate.history.next" }, "[[": { "type": "navigate.link.prev" }, @@ -61,6 +61,7 @@ export default { "twitter": "https://twitter.com/search?q={}", "wikipedia": "https://en.wikipedia.org/w/index.php?search={}" } - } + }, + "openAdjacentTabs": false }` }; diff --git a/src/shared/validators/setting.js b/src/shared/validators/setting.js index 949ab29..5fe75b2 100644 --- a/src/shared/validators/setting.js +++ b/src/shared/validators/setting.js @@ -1,6 +1,6 @@ import operations from 'shared/operations'; -const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist']; +const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist', 'openAdjacentTabs']; const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => { return operations[key]; }); From 9ce54583314444a7f6c41db731be5d58f669702a Mon Sep 17 00:00:00 2001 From: Shinya Ohyanagi Date: Thu, 16 Nov 2017 23:22:56 +0900 Subject: [PATCH 005/178] Fix add return statement --- src/console/components/console.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console/components/console.js b/src/console/components/console.js index 7c1976e..682d5dc 100644 --- a/src/console/components/console.js +++ b/src/console/components/console.js @@ -71,7 +71,7 @@ export default class ConsoleComponent { break; case KeyboardEvent.DOM_VK_M: if (e.ctrlKey) { - this.doEnter(e); + return this.doEnter(e); } break; case KeyboardEvent.DOM_VK_DOWN: From 4a446793212b97dc16f87c99f99def6fb5fcd1d2 Mon Sep 17 00:00:00 2001 From: chocolateboy Date: Fri, 17 Nov 2017 19:02:13 +0000 Subject: [PATCH 006/178] improve #linkPrev and #linkNext: - add support for elements - match if there's more than one rel e.g. ... - more tests --- src/content/navigates.js | 31 ++++--- test/content/navigates.test.js | 156 +++++++++++++++++++++++++-------- 2 files changed, 136 insertions(+), 51 deletions(-) diff --git a/src/content/navigates.js b/src/content/navigates.js index 64e5fc0..3e12a6f 100644 --- a/src/content/navigates.js +++ b/src/content/navigates.js @@ -2,13 +2,14 @@ const PREV_LINK_PATTERNS = [ /\bprev\b/i, /\bprevious\b/i, /\bback\b/i, //, /\u203a/, /\u2192/, /\xbb/, /\u226b/, />>/ ]; const findLinkByPatterns = (win, patterns) => { - let links = win.document.getElementsByTagName('a'); + const links = win.document.getElementsByTagName('a'); return Array.prototype.find.call(links, (link) => { return patterns.some(ptn => ptn.test(link.textContent)); }); @@ -22,30 +23,32 @@ const historyNext = (win) => { win.history.forward(); }; -const linkPrev = (win) => { - let link = win.document.querySelector('a[rel=prev]'); +const linkCommon = (win, rel, patterns) => { + let link = win.document.querySelector(`link[rel~=${rel}][href]`); + if (link) { - return link.click(); + win.location = link.getAttribute('href'); + return; } - link = findLinkByPatterns(win, PREV_LINK_PATTERNS); + + link = win.document.querySelector(`a[rel~=${rel}]`) || + findLinkByPatterns(win, patterns); + if (link) { link.click(); } }; +const linkPrev = (win) => { + linkCommon(win, 'prev', PREV_LINK_PATTERNS); +}; + const linkNext = (win) => { - let link = win.document.querySelector('a[rel=next]'); - if (link) { - return link.click(); - } - link = findLinkByPatterns(win, NEXT_LINK_PATTERNS); - if (link) { - link.click(); - } + linkCommon(win, 'next', NEXT_LINK_PATTERNS); }; const parent = (win) => { - let loc = win.location; + const loc = win.location; if (loc.hash !== '') { loc.hash = ''; return; diff --git a/test/content/navigates.test.js b/test/content/navigates.test.js index b5144e9..d8a3316 100644 --- a/test/content/navigates.test.js +++ b/test/content/navigates.test.js @@ -1,56 +1,138 @@ -import { expect } from "chai"; +import { expect } from 'chai'; import * as navigates from 'content/navigates'; +const testRel = (done, rel, html) => { + const method = rel === 'prev' ? 'linkPrev' : 'linkNext'; + document.body.innerHTML = html; + navigates[method](window); + setTimeout(() => { + expect(document.location.hash).to.equal(`#${rel}`); + done(); + }, 0); +}; + +const testPrev = html => done => testRel(done, 'prev', html); +const testNext = html => done => testRel(done, 'next', html); + describe('navigates module', () => { describe('#linkPrev', () => { - it('clicks prev link by text content', (done) => { - document.body.innerHTML = 'xprevx go to prev'; - navigates.linkPrev(window); - setTimeout(() => { - expect(document.location.hash).to.equal('#prev'); - done(); - }, 0); - }); + it('navigates to elements whose rel attribute is "prev"', testPrev( + '' + )); - it('clicks a[rel=prev] element preferentially', (done) => { - document.body.innerHTML = 'prev '; - navigates.linkPrev(window); - setTimeout(() => { - expect(document.location.hash).to.equal('#prev'); - done(); - }, 0); - }); - }); + it('navigates to elements whose rel attribute starts with "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute ends with "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute contains "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute is "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute starts with "prev"', testPrev( + 'click me' + )); + + it('navigates to elements whose rel attribute ends with "prev"', testPrev( + 'click me' + )); + + it('navigates to elements whose rel attribute contains "prev"', testPrev( + 'click me' + )); + + it('navigates to elements whose text matches "prev"', testPrev( + 'previewgo to prev' + )); + + it('navigates to elements whose text matches "previous"', testPrev( + 'previewgo to previous' + )); + + it('navigates to elements whose decoded text matches "<<"', testPrev( + 'click me<<' + )); + + it('navigates to matching elements by clicking', testPrev( + `` + )); + + it('prefers link[rel~=prev] to a[rel~=prev]', testPrev( + '' + )); + it('prefers a[rel~=prev] to a::text(pattern)', testPrev( + 'go to prev' + )); + }); describe('#linkNext', () => { - it('clicks next link by text content', (done) => { - document.body.innerHTML = 'xnextx go to next'; - navigates.linkNext(window); - setTimeout(() => { - expect(document.location.hash).to.equal('#next'); - done(); - }, 0); - }); + it('navigates to elements whose rel attribute is "next"', testNext( + '' + )); - it('clicks a[rel=next] element preferentially', (done) => { - document.body.innerHTML = 'next '; - navigates.linkNext(window); - setTimeout(() => { - expect(document.location.hash).to.equal('#next'); - done(); - }, 0); - }); + it('navigates to elements whose rel attribute starts with "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute ends with "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute contains "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute is "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute starts with "next"', testNext( + 'click me' + )); + + it('navigates to elements whose rel attribute ends with "next"', testNext( + 'click me' + )); + + it('navigates to elements whose rel attribute contains "next"', testNext( + 'click me' + )); + + it('navigates to elements whose text matches "next"', testNext( + 'inextricablego to next' + )); + + it('navigates to elements whose decoded text matches ">>"', testNext( + 'click me>>' + )); + + it('navigates to matching elements by clicking', testNext( + `` + )); + + it('prefers link[rel~=next] to a[rel~=next]', testNext( + 'go to next' + )); }); describe('#parent', () => { // NOTE: not able to test location it('removes hash', () => { - window.location.hash = "#section-1"; + window.location.hash = '#section-1'; navigates.parent(window); expect(document.location.hash).to.be.empty; }); }); }); - - From b70a671d7e7c8b801f8a05210c71f7c9a8e48828 Mon Sep 17 00:00:00 2001 From: Shinya Ohyanagi Date: Sat, 18 Nov 2017 13:22:43 +0900 Subject: [PATCH 007/178] Fix drop , from cursor selector Because these are not Vim's default behavior. --- src/console/components/console.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/console/components/console.js b/src/console/components/console.js index 682d5dc..21439ef 100644 --- a/src/console/components/console.js +++ b/src/console/components/console.js @@ -78,7 +78,6 @@ export default class ConsoleComponent { this.selectNext(e); break; case KeyboardEvent.DOM_VK_N: - case KeyboardEvent.DOM_VK_J: if (e.ctrlKey) { this.selectNext(e); } @@ -87,7 +86,6 @@ export default class ConsoleComponent { this.selectPrev(e); break; case KeyboardEvent.DOM_VK_P: - case KeyboardEvent.DOM_VK_K: if (e.ctrlKey) { this.selectPrev(e); } From 5d0554c7e8be7d2e96a76927b46a37c82e0eb011 Mon Sep 17 00:00:00 2001 From: Shinya Ohyanagi Date: Sat, 18 Nov 2017 13:53:33 +0900 Subject: [PATCH 008/178] Fix drop arrow keys from console --- src/console/components/console.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/console/components/console.js b/src/console/components/console.js index 21439ef..7c23dab 100644 --- a/src/console/components/console.js +++ b/src/console/components/console.js @@ -74,17 +74,11 @@ export default class ConsoleComponent { return this.doEnter(e); } break; - case KeyboardEvent.DOM_VK_DOWN: - this.selectNext(e); - break; case KeyboardEvent.DOM_VK_N: if (e.ctrlKey) { this.selectNext(e); } break; - case KeyboardEvent.DOM_VK_UP: - this.selectPrev(e); - break; case KeyboardEvent.DOM_VK_P: if (e.ctrlKey) { this.selectPrev(e); From b878ef3f090b6a16f12736e34ab3868fe9de0d6e Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 19 Nov 2017 08:55:50 +0900 Subject: [PATCH 009/178] Update QA for release 0.6 --- QA.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/QA.md b/QA.md index c1f413d..f91ba83 100644 --- a/QA.md +++ b/QA.md @@ -36,6 +36,7 @@ The behaviors of the console are tested in [Console section](#consoles). #### Navigation - [ ] H, L: go back and forward in histories +- [ ] [[, ]]: Open next/prev link in tags. - [ ] [[, ]]: find prev and next links and open it - [ ] gu: go to parent directory - [ ] gU: go to root directory @@ -143,6 +144,8 @@ The behaviors of the console are tested in [Console section](#consoles). - [ ] able to scroll on Gmail and Slack - [ ] Fucus text box on Twitter or Slack, press j, then j is typed in the box - [ ] Focus the text box on Twitter or Slack on following mode +- [ ] Tha pages is shown in https://pitchify.com/ +- [ ] Open console in http://www.espncricinfo.com/ ## Find mode From a269b117b10eb204b054d56f4feb8334b82c7c42 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 19 Nov 2017 09:36:39 +0900 Subject: [PATCH 010/178] Update QA --- QA.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QA.md b/QA.md index f91ba83..148e4c8 100644 --- a/QA.md +++ b/QA.md @@ -36,7 +36,7 @@ The behaviors of the console are tested in [Console section](#consoles). #### Navigation - [ ] H, L: go back and forward in histories -- [ ] [[, ]]: Open next/prev link in tags. +- [ ] [[, ]]: Open next/prev link in `` tags. - [ ] [[, ]]: find prev and next links and open it - [ ] gu: go to parent directory - [ ] gU: go to root directory From bf141d0330e4f46efd6990113f251f93218fb303 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 19 Nov 2017 12:01:34 +0900 Subject: [PATCH 011/178] Update QA --- QA.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QA.md b/QA.md index 148e4c8..8cba39f 100644 --- a/QA.md +++ b/QA.md @@ -150,7 +150,7 @@ The behaviors of the console are tested in [Console section](#consoles). ## Find mode - [ ] open console with / -- [ ] highlight a word on Enter pressed in find console +- [ ] highlight a word on Enter pressed in find console - [ ] Search next/prev by n/N - [ ] Wrap search by n/N - [ ] Find with last keyword if keyword is empty From 27263e906d558e53e04121a79e20b62d03d4c40f Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 19 Nov 2017 12:01:49 +0900 Subject: [PATCH 012/178] Fix message CSS --- src/console/site.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/console/site.scss b/src/console/site.scss index 5aaea12..cb89e50 100644 --- a/src/console/site.scss +++ b/src/console/site.scss @@ -69,6 +69,8 @@ body { &-message { @include consoole-font; + + border-top: 1px solid gray; } &-error { From 3a05b9300e104b8729644b1519e4a80d139fe96c Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 19 Nov 2017 12:27:07 +0900 Subject: [PATCH 013/178] Bump a version --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 5fd1c1a..532eaac 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "Vim Vixen", "description": "Vim Vixen", - "version": "0.5", + "version": "0.6", "icons": { "48": "resources/icon_48x48.png", "96": "resources/icon_96x96.png" From 05c7a64b6d41a87c92332556e80fbaa75f12d761 Mon Sep 17 00:00:00 2001 From: Kostyantyn Leschenko Date: Mon, 20 Nov 2017 16:24:25 +0200 Subject: [PATCH 014/178] Fix history completion to show most frequent results first. --- src/background/histories.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/background/histories.js b/src/background/histories.js index 6b6e4c6..a7d3d47 100644 --- a/src/background/histories.js +++ b/src/background/histories.js @@ -76,7 +76,6 @@ const getCompletions = (keyword) => { .sort((x, y) => x[0].visitCount < y[0].visitCount) .slice(0, 10) .map(item => item[0]) - .sort((x, y) => x.url > y.url) )[0]; }); }; From cc539d96bc2d14796279fc2c4c867bb6a3b2df06 Mon Sep 17 00:00:00 2001 From: Kostyantyn Leschenko Date: Mon, 20 Nov 2017 16:58:39 +0200 Subject: [PATCH 015/178] Fix buffers completion when there are some tabs with undefined title. --- src/background/tabs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/background/tabs.js b/src/background/tabs.js index d641616..b34f7c2 100644 --- a/src/background/tabs.js +++ b/src/background/tabs.js @@ -51,7 +51,7 @@ const selectByKeyword = (current, keyword) => { const getCompletions = (keyword) => { return browser.tabs.query({ currentWindow: true }).then((tabs) => { let matched = tabs.filter((t) => { - return t.url.includes(keyword) || t.title.includes(keyword); + return t.url.includes(keyword) || t.title && t.title.includes(keyword); }); return matched; }); From ee3cd3faabbe64265746ef39d419f63db24d11ba Mon Sep 17 00:00:00 2001 From: chocolateboy Date: Thu, 23 Nov 2017 14:10:36 +0000 Subject: [PATCH 016/178] pagination tweaks and fixes: - fallback links: - select the last matching link rather than the first - use `innerText` rather than `textContent` - use a single regex for each pattern rather than an array - fix markup typo in test --- src/content/navigates.js | 49 +++++++++++++++++++--------------- test/content/navigates.test.js | 6 ++--- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/content/navigates.js b/src/content/navigates.js index 3e12a6f..c9baa30 100644 --- a/src/content/navigates.js +++ b/src/content/navigates.js @@ -1,18 +1,18 @@ -const PREV_LINK_PATTERNS = [ - /\bprev\b/i, /\bprevious\b/i, /\bback\b/i, - //, /\u203a/, /\u2192/, /\xbb/, /\u226b/, />>/ -]; - -const findLinkByPatterns = (win, patterns) => { - const links = win.document.getElementsByTagName('a'); - return Array.prototype.find.call(links, (link) => { - return patterns.some(ptn => ptn.test(link.textContent)); - }); +const REL_PATTERN = { + prev: /^(?:prev(?:ious)?|older)\b|\u2039|\u2190|\xab|\u226a|<>/i, +}; + +// Return the last element in the document matching the supplied selector +// and the optional filter, or null if there are no matches. +const selectLast = (win, selector, filter) => { + let nodes = win.document.querySelectorAll(selector); + + if (filter) { + nodes = Array.from(nodes).filter(filter); + } + + return nodes.length ? nodes[nodes.length - 1] : null; }; const historyPrev = (win) => { @@ -23,16 +23,21 @@ const historyNext = (win) => { win.history.forward(); }; -const linkCommon = (win, rel, patterns) => { - let link = win.document.querySelector(`link[rel~=${rel}][href]`); +// Code common to linkPrev and linkNext which navigates to the specified page. +const linkRel = (win, rel) => { + let link = selectLast(win, `link[rel~=${rel}][href]`); if (link) { - win.location = link.getAttribute('href'); + win.location = link.href; return; } - link = win.document.querySelector(`a[rel~=${rel}]`) || - findLinkByPatterns(win, patterns); + const pattern = REL_PATTERN[rel]; + + link = selectLast(win, `a[rel~=${rel}][href]`) || + // `innerText` is much slower than `textContent`, but produces much better + // (i.e. less unexpected) results + selectLast(win, 'a[href]', lnk => pattern.test(lnk.innerText)); if (link) { link.click(); @@ -40,11 +45,11 @@ const linkCommon = (win, rel, patterns) => { }; const linkPrev = (win) => { - linkCommon(win, 'prev', PREV_LINK_PATTERNS); + linkRel(win, 'prev'); }; const linkNext = (win) => { - linkCommon(win, 'next', NEXT_LINK_PATTERNS); + linkRel(win, 'next'); }; const parent = (win) => { diff --git a/test/content/navigates.test.js b/test/content/navigates.test.js index d8a3316..f1f0741 100644 --- a/test/content/navigates.test.js +++ b/test/content/navigates.test.js @@ -53,7 +53,7 @@ describe('navigates module', () => { )); it('navigates to elements whose text matches "previous"', testPrev( - 'previewgo to previous' + 'previouslyprevious page' )); it('navigates to elements whose decoded text matches "<<"', testPrev( @@ -119,11 +119,11 @@ describe('navigates module', () => { )); it('prefers link[rel~=next] to a[rel~=next]', testNext( - '' )); it('prefers a[rel~=next] to a::text(pattern)', testNext( - 'go to next' + 'next page' )); }); From 127e94836e5ec708b2c28efe2578a989e8c2cb28 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 25 Nov 2017 13:22:27 +0900 Subject: [PATCH 017/178] Add badges to READM --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e8a9835..574a845 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Vim Vixen +[![Join the chat room on Gitter for vim-vixen/vim-vixen](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/vim-vixen/vim-vixen) +[![Build Status](https://travis-ci.org/ueokande/vim-vixen.svg?branch=kaizen)](https://travis-ci.org/ueokande/vim-vixen) + Vim Vixen is a Firefox add-on which allows you to navigate with keyboard on the browser. Firefox started to support WebExtensions API and will stop supporting add-ons using legacy APIs from version 57. For this reason, many legacy add-ons do not work on Firefox 57. From 89c52173ce5ead27c234063c08b1aa1c67298f6d Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 18 Nov 2017 17:09:41 +0900 Subject: [PATCH 018/178] install preact --- package-lock.json | 98 ++++++----------------------------------------- package.json | 9 ++--- 2 files changed, 14 insertions(+), 93 deletions(-) diff --git a/package-lock.json b/package-lock.json index ee8a41c..0a50bf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -735,12 +735,6 @@ "babel-helper-is-void-0": "0.2.0" } }, - "babel-plugin-syntax-flow": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", - "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", - "dev": true - }, "babel-plugin-syntax-jsx": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", @@ -981,16 +975,6 @@ "regexpu-core": "2.0.0" } }, - "babel-plugin-transform-flow-strip-types": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", - "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", - "dev": true, - "requires": { - "babel-plugin-syntax-flow": "6.18.0", - "babel-runtime": "6.25.0" - } - }, "babel-plugin-transform-inline-consecutive-adds": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz", @@ -1024,15 +1008,6 @@ "esutils": "2.0.2" } }, - "babel-plugin-transform-react-display-name": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", - "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", - "dev": true, - "requires": { - "babel-runtime": "6.25.0" - } - }, "babel-plugin-transform-react-jsx": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", @@ -1044,26 +1019,6 @@ "babel-runtime": "6.25.0" } }, - "babel-plugin-transform-react-jsx-self": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", - "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", - "dev": true, - "requires": { - "babel-plugin-syntax-jsx": "6.18.0", - "babel-runtime": "6.25.0" - } - }, - "babel-plugin-transform-react-jsx-source": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", - "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", - "dev": true, - "requires": { - "babel-plugin-syntax-jsx": "6.18.0", - "babel-runtime": "6.25.0" - } - }, "babel-plugin-transform-regenerator": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz", @@ -1165,15 +1120,6 @@ "babel-plugin-transform-regenerator": "6.24.1" } }, - "babel-preset-flow": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", - "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", - "dev": true, - "requires": { - "babel-plugin-transform-flow-strip-types": "6.22.0" - } - }, "babel-preset-minify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.2.0.tgz", @@ -1205,18 +1151,14 @@ "lodash.isplainobject": "4.0.6" } }, - "babel-preset-react": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", - "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", + "babel-preset-preact": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-preact/-/babel-preset-preact-1.1.0.tgz", + "integrity": "sha1-NaxlWnOkm4Q4FjzgU4Fld+GYCGE=", "dev": true, "requires": { "babel-plugin-syntax-jsx": "6.18.0", - "babel-plugin-transform-react-display-name": "6.25.0", - "babel-plugin-transform-react-jsx": "6.24.1", - "babel-plugin-transform-react-jsx-self": "6.22.0", - "babel-plugin-transform-react-jsx-source": "6.22.0", - "babel-preset-flow": "6.23.0" + "babel-plugin-transform-react-jsx": "6.24.1" } }, "babel-register": { @@ -6273,6 +6215,12 @@ "uniqs": "2.0.0" } }, + "preact": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/preact/-/preact-8.2.6.tgz", + "integrity": "sha1-ACi0Ju+Y/Mp0Gjxhf/W4E7mpR8c=", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -6491,30 +6439,6 @@ } } }, - "react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.0.0.tgz", - "integrity": "sha1-zn348ZQbA28Cssyp29DLHw6FXi0=", - "dev": true, - "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "prop-types": "15.6.0" - } - }, - "react-dom": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.0.0.tgz", - "integrity": "sha1-nMMHnD3NcNTG4BuEqrKn40wwP1g=", - "dev": true, - "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "prop-types": "15.6.0" - } - }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", diff --git a/package.json b/package.json index ad25ffa..5606b79 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,9 @@ "description": "Vim vixen", "scripts": { "start": "webpack -w --debug --devtool inline-source-map", - "lint": "eslint --ext .jsx,.js src", "build": "NODE_ENV=production webpack --progress --display-error-details", "package": "npm run build && ./package.sh", - "lint": "eslint src", + "lint": "eslint --ext .jsx,.js src", "test": "karma start" }, "repository": { @@ -24,9 +23,8 @@ "babel-eslint": "^7.2.3", "babel-loader": "^7.1.1", "babel-minify-webpack-plugin": "^0.2.0", - "babel-plugin-transform-react-jsx": "^6.24.1", "babel-preset-es2015": "^6.24.1", - "babel-preset-react": "^6.24.1", + "babel-preset-preact": "^1.1.0", "chai": "^4.1.1", "css-loader": "^0.28.4", "eslint": "^4.7.0", @@ -41,8 +39,7 @@ "karma-webpack": "^2.0.4", "mocha": "^3.5.0", "node-sass": "^4.5.3", - "react": "^16.0.0", - "react-dom": "^16.0.0", + "preact": "^8.2.6", "sass-loader": "^6.0.6", "style-loader": "^0.18.2", "webpack": "^3.5.3" From 44459e39c3526673ac2ac7065c5659e4af5ea7d8 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 18 Nov 2017 22:02:44 +0900 Subject: [PATCH 019/178] use preact --- .eslintrc | 2 ++ src/settings/components/index.jsx | 9 ++------- src/settings/index.jsx | 5 ++--- src/shared/store/provider.jsx | 13 +++++-------- webpack.config.js | 2 +- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/.eslintrc b/.eslintrc index 949b5a5..6717889 100644 --- a/.eslintrc +++ b/.eslintrc @@ -44,6 +44,7 @@ "no-plusplus": "off", "no-ternary": "off", "no-undefined": "off", + "no-unused-vars": ["error", { "varsIgnorePattern": "h" }], "no-use-before-define": "off", "no-warning-comments": "off", "object-curly-newline": ["error", { "consistent": true }], @@ -65,5 +66,6 @@ "react/jsx-indent": ["error", 2], "react/prop-types": "off", + "react/react-in-jsx-scope": "off" } } diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index 4418942..bb2045a 100644 --- a/src/settings/components/index.jsx +++ b/src/settings/components/index.jsx @@ -1,10 +1,9 @@ import './site.scss'; -import React from 'react'; -import PropTypes from 'prop-types'; +import { h, Component } from 'preact'; import * as settingActions from 'settings/actions/setting'; import * as validator from 'shared/validators/setting'; -class SettingsComponent extends React.Component { +class SettingsComponent extends Component { constructor(props, context) { super(props, context); @@ -84,8 +83,4 @@ class SettingsComponent extends React.Component { } } -SettingsComponent.contextTypes = { - store: PropTypes.any, -}; - export default SettingsComponent; diff --git a/src/settings/index.jsx b/src/settings/index.jsx index 7516fb7..eb251b4 100644 --- a/src/settings/index.jsx +++ b/src/settings/index.jsx @@ -1,5 +1,4 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import { h, render } from 'preact'; import SettingsComponent from './components'; import reducer from 'settings/reducers/setting'; import Provider from 'shared/store/provider'; @@ -9,7 +8,7 @@ const store = createStore(reducer); document.addEventListener('DOMContentLoaded', () => { let wrapper = document.getElementById('vimvixen-settings'); - ReactDOM.render( + render( , diff --git a/src/shared/store/provider.jsx b/src/shared/store/provider.jsx index 743f656..fe925aa 100644 --- a/src/shared/store/provider.jsx +++ b/src/shared/store/provider.jsx @@ -1,18 +1,15 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import { h, Component } from 'preact'; -class Provider extends React.PureComponent { +class Provider extends Component { getChildContext() { return { store: this.props.store }; } render() { - return React.Children.only(this.props.children); + return
+ { this.props.children } +
; } } -Provider.childContextTypes = { - store: PropTypes.any, -}; - export default Provider; diff --git a/webpack.config.js b/webpack.config.js index 16d437f..fc5ef5e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -25,7 +25,7 @@ config = { exclude: /node_modules/, loader: 'babel-loader', query: { - presets: ['es2015', 'react'] + presets: ['es2015', 'preact'] } }, { From d33b37cdb9d2956f5f2d23ab4e71e35db137b16e Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 19 Nov 2017 08:23:51 +0900 Subject: [PATCH 020/178] Use Preact for settings and show validation --- src/settings/components/index.jsx | 48 +++++++++++++++---------- src/settings/components/site.scss | 2 ++ src/settings/components/ui/input.jsx | 50 +++++++++++++++++++++++++++ src/settings/components/ui/input.scss | 17 +++++++++ 4 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 src/settings/components/ui/input.jsx create mode 100644 src/settings/components/ui/input.scss diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index bb2045a..98d8fb2 100644 --- a/src/settings/components/index.jsx +++ b/src/settings/components/index.jsx @@ -1,5 +1,6 @@ import './site.scss'; import { h, Component } from 'preact'; +import Input from './ui/input'; import * as settingActions from 'settings/actions/setting'; import * as validator from 'shared/validators/setting'; @@ -10,6 +11,9 @@ class SettingsComponent extends Component { this.state = { settings: { json: '', + }, + errors: { + json: '', } }; this.context.store.subscribe(this.stateChanged.bind(this)); @@ -35,39 +39,47 @@ class SettingsComponent extends Component {

Configure Vim-Vixen

-

Load settings from:

- - + label='Use plain JSON' + checked={this.state.settings.source === 'json'} + value='json' /> -