$(document).ready(function () { // duplicate var csrftoken = $('input[name=csrf_token]').val(); $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken) } } }) var browsersteps_session_id; var browserless_seconds_remaining = 0; var apply_buttons_disabled = false; var include_text_elements = $("#include_text_elements"); var xpath_data = false; var current_selected_i; var state_clicked = false; var c; // redline highlight context var ctx; var last_click_xy = {'x': -1, 'y': -1} $(window).resize(function () { set_scale(); }); // Should always be disabled $('#browser_steps >li:first-child select').val('Goto site').attr('disabled', 'disabled'); $('#browsersteps-click-start').click(function () { $("#browsersteps-click-start").fadeOut(); $("#browsersteps-selector-wrapper .spinner").fadeIn(); start(); }); $('a#browsersteps-tab').click(function () { reset(); }); window.addEventListener('hashchange', function () { if (window.location.hash == '#browser-steps') { reset(); } }); function reset() { xpath_data = false; $('#browsersteps-img').removeAttr('src'); $("#browsersteps-click-start").show(); $("#browsersteps-selector-wrapper .spinner").hide(); browserless_seconds_remaining = 0; browsersteps_session_id = false; apply_buttons_disabled = false; ctx.clearRect(0, 0, c.width, c.height); set_first_gotosite_disabled(); } function set_first_gotosite_disabled() { $('#browser_steps >li:first-child select').val('Goto site').attr('disabled', 'disabled'); $('#browser_steps >li:first-child').css('opacity', '0.5'); } // Show seconds remaining until playwright/browserless needs to restart the session // (See comment at the top of changedetectionio/blueprint/browser_steps/__init__.py ) setInterval(() => { if (browserless_seconds_remaining >= 1) { document.getElementById('browserless-seconds-remaining').innerText = browserless_seconds_remaining + " seconds remaining in session"; browserless_seconds_remaining -= 1; } }, "1000") function set_scale() { // some things to check if the scaling doesnt work // - that the widths/sizes really are about the actual screen size cat elements.json |grep -o width......|sort|uniq selector_image = $("img#browsersteps-img")[0]; selector_image_rect = selector_image.getBoundingClientRect(); // make the canvas and input steps the same size as the image $('#browsersteps-selector-canvas').attr('height', selector_image_rect.height).attr('width', selector_image_rect.width); //$('#browsersteps-selector-wrapper').attr('width', selector_image_rect.width); $('#browser-steps-ui').attr('width', selector_image_rect.width); x_scale = selector_image_rect.width / xpath_data['browser_width']; y_scale = selector_image_rect.height / selector_image.naturalHeight; ctx.strokeStyle = 'rgba(255,0,0, 0.9)'; ctx.fillStyle = 'rgba(255,0,0, 0.1)'; ctx.lineWidth = 3; console.log("scaling set x: " + x_scale + " by y:" + y_scale); } // bootstrap it, this will trigger everything else $('#browsersteps-img').bind('load', function () { $('body').addClass('full-width'); console.log("Loaded background..."); document.getElementById("browsersteps-selector-canvas"); c = document.getElementById("browsersteps-selector-canvas"); // redline highlight context ctx = c.getContext("2d"); // @todo is click better? $('#browsersteps-selector-canvas').off("mousemove mousedown click"); // Undo disable_browsersteps_ui $("#browser-steps-ui").css('opacity', '1.0'); // init set_scale(); // @todo click ? some better library? $('#browsersteps-selector-canvas').bind('click', function (e) { // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent e.preventDefault() }); $('#browsersteps-selector-canvas').bind('mousedown', function (e) { // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent e.preventDefault() console.log(e); console.log("current xpath in index is " + current_selected_i); last_click_xy = {'x': parseInt((1 / x_scale) * e.offsetX), 'y': parseInt((1 / y_scale) * e.offsetY)} process_selected(current_selected_i); current_selected_i = false; // if process selected returned false, then best we can do is offer a x,y click :( if (!found_something) { var first_available = $("ul#browser_steps li.empty").first(); $('select', first_available).val('Click X,Y').change(); $('input[type=text]', first_available).first().val(last_click_xy['x'] + ',' + last_click_xy['y']); draw_circle_on_canvas(e.offsetX, e.offsetY); } }); $('#browsersteps-selector-canvas').bind('mousemove', function (e) { if (!xpath_data) { return; } // checkbox if find elements is enabled ctx.clearRect(0, 0, c.width, c.height); ctx.fillStyle = 'rgba(255,0,0, 0.1)'; ctx.strokeStyle = 'rgba(255,0,0, 0.9)'; // Add in offset if ((typeof e.offsetX === "undefined" || typeof e.offsetY === "undefined") || (e.offsetX === 0 && e.offsetY === 0)) { var targetOffset = $(e.target).offset(); e.offsetX = e.pageX - targetOffset.left; e.offsetY = e.pageY - targetOffset.top; } current_selected_i = false; // Reverse order - the most specific one should be deeper/"laster" // Basically, find the most 'deepest' //$('#browsersteps-selector-canvas').css('cursor', 'pointer'); for (var i = xpath_data['size_pos'].length; i !== 0; i--) { // draw all of them? let them choose somehow? var sel = xpath_data['size_pos'][i - 1]; // If we are in a bounding-box if (e.offsetY > sel.top * y_scale && e.offsetY < sel.top * y_scale + sel.height * y_scale && e.offsetX > sel.left * y_scale && e.offsetX < sel.left * y_scale + sel.width * y_scale ) { // Only highlight these interesting types if (1) { ctx.strokeRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale); ctx.fillRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale); current_selected_i = i - 1; break; // find the smallest one at this x,y // does it mean sort the xpath list by size (w*h) i think so! } else { if (include_text_elements[0].checked === true) { // blue one with background instead? ctx.fillStyle = 'rgba(0,0,255, 0.1)'; ctx.strokeStyle = 'rgba(0,0,200, 0.7)'; $('#browsersteps-selector-canvas').css('cursor', 'grab'); ctx.strokeRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale); ctx.fillRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale); current_selected_i = i - 1; break; } } } } }.debounce(10)); }); // $("#browser-steps-fieldlist").bind('mouseover', function(e) { // console.log(e.xpath_data_index); // }); // callback for clicking on an xpath on the canvas function process_selected(xpath_data_index) { found_something = false; var first_available = $("ul#browser_steps li.empty").first(); if (xpath_data_index !== false) { // Nothing focused, so fill in a new one // if inpt type button or