aboutsummaryrefslogtreecommitdiff
path: root/src/content
diff options
context:
space:
mode:
Diffstat (limited to 'src/content')
-rw-r--r--src/content/follow.js48
-rw-r--r--src/content/hint.js6
-rw-r--r--src/content/index.js34
3 files changed, 65 insertions, 23 deletions
diff --git a/src/content/follow.js b/src/content/follow.js
index 5abeee0..7d69b45 100644
--- a/src/content/follow.js
+++ b/src/content/follow.js
@@ -8,6 +8,7 @@ export default class Follow {
this.doc = doc;
this.hintElements = {};
this.keys = [];
+ this.onActivatedCallbacks = [];
// TODO activate input elements and push button elements
let links = Follow.getTargetElements(doc);
@@ -36,7 +37,7 @@ export default class Follow {
} else if (keyCode === KeyboardEvent.DOM_VK_ENTER ||
keyCode === KeyboardEvent.DOM_VK_RETURN) {
let chars = Follow.codeChars(this.keys);
- this.hintElements[chars].activate();
+ this.activate(this.hintElements[chars].target);
return;
} else if (Follow.availableKey(keyCode)) {
this.keys.push(keyCode);
@@ -45,6 +46,9 @@ export default class Follow {
this.keys.pop();
}
+ e.stopPropagation();
+ e.preventDefault();
+
this.refreshKeys();
}
@@ -61,7 +65,7 @@ export default class Follow {
return;
} else if (shown.length === 1) {
this.remove();
- this.hintElements[chars].activate();
+ this.activate(this.hintElements[chars].target);
}
shown.forEach((key) => {
@@ -72,7 +76,6 @@ export default class Follow {
});
}
-
remove() {
this.doc.removeEventListener('keydown', this.boundKeydown);
Object.keys(this.hintElements).forEach((key) => {
@@ -80,6 +83,14 @@ export default class Follow {
});
}
+ activate(element) {
+ this.onActivatedCallbacks.forEach(f => f(element));
+ }
+
+ onActivated(f) {
+ this.onActivatedCallbacks.push(f);
+ }
+
static availableKey(keyCode) {
return (
KeyboardEvent.DOM_VK_0 <= keyCode && keyCode <= KeyboardEvent.DOM_VK_9 ||
@@ -113,21 +124,26 @@ export default class Follow {
return chars;
}
+ static inWindow(window, element) {
+ let {
+ top, left, bottom, right
+ } = element.getBoundingClientRect();
+ return (
+ top >= 0 && left >= 0 &&
+ bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
+ right <= (window.innerWidth || document.documentElement.clientWidth)
+ );
+ }
+
static getTargetElements(doc) {
- let all = doc.querySelectorAll('a');
- let filtered = Array.prototype.filter.call(all, (e) => {
- return Follow.isVisibleElement(e);
+ let all = doc.querySelectorAll('a,button,input,textarea');
+ let filtered = Array.prototype.filter.call(all, (element) => {
+ let style = window.getComputedStyle(element);
+ return style.display !== 'none' &&
+ style.visibility !== 'hidden' &&
+ element.type !== 'hidden' &&
+ Follow.inWindow(window, element);
});
return filtered;
}
-
- static isVisibleElement(element) {
- let style = window.getComputedStyle(element);
- if (style.display === 'none') {
- return false;
- } else if (style.visibility === 'hidden') {
- return false;
- }
- return true;
- }
}
diff --git a/src/content/hint.js b/src/content/hint.js
index c75ca8b..cc46fd6 100644
--- a/src/content/hint.js
+++ b/src/content/hint.js
@@ -33,10 +33,4 @@ export default class Hint {
remove() {
this.element.remove();
}
-
- activate() {
- if (this.target.tagName.toLowerCase() === 'a') {
- this.target.click();
- }
- }
}
diff --git a/src/content/index.js b/src/content/index.js
index a9ccd63..159429e 100644
--- a/src/content/index.js
+++ b/src/content/index.js
@@ -8,6 +8,38 @@ import messages from '../messages';
consoleFrames.initialize(window.document);
+const startFollows = (newTab) => {
+ let follow = new Follow(window.document, newTab);
+ follow.onActivated((element) => {
+ switch (element.tagName.toLowerCase()) {
+ case 'a':
+ return browser.runtime.sendMessage({
+ type: messages.OPEN_URL,
+ url: element.href,
+ newTab
+ });
+ case 'input':
+ switch (element.type) {
+ case 'file':
+ case 'checkbox':
+ case 'radio':
+ case 'submit':
+ case 'reset':
+ case 'button':
+ case 'image':
+ case 'color':
+ return element.click();
+ default:
+ return element.focus();
+ }
+ case 'textarea':
+ return element.focus();
+ case 'button':
+ return element.click();
+ }
+ });
+};
+
window.addEventListener('keypress', (e) => {
if (e.target instanceof HTMLInputElement) {
return;
@@ -34,7 +66,7 @@ const execOperation = (operation) => {
case operations.SCROLL_RIGHT:
return scrolls.scrollRight(window);
case operations.FOLLOW_START:
- return new Follow(window.document, operation.newTab);
+ return startFollows(operation.newTab);
case operations.NAVIGATE_HISTORY_PREV:
return navigates.historyPrev(window);
case operations.NAVIGATE_HISTORY_NEXT: