From 764d7a34bda121f97e947861c41722a12af37b15 Mon Sep 17 00:00:00 2001 From: usk Date: Sun, 5 Nov 2017 10:06:26 +0900 Subject: 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(-) (limited to 'src/content/components/common/follow.js') 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(','); -- cgit v1.2.3 From 177940981ed9c4f096ad7db20f0b7ee044fd7b17 Mon Sep 17 00:00:00 2001 From: Erwan Ameil Date: Thu, 16 Nov 2017 13:03:38 +0000 Subject: 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 ++++++-- .../components/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(-) (limited to 'src/content/components/common/follow.js') 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]; }); -- cgit v1.2.3 From de7883329bb3d2a5a5a12cd278970b04107a0097 Mon Sep 17 00:00:00 2001 From: usk Date: Sun, 24 Dec 2017 06:14:17 +0900 Subject: do not follow link which has aria-hidden attribute or aria-disabled attribute --- src/content/components/common/follow.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/content/components/common/follow.js') diff --git a/src/content/components/common/follow.js b/src/content/components/common/follow.js index 7717154..42dd897 100644 --- a/src/content/components/common/follow.js +++ b/src/content/components/common/follow.js @@ -30,6 +30,21 @@ const inViewport = (win, element, viewSize, framePosition) => { return true; }; +const isAriaHiddenOrAriaDisabled = (win, element) => { + if (!element || win.document.documentElement === element) { + return false; + } + for (let attr of ['aria-hidden', 'aria-disabled']) { + if (element.hasAttribute(attr)) { + let hidden = element.getAttribute(attr).toLowerCase(); + if (hidden === '' || hidden === 'true') { + return true; + } + } + } + return isAriaHiddenOrAriaDisabled(win, element.parentNode); +}; + export default class Follow { constructor(win, store) { this.win = win; @@ -171,6 +186,7 @@ export default class Follow { style.visibility !== 'hidden' && element.type !== 'hidden' && element.offsetHeight > 0 && + !isAriaHiddenOrAriaDisabled(win, element) && inViewport(win, element, viewSize, framePosition); }); return filtered; -- cgit v1.2.3 From 8cc7d472dff5882e4379869345667dd4ba53ca45 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 26 Feb 2018 21:20:13 +0900 Subject: Cancel following by --- src/content/components/common/follow.js | 1 + src/content/components/top-content/follow-controller.js | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/content/components/common/follow.js') diff --git a/src/content/components/common/follow.js b/src/content/components/common/follow.js index 42dd897..a8682c5 100644 --- a/src/content/components/common/follow.js +++ b/src/content/components/common/follow.js @@ -63,6 +63,7 @@ export default class Follow { this.win.parent.postMessage(JSON.stringify({ type: messages.FOLLOW_KEY_PRESS, key: key.key, + ctrlKey: key.ctrlKey, }), '*'); return true; } diff --git a/src/content/components/top-content/follow-controller.js b/src/content/components/top-content/follow-controller.js index 1e7f3cd..1b5586b 100644 --- a/src/content/components/top-content/follow-controller.js +++ b/src/content/components/top-content/follow-controller.js @@ -32,7 +32,7 @@ export default class FollowController { case messages.FOLLOW_RESPONSE_COUNT_TARGETS: return this.create(message.count, sender); case messages.FOLLOW_KEY_PRESS: - return this.keyPress(message.key); + return this.keyPress(message.key, message.ctrlKey); } } @@ -69,7 +69,11 @@ export default class FollowController { }); } - keyPress(key) { + keyPress(key, ctrlKey) { + if (key === '[' && ctrlKey) { + this.store.dispatch(followControllerActions.disable()); + return true; + } switch (key) { case 'Enter': this.activate(); -- cgit v1.2.3