diff --git a/README.md b/README.md index 84cf2a2..c163901 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Firefox by WebExtensions API. - [ ] find a keyword in the page - [ ] navigations - [ ] yank/paste page - - [ ] pagenation + - [x] pagenation - [ ] open parent page - [ ] hints - [x] open a link diff --git a/src/background/keys.js b/src/background/keys.js index 577f023..2549c8d 100644 --- a/src/background/keys.js +++ b/src/background/keys.js @@ -30,6 +30,8 @@ const defaultKeymap = { 'F': { type: operations.FOLLOW_START, newTab: true }, 'H': { type: operations.NAVIGATE_HISTORY_PREV }, 'L': { type: operations.NAVIGATE_HISTORY_NEXT }, + '[[': { type: operations.NAVIGATE_LINK_PREV }, + ']]': { type: operations.NAVIGATE_LINK_NEXT }, }; const asKeymapChars = (keys) => { diff --git a/src/content/index.js b/src/content/index.js index be01089..0e4f7e1 100644 --- a/src/content/index.js +++ b/src/content/index.js @@ -39,6 +39,10 @@ const execOperation = (operation) => { return navigates.historyPrev(window); case operations.NAVIGATE_HISTORY_NEXT: return navigates.historyNext(window); + case operations.NAVIGATE_LINK_PREV: + return navigates.linkPrev(window); + case operations.NAVIGATE_LINK_NEXT: + return navigates.linkNext(window); } }; diff --git a/src/content/navigates.js b/src/content/navigates.js index 28f34c5..b68052d 100644 --- a/src/content/navigates.js +++ b/src/content/navigates.js @@ -1,8 +1,47 @@ +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'); + return Array.prototype.find.call(links, (link) => { + return patterns.some(ptn => ptn.test(link.textContent)); + }); +}; + const historyPrev = (win) => { win.history.back(); }; + const historyNext = (win) => { win.history.forward(); }; -export { historyPrev, historyNext }; +const linkPrev = (win) => { + let link = win.document.querySelector('a[rel=prev]'); + if (link) { + return link.click(); + } + link = findLinkByPatterns(win, PREV_LINK_PATTERNS); + if (link) { + link.click(); + } +}; + +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(); + } +}; + +export { historyPrev, historyNext, linkPrev, linkNext }; diff --git a/src/operations/index.js b/src/operations/index.js index 6d8cc7e..bb19df8 100644 --- a/src/operations/index.js +++ b/src/operations/index.js @@ -13,6 +13,8 @@ export default { FOLLOW_START: 'follow.start', NAVIGATE_HISTORY_PREV: 'navigate.history.prev', NAVIGATE_HISTORY_NEXT: 'navigate.history.next', + NAVIGATE_LINK_PREV: 'navigate.link.prev', + NAVIGATE_LINK_NEXT: 'navigate.link.next', // Background TABS_CLOSE: 'tabs.close', diff --git a/test/content/navigates.test.js b/test/content/navigates.test.js new file mode 100644 index 0000000..21c2a23 --- /dev/null +++ b/test/content/navigates.test.js @@ -0,0 +1,50 @@ +import { expect } from "chai"; +import * as navigates from '../../src/content/navigates'; + +describe('navigates module', () => { + beforeEach(() => { + }); + + 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('clicks a[rel=prev] element preferentially', (done) => { + document.body.innerHTML = 'prev '; + navigates.linkPrev(window); + setTimeout(() => { + expect(document.location.hash).to.equal('#prev'); + done(); + }, 0); + }); + }); + + + 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('clicks a[rel=next] element preferentially', (done) => { + document.body.innerHTML = 'next '; + navigates.linkNext(window); + setTimeout(() => { + expect(document.location.hash).to.equal('#next'); + done(); + }, 0); + }); + }); +}); + +