follow links for multi-frames in viewport

jh-changes
Shin'ya Ueoka 7 years ago
parent ac5354020e
commit 45b3b0510f
  1. 1
      .eslintrc
  2. 31
      src/content/components/common/follow.js
  3. 18
      src/content/components/top-content/follow-controller.js
  4. 5
      test/content/components/common/follow.test.js

@ -29,6 +29,7 @@
"id-length": "off",
"indent": ["error", 2],
"jsx-quotes": ["error", "prefer-single"],
"max-params": ["error", 5],
"max-statements": ["error", 15],
"multiline-ternary": "off",
"newline-after-var": "off",

@ -6,16 +6,25 @@ const TARGET_SELECTOR = [
'[contenteditable=true]', '[contenteditable=""]'
].join(',');
const inWindow = (win, element) => {
const inViewport = (win, element, viewSize, framePosition) => {
let {
top, left, bottom, right
} = element.getBoundingClientRect();
let doc = win.doc;
return (
top >= 0 && left >= 0 &&
bottom <= (win.innerHeight || doc.documentElement.clientHeight) &&
right <= (win.innerWidth || doc.documentElement.clientWidth)
);
let frameWidth = win.innerWidth || doc.documentElement.clientWidth;
let frameHeight = win.innerHeight || doc.documentElement.clientHeight;
if (right < 0 || bottom < 0 || top > frameHeight || left > frameWidth) {
// out of frame
return false;
}
if (right + framePosition.x < 0 || bottom + framePosition.y < 0 ||
left + framePosition.x > viewSize.width ||
top + framePosition.y > viewSize.height) {
// out of viewport
return false;
}
return true;
};
export default class Follow {
@ -60,8 +69,8 @@ export default class Follow {
});
}
countHints(sender) {
this.targets = Follow.getTargetElements(this.win);
countHints(sender, viewSize, framePosition) {
this.targets = Follow.getTargetElements(this.win, viewSize, framePosition);
sender.postMessage(JSON.stringify({
type: messages.FOLLOW_RESPONSE_COUNT_TARGETS,
count: this.targets.length,
@ -133,7 +142,7 @@ export default class Follow {
onMessage(message, sender) {
switch (message.type) {
case messages.FOLLOW_REQUEST_COUNT_TARGETS:
return this.countHints(sender);
return this.countHints(sender, message.viewSize, message.framePosition);
case messages.FOLLOW_CREATE_HINTS:
return this.createHints(message.keysArray, message.newTab);
case messages.FOLLOW_SHOW_HINTS:
@ -145,7 +154,7 @@ export default class Follow {
}
}
static getTargetElements(win) {
static getTargetElements(win, viewSize, framePosition) {
let all = win.document.querySelectorAll(TARGET_SELECTOR);
let filtered = Array.prototype.filter.call(all, (element) => {
let style = win.getComputedStyle(element);
@ -153,7 +162,7 @@ export default class Follow {
style.visibility !== 'hidden' &&
element.type !== 'hidden' &&
element.offsetHeight > 0 &&
inWindow(win, element);
inViewport(win, element, viewSize, framePosition);
});
return filtered;
}

@ -87,8 +87,24 @@ export default class FollowController {
count() {
this.producer = new HintKeyProducer(DEFAULT_HINT_CHARSET);
broadcastMessage(this.win, {
let doc = this.win.document;
let viewWidth = this.win.innerWidth || doc.documentElement.clientWidth;
let viewHeight = this.win.innerHeight || doc.documentElement.clientHeight;
let frameElements = this.win.document.querySelectorAll('frame,iframe');
this.win.postMessage(JSON.stringify({
type: messages.FOLLOW_REQUEST_COUNT_TARGETS,
viewSize: { width: viewWidth, height: viewHeight },
framePosition: { x: 0, y: 0 },
}), '*');
frameElements.forEach((element) => {
let { left: frameX, top: frameY } = element.getBoundingClientRect();
let message = JSON.stringify({
type: messages.FOLLOW_REQUEST_COUNT_TARGETS,
viewSize: { width: viewWidth, height: viewHeight },
framePosition: { x: frameX, y: frameY },
});
element.contentWindow.postMessage(message, '*');
});
}

@ -8,7 +8,10 @@ describe('FollowComponent', () => {
});
it('returns visible links', () => {
let targets = FollowComponent.getTargetElements(window);
let targets = FollowComponent.getTargetElements(
window,
{ width: window.innerWidth, height: window.innerHeight },
{ x: 0, y: 0 });
expect(targets).to.have.lengthOf(3);
let ids = Array.prototype.map.call(targets, (e) => e.id);