EN
JavaScript - mouse click by selector macro player for web page
7
points
In this post simple mouse click macro player has been presented.
Most important features of macro player are:
- defining ordered click operations to execute,
- switching between frames/iframes if they are avaialble on web page,
- waiting until element will be available,
- timeout to prevent infinite waiting.
1. Mouse click macro player example
This example shows how to simulate simple cliking.
// ONLINE-RUNNER:browser;
<!doctype html>
<html>
<head>
<script>
function executeMouseClick(selectors, onFinished, root, limit) {
var iteration = 0;
if (limit == null) {
limit = 1000;
}
function findShadow(selector, callback, root) {
if (iteration < limit) {
var replacement = selector(root);
if (replacement) {
if(callback) {
callback(replacement);
}
} else {
function proxy() {
findShadow(selector, callback, root);
}
setTimeout(proxy, 100);
}
iteration += 1;
} else {
if (onFinished) {
onFinished(false, 'Timeout exceeded!');
}
}
}
function clickElement(selector, callback, root) {
if(iteration < limit) {
var element = root.querySelector(selector);
if (element) {
element.click();
if (callback) {
callback(root);
}
} else {
function proxy() {
clickElement(selector, callback, root);
}
setTimeout(proxy, 100);
}
iteration += 1;
} else {
if (onFinished) {
onFinished(false, 'Timeout exceeded!');
}
}
}
function makeIteration(index, root) {
if (index < selectors.length) {
var selector = selectors[index];
function proxy(root) {
makeIteration(++index, root);
}
if (selector instanceof Function ) {
findShadow(selector, proxy, root);
} else {
clickElement(selector, proxy, root);
}
} else {
if (onFinished) {
onFinished(true, root);
}
}
}
makeIteration(0, root || document);
}
</script>
</head>
<body>
<button title="Button 1" onclick="console.log('Button 1')">Button 1</button>
<button class="button-2" onclick="console.log('Button 2')">Button 2</button>
<button onclick="simulateClicking()">Simulate buttons clicking</button>
<script>
function simulateClicking() {
var selectors = [
'[title="Button 1"]',
'.button-2'
];
function onFinished(result, root) {
if (result) {
console.log('All buttons clicked!');
} else {
console.log('Macro timeout!');
}
}
executeMouseClick(selectors, onFinished);
}
</script>
</body>
</html>
2. Mouse click macro player with waiting for button example
In this example waiting when button will be added has been shown.
// ONLINE-RUNNER:browser;
<!doctype html>
<html>
<head>
<script>
function executeMouseClick(selectors, onFinished, root, limit) {
var iteration = 0;
if (limit == null) {
limit = 1000;
}
function findShadow(selector, callback, root) {
if (iteration < limit) {
var replacement = selector(root);
if (replacement) {
if(callback) {
callback(replacement);
}
} else {
function proxy() {
findShadow(selector, callback, root);
}
setTimeout(proxy, 100);
}
iteration += 1;
} else {
if (onFinished) {
onFinished(false, 'Timeout exceeded!');
}
}
}
function clickElement(selector, callback, root) {
if(iteration < limit) {
var element = root.querySelector(selector);
if (element) {
element.click();
if (callback) {
callback(root);
}
} else {
function proxy() {
clickElement(selector, callback, root);
}
setTimeout(proxy, 100);
}
iteration += 1;
} else {
if (onFinished) {
onFinished(false, 'Timeout exceeded!');
}
}
}
function makeIteration(index, root) {
if (index < selectors.length) {
var selector = selectors[index];
function proxy(root) {
makeIteration(++index, root);
}
if (selector instanceof Function ) {
findShadow(selector, proxy, root);
} else {
clickElement(selector, proxy, root);
}
} else {
if (onFinished) {
onFinished(true, root);
}
}
}
makeIteration(0, root || document);
}
// this function is not part of executeMouseClick function
// more details about function here: https://dirask.com/q/aDWV81
function makeLoop(count, duration, onIteration) {
var index = 0;
var sleep = duration / count;
function action() {
if (index < count) {
onIteration(index++);
setTimeout(action, sleep);
}
}
if (index < count) {
setTimeout(action, sleep);
}
}
// this function is not part of executeMouseClick function
function appendButton(number) {
var button = document.createElement('button');
button.onclick = function() {
console.log('Button ' + number + ' clicked!');
};
button.className = 'button-' + number;
button.innerText = 'Button ' + number;
document.body.appendChild(button);
}
</script>
</head>
<body>
<p>
Click on "Simulate buttons clicking" before
waiting for button will be finished if you
want to see effect of waiting for second button.
</p>
<button title="Button 1" onclick="console.log('Button 1 cliked!')">
Button 1
</button>
<button onclick="simulateClicking()">
Simulate buttons clicking
</button>
<script>
function simulateClicking() {
var selectors = [
'[title="Button 1"]',
'.button-2'
];
function onFinished(result, root) {
if (result) {
console.log('All buttons clicked!');
} else {
console.log('Macro timeout!');
}
}
executeMouseClick(selectors, onFinished);
}
// Button 2 will be added after 5 seconds
makeLoop(5, 5000, function(index) {
var iteration = index + 1;
console.log('... Waiting for button (iteration: ' + iteration + '/5).');
if (iteration == 5) {
appendButton(2);
console.log('--> Button added!');
}
}, 5000);
</script>
</body>
</html>
2. Mouse click macro player with button inside iframe example
In this example accessing to button inside iframe has been shown.
// ONLINE-RUNNER:browser;
<!doctype html>
<html>
<head>
<script>
function executeMouseClick(selectors, onFinished, root, limit) {
var iteration = 0;
if (limit == null) {
limit = 1000;
}
function findShadow(selector, callback, root) {
if (iteration < limit) {
var replacement = selector(root);
if (replacement) {
if(callback) {
callback(replacement);
}
} else {
function proxy() {
findShadow(selector, callback, root);
}
setTimeout(proxy, 100);
}
iteration += 1;
} else {
if (onFinished) {
onFinished(false, 'Timeout exceeded!');
}
}
}
function clickElement(selector, callback, root) {
if(iteration < limit) {
var element = root.querySelector(selector);
if (element) {
element.click();
if (callback) {
callback(root);
}
} else {
function proxy() {
clickElement(selector, callback, root);
}
setTimeout(proxy, 100);
}
iteration += 1;
} else {
if (onFinished) {
onFinished(false, 'Timeout exceeded!');
}
}
}
function makeIteration(index, root) {
if (index < selectors.length) {
var selector = selectors[index];
function proxy(root) {
makeIteration(++index, root);
}
if (selector instanceof Function ) {
findShadow(selector, proxy, root);
} else {
clickElement(selector, proxy, root);
}
} else {
if (onFinished) {
onFinished(true, root);
}
}
}
makeIteration(0, root || document);
}
</script>
</head>
<body>
<button title="Button 1" onclick="console.log('Button 1 cliked!')">
Button 1
</button>
<button onclick="simulateClicking()">
Simulate buttons clicking
</button>
<br /><br />
<iframe id="my-frame"></iframe>
<script>
var frame = document.getElementById('my-frame');
var root = frame.contentDocument;
root.open();
root.write('<button title="Button 2" onclick="alert(\'Iframe button: Clicked!\')">Click me!</button>');
root.close();
function simulateClicking() {
var selectors = [
'[title="Button 1"]',
function(root) { // this function goes inside iframe switching root
// root variable represents active root e.g. document
var frame = root.getElementById('my-frame');
if (frame)
return frame.contentDocument; // it will be from now new root
return null; // null affects waiting for iframe
},
'[title="Button 2"]'
];
function onFinished(result, root) {
if (result) {
console.log('All buttons clicked!');
} else {
console.log('Macro timeout!');
}
}
// this function starts with root document abject as root
executeMouseClick(selectors, onFinished, document);
}
</script>
</body>
</html>