Replicating click across devices

This commit is contained in:
Manoj Vivek 2019-08-16 21:43:38 +05:30
parent 49afb61f1f
commit 8adafd5806
5 changed files with 97 additions and 23 deletions

View file

@ -2,5 +2,9 @@
margin: 10px;
}
.deviceTitle {
font-weight: normal;
font-size: 16px;
}
.deviceWrapper {
}

View file

@ -1,6 +1,7 @@
// @flow
import React, {Component, createRef} from 'react';
import {ipcRenderer} from 'electron';
import pubsub from 'pubsub.js';
import BugIcon from '../icons/Bug';
import cx from 'classnames';
@ -8,6 +9,7 @@ import styles from './style.module.css';
const MESSAGE_TYPES = {
scroll: 'scroll',
click: 'click',
};
class WebView extends Component {
@ -21,6 +23,8 @@ class WebView extends Component {
'ipc-message',
this.messageHandler
);
pubsub.subscribe('scroll', this.processScrollEvent);
pubsub.subscribe('click', this.processClickEvent);
this.webviewRef.current.addEventListener('dom-ready', () => {
this.initEventTriggers(this.webviewRef.current);
@ -32,33 +36,28 @@ class WebView extends Component {
});
}
componentDidUpdate(prevProps, prevState) {
this.processIfScrollChange(prevProps);
}
processIfScrollChange = prevProps => {
const {
browser: {
scrollPosition: {x: prevX, y: prevY},
},
} = prevProps;
const {
browser: {
scrollPosition: {x, y},
},
} = this.props;
if (x === prevX && y === prevY) {
processScrollEvent = message => {
if (message.sourceDeviceId === this.props.device.id) {
return;
}
console.log('Scrolling to ', {x, y});
this.webviewRef.current.send('scroll', {x, y});
this.webviewRef.current.send('scrollMessage', message.position);
};
processClickEvent = message => {
if (message.sourceDeviceId === this.props.device.id) {
return;
}
this.webviewRef.current.send('clickMessage', message);
};
messageHandler = ({channel: type, args: [message]}) => {
console.log('Message recieved', message);
switch (type) {
case MESSAGE_TYPES.scroll:
this.props.onScrollChange(message);
pubsub.publish('scroll', [message]);
return;
case MESSAGE_TYPES.click:
pubsub.publish('click', [message]);
return;
}
};
@ -66,6 +65,7 @@ class WebView extends Component {
initEventTriggers = webview => {
console.log('Initializing triggers');
webview.getWebContents().executeJavaScript(`
responsivelyApp.deviceId = ${this.props.device.id};
document.body.addEventListener('mouseleave', () => responsivelyApp.mouseOn = false)
document.body.addEventListener('mouseenter', () => responsivelyApp.mouseOn = true)
@ -73,11 +73,32 @@ class WebView extends Component {
if (!responsivelyApp.mouseOn) {
return;
}
responsivelyApp.sendMessageToHost(
window.responsivelyApp.sendMessageToHost(
'${MESSAGE_TYPES.scroll}',
{x: window.scrollX, y: window.scrollY}
{
sourceDeviceId: window.responsivelyApp.deviceId,
position: {x: window.scrollX, y: window.scrollY},
}
);
})
});
document.querySelectorAll('*')
.forEach(elem => {
elem.addEventListener('click', e => {
if (e.responsivelyAppProcessed) {
return;
}
e.responsivelyAppProcessed = true;
console.log('clicked', e);
window.responsivelyApp.sendMessageToHost(
'${MESSAGE_TYPES.click}',
{
sourceDeviceId: window.responsivelyApp.deviceId,
cssPath: window.responsivelyApp.cssPath(e.target),
}
);
});
});
`);
};

View file

@ -2,12 +2,55 @@ const {ipcRenderer} = require('electron');
console.log('Preloader');
global.responsivelyApp = {
sendMessageToHost: (type, message) => ipcRenderer.sendToHost(type, message),
cssPath: el => {
if (!(el instanceof Element)) return;
var path = [];
while (el.nodeType === Node.ELEMENT_NODE) {
var selector = el.nodeName.toLowerCase();
if (selector === 'html') {
} else if (el.id) {
selector += '#' + el.id;
} else {
var sib = el,
nth = 1;
while (
sib.nodeType === Node.ELEMENT_NODE &&
(sib = sib.previousSibling) &&
nth++
);
selector += ':nth-child(' + nth + ')';
}
path.unshift(selector);
el = el.parentNode;
}
return path.join(' > ');
},
eventFire: (el, etype) => {
if (el.fireEvent) {
el.fireEvent('on' + etype);
} else {
var evObj = document.createEvent('Events');
evObj.initEvent(etype, true, false);
evObj.responsivelyAppProcessed = true;
el.dispatchEvent(evObj);
}
},
};
ipcRenderer.on('scroll', (event, args) => {
ipcRenderer.on('scrollMessage', (event, args) => {
console.log('Recieved scroll message from host', event, args);
window.scrollTo({
top: args.y,
left: args.x,
});
});
ipcRenderer.on('clickMessage', (event, args) => {
console.log('Recieved click message from host', event, args);
const elem = document.querySelector(args.cssPath);
if (!elem) {
console.log('Element to click is not found', args);
return;
}
window.responsivelyApp.eventFire(elem, 'click');
});

View file

@ -235,6 +235,7 @@
"electron-log": "^3.0.7",
"electron-updater": "^4.1.2",
"history": "^4.7.2",
"pubsub.js": "^1.5.2",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-hot-loader": "^4.3.12",

View file

@ -9833,6 +9833,11 @@ public-encrypt@^4.0.0:
randombytes "^2.0.1"
safe-buffer "^5.1.2"
pubsub.js@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/pubsub.js/-/pubsub.js-1.5.2.tgz#f7a6c5e12cabe5b48b24326e2e2d6cd6542f0a4b"
integrity sha1-96bF4Syr5bSLJDJuLi1s1lQvCks=
pump@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"