UNPKG

donobu

Version:

Create browser automations with an LLM agent and replay them as Playwright scripts.

223 lines (198 loc) 6.53 kB
/** * Donobu script for tracking interactions with the current page. This scripts assumes the * following: * 1. There is an exposed binding to call back to Java named "donobuTrackInteraction". * 2. The smart-selector-generator.js script has defined the "donobuGenerateSmartSelectors" * method on the window object. * 3. The Donobu backend uses the "data-donobu-marker" as a DOM element attribute to uniquely * identify interesting DOM elements. */ (() => { if (window.donobuListenersRegistered) { return; } window.donobuStartDragPosition = { x: 0, y: 0 }; // Helper function to check if an event target is inside the Donobu control panel. const isDonobuControlPanelInteraction = (element) => { while (element != null) { if (element.id === 'donobu-control-panel') { return true; } element = element.parentElement; } return false; }; // Ensure that the target element has a unique `data-donobu-marker` attribute. If the attribute // does not exist, then it will be created with a random value. If the attribute already exists, // then this function has no effect. Returns the value of the attribute. const ensureElementHasUniqueDonobuAttribute = (element) => { const donobuMarkerAttributeName = 'data-donobu-marker'; let donobuMarkerAttributeValue = element.getAttribute( donobuMarkerAttributeName, ); if (!donobuMarkerAttributeValue) { donobuMarkerAttributeValue = `${Math.random().toString(36).slice(2, 11)}`; element.setAttribute( donobuMarkerAttributeName, donobuMarkerAttributeValue, ); } return donobuMarkerAttributeValue; }; // Mouse events ['click', 'dblclick', 'contextmenu', 'mousedown', 'mouseup'].forEach( (eventType) => { document.addEventListener( eventType, function (e) { let donobuMarker; // Skip events if they occur in the Donobu control panel. if (isDonobuControlPanelInteraction(e.target)) { return; } else { donobuMarker = ensureElementHasUniqueDonobuAttribute(e.target); } const eventData = { type: eventType, x: e.clientX, y: e.clientY, selectors: window.donobuGenerateSmartSelectors(e.target), timestamp: new Date().getTime(), donobuMarker: donobuMarker, }; if (eventType === 'mousedown') { donobuStartDragPosition = { x: e.clientX, y: e.clientY }; } else if (eventType === 'mouseup') { eventData.dragDistance = Math.sqrt( Math.pow(e.clientX - donobuStartDragPosition.x, 2) + Math.pow(e.clientY - donobuStartDragPosition.y, 2), ); } donobuTrackInteraction(eventData); }, true, ); }, ); // Keyboard events ['keydown', 'keyup'].forEach((eventType) => { document.addEventListener( eventType, function (e) { let donobuMarker; // Skip events if they occur in the Donobu control panel. if (isDonobuControlPanelInteraction(e.target)) { return; } else { donobuMarker = ensureElementHasUniqueDonobuAttribute(e.target); } donobuTrackInteraction({ type: eventType, key: e.key, keyCode: e.keyCode, altKey: e.altKey, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey, selectors: window.donobuGenerateSmartSelectors(e.target), timestamp: new Date().getTime(), donobuMarker: donobuMarker, }); }, true, ); }); // Form events ['change', 'submit'].forEach((eventType) => { document.addEventListener( eventType, function (e) { let donobuMarker; // Skip events if they occur in the Donobu control panel. if (isDonobuControlPanelInteraction(e.target)) { return; } else { donobuMarker = ensureElementHasUniqueDonobuAttribute(e.target); } const eventData = { type: eventType, selectors: window.donobuGenerateSmartSelectors(e.target), timestamp: new Date().getTime(), donobuMarker: donobuMarker, }; if (eventType === 'change') { eventData.value = e.target.value; } if (eventType === 'submit') { const formData = new FormData(e.target); eventData.formData = {}; for (let [key, value] of formData.entries()) { eventData.formData[key] = value; } } donobuTrackInteraction(eventData); }, true, ); }); // These are commented out since they materially slow the page. // // // Scroll events // window.addEventListener( // "scroll", // function (e) { // donobuTrackInteraction({ // type: "scroll", // scrollX: window.scrollX, // scrollY: window.scrollY, // timestamp: new Date().getTime(), // }); // }, // true // ); // // // Window resize event // window.addEventListener( // "resize", // function (e) { // donobuTrackInteraction({ // type: "resize", // width: window.innerWidth, // height: window.innerHeight, // timestamp: new Date().getTime(), // }); // }, // true // ); // Touch events for mobile ['touchstart', 'touchend', 'touchmove', 'touchcancel'].forEach( (eventType) => { document.addEventListener( eventType, function (e) { let donobuMarker; // Skip events if they occur in the Donobu control panel. if (isDonobuControlPanelInteraction(e.target)) { return; } else { donobuMarker = ensureElementHasUniqueDonobuAttribute(e.target); } const touches = Array.from(e.touches).map((touch) => ({ x: touch.clientX, y: touch.clientY, identifier: touch.identifier, donobuMarker: donobuMarker, })); donobuTrackInteraction({ type: eventType, touches: touches, selectors: window.donobuGenerateSmartSelectors(e.target), timestamp: new Date().getTime(), }); }, true, ); }, ); window.donobuListenersRegistered = true; })();