follow links for multi-frames in viewport
This commit is contained in:
parent
ac5354020e
commit
45b3b0510f
4 changed files with 42 additions and 13 deletions
|
@ -29,6 +29,7 @@
|
||||||
"id-length": "off",
|
"id-length": "off",
|
||||||
"indent": ["error", 2],
|
"indent": ["error", 2],
|
||||||
"jsx-quotes": ["error", "prefer-single"],
|
"jsx-quotes": ["error", "prefer-single"],
|
||||||
|
"max-params": ["error", 5],
|
||||||
"max-statements": ["error", 15],
|
"max-statements": ["error", 15],
|
||||||
"multiline-ternary": "off",
|
"multiline-ternary": "off",
|
||||||
"newline-after-var": "off",
|
"newline-after-var": "off",
|
||||||
|
|
|
@ -6,16 +6,25 @@ const TARGET_SELECTOR = [
|
||||||
'[contenteditable=true]', '[contenteditable=""]'
|
'[contenteditable=true]', '[contenteditable=""]'
|
||||||
].join(',');
|
].join(',');
|
||||||
|
|
||||||
const inWindow = (win, element) => {
|
const inViewport = (win, element, viewSize, framePosition) => {
|
||||||
let {
|
let {
|
||||||
top, left, bottom, right
|
top, left, bottom, right
|
||||||
} = element.getBoundingClientRect();
|
} = element.getBoundingClientRect();
|
||||||
let doc = win.doc;
|
let doc = win.doc;
|
||||||
return (
|
let frameWidth = win.innerWidth || doc.documentElement.clientWidth;
|
||||||
top >= 0 && left >= 0 &&
|
let frameHeight = win.innerHeight || doc.documentElement.clientHeight;
|
||||||
bottom <= (win.innerHeight || doc.documentElement.clientHeight) &&
|
|
||||||
right <= (win.innerWidth || doc.documentElement.clientWidth)
|
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 {
|
export default class Follow {
|
||||||
|
@ -60,8 +69,8 @@ export default class Follow {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
countHints(sender) {
|
countHints(sender, viewSize, framePosition) {
|
||||||
this.targets = Follow.getTargetElements(this.win);
|
this.targets = Follow.getTargetElements(this.win, viewSize, framePosition);
|
||||||
sender.postMessage(JSON.stringify({
|
sender.postMessage(JSON.stringify({
|
||||||
type: messages.FOLLOW_RESPONSE_COUNT_TARGETS,
|
type: messages.FOLLOW_RESPONSE_COUNT_TARGETS,
|
||||||
count: this.targets.length,
|
count: this.targets.length,
|
||||||
|
@ -133,7 +142,7 @@ export default class Follow {
|
||||||
onMessage(message, sender) {
|
onMessage(message, sender) {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case messages.FOLLOW_REQUEST_COUNT_TARGETS:
|
case messages.FOLLOW_REQUEST_COUNT_TARGETS:
|
||||||
return this.countHints(sender);
|
return this.countHints(sender, message.viewSize, message.framePosition);
|
||||||
case messages.FOLLOW_CREATE_HINTS:
|
case messages.FOLLOW_CREATE_HINTS:
|
||||||
return this.createHints(message.keysArray, message.newTab);
|
return this.createHints(message.keysArray, message.newTab);
|
||||||
case messages.FOLLOW_SHOW_HINTS:
|
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 all = win.document.querySelectorAll(TARGET_SELECTOR);
|
||||||
let filtered = Array.prototype.filter.call(all, (element) => {
|
let filtered = Array.prototype.filter.call(all, (element) => {
|
||||||
let style = win.getComputedStyle(element);
|
let style = win.getComputedStyle(element);
|
||||||
|
@ -153,7 +162,7 @@ export default class Follow {
|
||||||
style.visibility !== 'hidden' &&
|
style.visibility !== 'hidden' &&
|
||||||
element.type !== 'hidden' &&
|
element.type !== 'hidden' &&
|
||||||
element.offsetHeight > 0 &&
|
element.offsetHeight > 0 &&
|
||||||
inWindow(win, element);
|
inViewport(win, element, viewSize, framePosition);
|
||||||
});
|
});
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,8 +87,24 @@ export default class FollowController {
|
||||||
|
|
||||||
count() {
|
count() {
|
||||||
this.producer = new HintKeyProducer(DEFAULT_HINT_CHARSET);
|
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,
|
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', () => {
|
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);
|
expect(targets).to.have.lengthOf(3);
|
||||||
|
|
||||||
let ids = Array.prototype.map.call(targets, (e) => e.id);
|
let ids = Array.prototype.map.call(targets, (e) => e.id);
|
||||||
|
|
Reference in a new issue