Configurable "Browser Steps" when Playwright/Chrome is configured (enter text, scroll, wait for text, click button etc) (#478)

This commit is contained in:
dgtlmoon
2022-11-24 20:53:01 +01:00
committed by GitHub
parent c98536ace4
commit 5b530ff61c
27 changed files with 1852 additions and 476 deletions

View File

@@ -0,0 +1,425 @@
$(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;
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();
});
$('a#browsersteps-tab').click(function () {
start();
});
// 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")
if (window.location.hash == '#browser-steps') {
start();
}
window.addEventListener('hashchange', function () {
if (window.location.hash == '#browser-steps') {
start();
}
// For when the page loads
if (!window.location.hash || window.location.hash != '#browser-steps') {
$("img#browsersteps-img").attr('src', '');
return;
}
});
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 select,input").removeAttr('disabled').css('opacity', '1.0');
$("#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) {
// 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 <button>
// from the top, find the next not used one and use it
var x = xpath_data['size_pos'][xpath_data_index];
console.log(x);
if (x && first_available.length) {
// @todo will it let you click shit that has a layer ontop? probably not.
if (x['tagtype'] === 'text' || x['tagtype'] === 'email' || x['tagName'] === 'textarea' || x['tagtype'] === 'password' || x['tagtype'] === 'search' ) {
$('select', first_available).val('Enter text in field').change();
$('input[type=text]', first_available).first().val(x['xpath']);
$('input[placeholder="Value"]', first_available).addClass('ok').click().focus();
found_something = true;
} else {
// Assume it's just for clicking on
// what are we clicking on?
if (x['tagName'].startsWith('h')|| x['tagName'] === 'a' || x['tagName'] === 'button' || x['tagtype'] === 'submit'|| x['tagtype'] === 'checkbox'|| x['tagtype'] === 'radio'|| x['tagtype'] === 'li') {
$('select', first_available).val('Click element').change();
$('input[type=text]', first_available).first().val(x['xpath']);
found_something = true;
}
}
first_available.xpath_data_index=xpath_data_index;
if (!found_something) {
if ( include_text_elements[0].checked === true) {
// Suggest that we use as filter?
// @todo filters should always be in the last steps, nothing non-filter after it
found_something = true;
ctx.strokeStyle = 'rgba(0,0,255, 0.9)';
ctx.fillStyle = 'rgba(0,0,255, 0.1)';
$('select', first_available).val('Extract text and use as filter').change();
$('input[type=text]', first_available).first().val(x['xpath']);
include_text_elements[0].checked = false;
}
}
}
} else {
}
}
function draw_circle_on_canvas(x, y) {
ctx.beginPath();
ctx.arc(x, y, 8, 0, 2 * Math.PI, false);
ctx.fillStyle = 'rgba(255,0,0, 0.6)';
ctx.fill();
}
function start() {
console.log("Starting browser-steps UI");
browsersteps_session_id=Date.now();
// @todo This setting of the first one should be done at the datalayer but wtforms doesnt wanna play nice
$('#browser_steps >li:first-child').removeClass('empty');
$('#browser_steps >li:first-child select').val('Goto site').attr('disabled', 'disabled');
$('#browser-steps-ui .loader').show();
$('.clear,.remove', $('#browser_steps >li:first-child')).hide();
$.ajax({
type: "GET",
url: browser_steps_sync_url+"&browsersteps_session_id="+browsersteps_session_id,
statusCode: {
400: function () {
// More than likely the CSRF token was lost when the server restarted
alert("There was a problem processing the request, please reload the page.");
}
}
}).done(function (data) {
xpath_data = data.xpath_data;
$('#browsersteps-img').attr('src', data.screenshot);
// This should trigger 'Goto site'
$('#browser_steps >li:first-child .apply').click();
browserless_seconds_remaining = data.browser_time_remaining;
}).fail(function (data) {
console.log(data);
alert('There was an error communicating with the server.');
});
}
function disable_browsersteps_ui() {
$("#browser_steps select,input").attr('disabled', 'disabled').css('opacity', '0.5');
$("#browser-steps-ui").css('opacity', '0.3');
$('#browsersteps-selector-canvas').off("mousemove mousedown click");
}
////////////////////////// STEPS UI ////////////////////
$('ul#browser_steps [type="text"]').keydown(function (e) {
if (e.keyCode === 13) {
// hitting [enter] in a browser-step input should trigger the 'Apply'
e.preventDefault();
$(".apply", $(this).closest('li')).click();
return false;
}
});
// Look up which step was selected, and enable or disable the related extra fields
// So that people using it dont' get confused
$('ul#browser_steps select').on("change", function () {
var config = browser_steps_config[$(this).val()].split(' ');
var elem_selector = $('tr:nth-child(2) input', $(this).closest('tbody'));
var elem_value = $('tr:nth-child(3) input', $(this).closest('tbody'));
if (config[0] == 0) {
$(elem_selector).fadeOut();
} else {
$(elem_selector).fadeIn();
}
if (config[1] == 0) {
$(elem_value).fadeOut();
} else {
$(elem_value).fadeIn();
}
if ($(this).val() === 'Click X,Y' && last_click_xy['x'] > 0 && $(elem_value).val().length === 0) {
// @todo handle scale
$(elem_value).val(last_click_xy['x'] + ',' + last_click_xy['y']);
}
}).change();
function set_greyed_state() {
$('ul#browser_steps select').not('option:selected[value="Choose one"]').closest('li').removeClass('empty');
$('ul#browser_steps select option:selected[value="Choose one"]').closest('li').addClass('empty');
}
// Add the extra buttons to the steps
$('ul#browser_steps li').each(function (i) {
$(this).append('<div class="control">' +
'<a data-step-index=' + i + ' class="pure-button button-secondary button-green button-xsmall apply" >Apply</a>&nbsp;' +
'<a data-step-index=' + i + ' class="pure-button button-secondary button-xsmall clear" >Clear</a>&nbsp;' +
'<a data-step-index=' + i + ' class="pure-button button-secondary button-red button-xsmall remove" >Remove</a>' +
'</div>')
}
);
$('ul#browser_steps li .control .clear').click(function (element) {
$("select", $(this).closest('li')).val("Choose one").change();
$(":text", $(this).closest('li')).val('');
});
$('ul#browser_steps li .control .remove').click(function (element) {
// so you wanna remove the 2nd (3rd spot 0,1,2,...)
var p = $("#browser_steps li").index($(this).closest('li'));
var elem_to_remove = $("#browser_steps li")[p];
$('.clear', elem_to_remove).click();
$("#browser_steps li").slice(p, 10).each(function (index) {
// get the next one's value from where we clicked
var next = $("#browser_steps li")[p + index + 1];
if (next) {
// and set THIS ones value from the next one
var n = $('input', next);
$("select", $(this)).val($('select', next).val());
$('input', this)[0].value = $(n)[0].value;
$('input', this)[1].value = $(n)[1].value;
// Triggers reconfiguring the field based on the system config
$("select", $(this)).change();
}
});
// Reset their hidden/empty states
set_greyed_state();
});
$('ul#browser_steps li .control .apply').click(function (event) {
// sequential requests @todo refactor
if(apply_buttons_disabled) {
return;
}
var current_data = $(event.currentTarget).closest('li');
$('#browser-steps-ui .loader').fadeIn();
apply_buttons_disabled=true;
$('ul#browser_steps li .control .apply').css('opacity',0.5);
$("#browsersteps-img").css('opacity',0.65);
var is_last_step = 0;
var step_n = $(event.currentTarget).data('step-index');
// On the last step, we should also be getting data ready for the visual selector
$('ul#browser_steps li select').each(function (i) {
if ($(this).val() !== 'Choose one') {
is_last_step += 1;
}
});
if (is_last_step == (step_n+1)) {
is_last_step = true;
} else {
is_last_step = false;
}
// POST the currently clicked step form widget back and await response, redraw
$.ajax({
method: "POST",
url: browser_steps_sync_url+"&browsersteps_session_id="+browsersteps_session_id,
data: {
'operation': $("select[id$='operation']", current_data).first().val(),
'selector': $("input[id$='selector']", current_data).first().val(),
'optional_value': $("input[id$='optional_value']", current_data).first().val(),
'step_n': step_n,
'is_last_step': is_last_step
},
statusCode: {
400: function () {
// More than likely the CSRF token was lost when the server restarted
alert("There was a problem processing the request, please reload the page.");
}
}
}).done(function (data) {
// it should return the new state (selectors available and screenshot)
xpath_data = data.xpath_data;
$('#browsersteps-img').attr('src', data.screenshot);
$('#browser-steps-ui .loader').fadeOut();
apply_buttons_disabled=false;
$("#browsersteps-img").css('opacity',1);
$('ul#browser_steps li .control .apply').css('opacity',1);
browserless_seconds_remaining = data.browser_time_remaining;
}).fail(function (data) {
console.log(data);
if (data.responseText.includes("Browser session expired")) {
disable_browsersteps_ui();
}
apply_buttons_disabled=false;
$('ul#browser_steps li .control .apply').css('opacity',1);
$("#browsersteps-img").css('opacity',1);
//$('#browsersteps-selector-wrapper .loader').fadeOut(2500);
});
});
$("ul#browser_steps select").change(function () {
set_greyed_state();
}).change();
});

View File

@@ -0,0 +1,34 @@
$(document).ready(function(){
checkUserVal();
$('#fetch_backend input').on('change', checkUserVal);
});
var checkUserVal = function(){
if($('#fetch_backend input:checked').val()=='html_requests') {
$('#request-override').show();
$('#webdriver-stepper').hide();
} else {
$('#request-override').hide();
$('#webdriver-stepper').show();
}
};
$('a.row-options').on('click', function(){
var row=$(this.closest('tr'));
switch($(this).data("action")) {
case 'remove':
$(row).remove();
break;
case 'add':
var new_row=$(row).clone(true).insertAfter($(row));
$('input', new_new).val("");
break;
case 'add':
var new_row=$(row).clone(true).insertAfter($(row));
$('input', new_new).val("");
break;
case 'resend-step':
break;
}
});

View File

@@ -3,7 +3,8 @@
window.addEventListener('hashchange', function () {
var tabs = document.getElementsByClassName('active');
while (tabs[0]) {
tabs[0].classList.remove('active')
tabs[0].classList.remove('active');
document.body.classList.remove('full-width');
}
set_active_tab();
}, false);
@@ -20,6 +21,7 @@ if (!has_errors.length) {
}
function set_active_tab() {
document.body.classList.remove('full-width');
var tab = document.querySelectorAll("a[href='" + location.hash + "']");
if (tab.length) {
tab[0].parentElement.className = "active";
@@ -45,4 +47,3 @@ function focus_error_tab() {

View File

@@ -1,10 +1,10 @@
// Horrible proof of concept code :)
// yes - this is really a hack, if you are a front-ender and want to help, please get in touch!
$(document).ready(function() {
$(document).ready(function () {
var current_selected_i;
var state_clicked=false;
var state_clicked = false;
var c;
@@ -13,9 +13,9 @@ $(document).ready(function() {
// redline highlight context
var ctx;
var current_default_xpath=[];
var x_scale=1;
var y_scale=1;
var current_default_xpath = [];
var x_scale = 1;
var y_scale = 1;
var selector_image;
var selector_image_rect;
var selector_data;
@@ -27,27 +27,27 @@ $(document).ready(function() {
bootstrap_visualselector();
});
$(document).on('keydown', function(event) {
$(document).on('keydown', function (event) {
if ($("img#selector-background").is(":visible")) {
if (event.key == "Escape") {
state_clicked=false;
state_clicked = false;
ctx.clearRect(0, 0, c.width, c.height);
}
}
});
// For when the page loads
if(!window.location.hash || window.location.hash != '#visualselector') {
$("img#selector-background").attr('src','');
if (!window.location.hash || window.location.hash != '#visualselector') {
$("img#selector-background").attr('src', '');
return;
}
// Handle clearing button/link
$('#clear-selector').on('click', function(event) {
if(!state_clicked) {
$('#clear-selector').on('click', function (event) {
if (!state_clicked) {
alert('Oops, Nothing selected!');
}
state_clicked=false;
state_clicked = false;
ctx.clearRect(0, 0, c.width, c.height);
xctx.clearRect(0, 0, c.width, c.height);
$("#include_filters").val('');
@@ -77,58 +77,61 @@ $(document).ready(function() {
// screenshot_url defined in the edit.html template
}).attr("src", screenshot_url);
}
// Tell visualSelector that the image should update
var s = $("img#selector-background").attr('src')+"?"+ new Date().getTime();
$("img#selector-background").attr('src',s)
}
function fetch_data() {
// Image is ready
$('.fetching-update-notice').html("Fetching element data..");
// Image is ready
$('.fetching-update-notice').html("Fetching element data..");
$.ajax({
url: watch_visual_selector_data_url,
context: document.body
}).done(function (data) {
$('.fetching-update-notice').html("Rendering..");
selector_data = data;
console.log("Reported browser width from backend: "+data['browser_width']);
state_clicked=false;
set_scale();
reflow_selector();
$('.fetching-update-notice').fadeOut();
});
$.ajax({
url: watch_visual_selector_data_url,
context: document.body
}).done(function (data) {
$('.fetching-update-notice').html("Rendering..");
selector_data = data;
console.log("Reported browser width from backend: " + data['browser_width']);
state_clicked = false;
set_scale();
reflow_selector();
$('.fetching-update-notice').fadeOut();
});
};
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#selector-background")[0];
selector_image_rect = selector_image.getBoundingClientRect();
// 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-wrapper").show();
selector_image = $("img#selector-background")[0];
selector_image_rect = selector_image.getBoundingClientRect();
// make the canvas the same size as the image
$('#selector-canvas').attr('height', selector_image_rect.height);
$('#selector-canvas').attr('width', selector_image_rect.width);
$('#selector-wrapper').attr('width', selector_image_rect.width);
x_scale = selector_image_rect.width / selector_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);
$("#selector-current-xpath").css('max-width', selector_image_rect.width);
// make the canvas the same size as the image
$('#selector-canvas').attr('height', selector_image_rect.height);
$('#selector-canvas').attr('width', selector_image_rect.width);
$('#selector-wrapper').attr('width', selector_image_rect.width);
x_scale = selector_image_rect.width / selector_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);
$("#selector-current-xpath").css('max-width', selector_image_rect.width);
}
function reflow_selector() {
$(window).resize(function() {
$(window).resize(function () {
set_scale();
highlight_current_selected_i();
});
var selector_currnt_xpath_text=$("#selector-current-xpath span");
var selector_currnt_xpath_text = $("#selector-current-xpath span");
set_scale();
set_scale();
console.log(selector_data['size_pos'].length + " selectors found");
console.log(selector_data['size_pos'].length + " selectors found");
// highlight the default one if we can find it in the xPath list
// or the xpath matches the default one
@@ -156,84 +159,84 @@ $(document).ready(function() {
}
$('#selector-canvas').bind('mousemove', function (e) {
if(state_clicked) {
return;
}
ctx.clearRect(0, 0, c.width, c.height);
current_selected_i=null;
$('#selector-canvas').bind('mousemove', function (e) {
if (state_clicked) {
return;
}
ctx.clearRect(0, 0, c.width, c.height);
current_selected_i = null;
// 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;
// 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;
}
// Reverse order - the most specific one should be deeper/"laster"
// Basically, find the most 'deepest'
var found = 0;
ctx.fillStyle = 'rgba(205,0,0,0.35)';
for (var i = selector_data['size_pos'].length; i !== 0; i--) {
// draw all of them? let them choose somehow?
var sel = selector_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
) {
// FOUND ONE
set_current_selected_text(sel.xpath);
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);
// no need to keep digging
// @todo or, O to go out/up, I to go in
// or double click to go up/out the selector?
current_selected_i = i - 1;
found += 1;
break;
}
}
}.debounce(5));
function set_current_selected_text(s) {
selector_currnt_xpath_text[0].innerHTML = s;
}
// Reverse order - the most specific one should be deeper/"laster"
// Basically, find the most 'deepest'
var found=0;
ctx.fillStyle = 'rgba(205,0,0,0.35)';
for (var i = selector_data['size_pos'].length; i!==0; i--) {
// draw all of them? let them choose somehow?
var sel = selector_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
function highlight_current_selected_i() {
if (state_clicked) {
state_clicked = false;
xctx.clearRect(0, 0, c.width, c.height);
return;
}
) {
// FOUND ONE
var sel = selector_data['size_pos'][current_selected_i];
if (sel[0] == '/') {
// @todo - not sure just checking / is right
$("#include_filters").val('xpath:' + sel.xpath);
} else {
$("#include_filters").val(sel.xpath);
}
xctx.fillStyle = 'rgba(205,205,205,0.95)';
xctx.strokeStyle = 'rgba(225,0,0,0.9)';
xctx.lineWidth = 3;
xctx.fillRect(0, 0, c.width, c.height);
// Clear out what only should be seen (make a clear/clean spot)
xctx.clearRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale);
xctx.strokeRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale);
state_clicked = true;
set_current_selected_text(sel.xpath);
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);
// no need to keep digging
// @todo or, O to go out/up, I to go in
// or double click to go up/out the selector?
current_selected_i=i-1;
found+=1;
break;
}
}
}.debounce(5));
function set_current_selected_text(s) {
selector_currnt_xpath_text[0].innerHTML=s;
}
function highlight_current_selected_i() {
if(state_clicked) {
state_clicked=false;
xctx.clearRect(0,0,c.width, c.height);
return;
}
var sel = selector_data['size_pos'][current_selected_i];
if (sel[0] == '/') {
// @todo - not sure just checking / is right
$("#include_filters").val('xpath:'+sel.xpath);
} else {
$("#include_filters").val(sel.xpath);
}
xctx.fillStyle = 'rgba(205,205,205,0.95)';
xctx.strokeStyle = 'rgba(225,0,0,0.9)';
xctx.lineWidth = 3;
xctx.fillRect(0,0,c.width, c.height);
// Clear out what only should be seen (make a clear/clean spot)
xctx.clearRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale);
xctx.strokeRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale);
state_clicked=true;
set_current_selected_text(sel.xpath);
}
$('#selector-canvas').bind('mousedown', function (e) {
highlight_current_selected_i();
});
$('#selector-canvas').bind('mousedown', function (e) {
highlight_current_selected_i();
});
}
});
});