I have a small bit of JavaScript that lets me make a selection on a web page. I want it to store the ID of the clicked element (if no ID exists, I dynamically assign one). The script works perfectly, but there's a timing issue because I need the script to run, let me make the selection and THEN have the result returned and passed to KM. But as far as I can tell, I can't pause that - the script runs and immediately moves to the next action in KM.
Is there a way for me to add a delay in the browser to get the ID?
The script is below. Note that when I do console.log, it correctly gets an ID, but I can't seem to pass that value into a KM var.
Any thoughts on how I could do this?
console.clear();
let result='';
function pickHTMLnode() {
return new Promise((resolve) => {
// Create a panel to display the XPath
const xpathPanel = document.createElement('div');
xpathPanel.setAttribute('id', 'xpathPanel');
xpathPanel.style.position = 'fixed';
xpathPanel.style.bottom = '10px';
xpathPanel.style.right = '10px';
xpathPanel.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
xpathPanel.style.color = 'white';
xpathPanel.style.padding = '10px';
xpathPanel.style.borderRadius = '5px';
xpathPanel.style.zIndex = '10000';
xpathPanel.style.fontFamily = 'Arial, sans-serif';
xpathPanel.style.fontSize = '14px';
xpathPanel.textContent = 'XPATH: ';
document.body.appendChild(xpathPanel);
// Function to generate XPath for an element
function getXPath(element) {
if (element.id !== '') {
return `//*[@id="${element.id}"]`;
}
if (element === document.body) {
return '/html/body';
}
let ix = 0;
const siblings = element.parentNode.childNodes;
for (let i = 0; i < siblings.length; i++) {
const sibling = siblings[i];
if (sibling === element) {
return `${getXPath(element.parentNode)}/${element.tagName.toLowerCase()}[${ix + 1}]`;
}
if (sibling.nodeType === 1 && sibling.tagName === element.tagName) {
ix++;
}
}
}
// Function to handle hover events
function handleHover(event) {
const element = event.target;
// Add dotted outline
element.style.outline = '5px dotted red';
// Display XPath in the panel
const xpath = getXPath(element);
xpathPanel.textContent = `XPATH: ${xpath}`;
}
// Function to handle mouseout events
function handleMouseOut(event) {
const element = event.target;
// Remove the outline
element.style.outline = '';
}
// Function to handle click events
function handleClick(event) {
event.preventDefault(); // Prevent the default behavior
event.stopPropagation(); // Stop the event from bubbling up
const element = event.target;
let selectedElementId;
if (element.id) {
selectedElementId = element.id;
} else {
selectedElementId = `element-${Date.now()}`;
element.id = selectedElementId;
}
console.log('Selected Element ID:', selectedElementId);
// Remove event listeners
document.removeEventListener('mouseover', handleHover, true);
document.removeEventListener('mouseout', handleMouseOut, true);
document.removeEventListener('click', handleClick, true);
document.getElementById('xpathPanel').remove();
// Remove the outline
element.style.outline = '';
// Resolve the promise with the selected element ID
resolve(selectedElementId);
}
// Add event listeners
document.addEventListener('mouseover', handleHover, true);
document.addEventListener('mouseout', handleMouseOut, true);
document.addEventListener('click', handleClick, true);
});
}
async function getElementId() {
try {
result = await pickHTMLnode();
console.log('Final result:', result);
return result;
} catch (error) {
console.error('Error selecting element:', error);
return result;
}
}
getElementId().then(elementId => {
console.log('Element ID returned:', elementId);
return elementId;
});
I did wonder if I could delay things by adding the pause until mouse clicked action, but that makes no difference. I guess the horse has already bolted, so to speak.