Can't use stopProgagation and preventDefault to stop opening a link - javascript

I can't seem to get preventDefault or stopPropagation to work on some types of links. I'd like to write a program to highlight an element on a webpage and save that element as I click it. I'd like to be able to click multiple elements on the page so the program should avoid navigate out of the page. The program fails in some cases. For examples, if I go to https://www.yahoo.com, past the program in the console log and click the ads image, it will open the link. The same happens when I visit https://www.amazon.com and click on the image above "Ad Feedback". It appears it just doesn't work on the ads links.
I tried this program on both firefox and chrome browser. The program works on majority of the links but fails on Ads link. By viewing the HTML source I can't figure out why it fails and how it can be fixed. The program is shown below. Just copy it to run in console.
var highlightDiv = document.createElement('div');
highlightDiv.id = 'testeditor123abc';
document.body.insertBefore(highlightDiv, document.body.firstChild);
var mouseX;
var mouseY;
document.addEventListener('mouseover', processElement, true);
document.addEventListener('click', captureElement, true);
function processElement(e) {
let elem = e.target;
let elemRect = elem.getBoundingClientRect();
highlightDiv.style.top = elemRect.top+'px';
highlightDiv.style.left = elemRect.left+'px';
highlightDiv.style.width = elemRect.width+'px';
highlightDiv.style.height = elemRect.height+'px';
highlightDiv.style.transition = '0.1s';
highlightDiv.style.background = 'rgba(0, 0, 255, 0.2)';
highlightDiv.style.borderColor = 'rgba(255, 0, 0, 0.8)';
highlightDiv.style.borderWidth = '2px';
highlightDiv.style.borderStyle = 'dashed';
highlightDiv.style.position = 'fixed';
highlightDiv.style.zIndex = '999999999999999';
highlightDiv.style.pointerEvents = 'none';
}
function captureElement(e) {
console.log('Mouse X: ', mouseX);
console.log('Mouse Y: ', mouseY);
let element = e.target;
let viewportDimensions = {};
viewportDimensions.height = document.documentElement.clientHeight;
viewportDimensions.width = document.documentElement.clientWidth;
let command = {};
console.log('Element:');
console.log(element);
e.preventDefault();
e.stopPropagation();
}
I hope the program would stop sending me to other page for any element I click on the page. I greatly appreciate any suggestion. Thanks.

Related

How can I make a tampermonkey / embedded js userscript wait before it runs?

If anyone has this similar problem the solution for me was to correctly format set timeout, before I was doing
setTimeout(function() {//program here}, 5000) but that did not work, naming the function and then calling it properly from settimeout did not cause any issues. Also, make sure the bottom of your file doesn't have some random brackets--mine did and causes problems.
I am currently trying to improve a mod menu / cheat for an online virtual school program. It works fine and builds its UI elements by appending to a few different areas on the virtual school page, however, whenever it runs it fails multiple times before succeeding because it is trying to append to objects that are not loaded yet.
The .js file is injected by this tool although I don't really know what it is doing. I can't see any options like "delay before running" etc.
How can I wait for either a certain amount of time or check if the site is loaded without interrupting it's loading process? All the solutions I have tried so far (settimeout, event listener for loaded, while loop for site not being loaded) don't work because they stop the site from loading while they check.
This is the start of the JS file (it will not run here)
(function() {
'use strict';
//==BEGIN UI BUILDING==
window.configElements = []; //Config infomation
function init() {
//Builder Functionsfunction appender(b, p){ //appends things, if p is null defaults to tweaksmenu
if (p == undefined) {
document.getElementById("tweaksmenu").appendChild(b)
} else document.getElementById(p).appendChild(b)
}
function RenderPane(name, id, width, height, margintop, marginleft) { //renders panes
window.pane = document.createElement("div")
window.pane.style.width = width
window.pane.style.height = height
window.pane.style.position = "absolute"
window.pane.style.marginTop = margintop
window.pane.style.marginLeft = marginleft
window.pane.style.border = "1px solid rgb(95, 95, 95)"
window.pane.style.borderRadius = "3px"
window.pane.style.backgroundColor = "rgb(39, 39, 39)"
window.pane.style.overflow = "hidden"
window.pane.style.color = "rgb(249, 166, 25)"
window.pane.style.textAlign = "center"
window.pane.style.overflowY = "scroll"
window.pane.id = id
window.panetitle = document.createElement("h1")
window.panetitle.innerText = " " + name //shitty centering fix
window.pane.appendChild(window.panetitle)
window.pane.appendChild(document.createElement("hr"))
document.getElementById("overlay").appendChild(window.pane)
}
function BuildMenuEntry (name, info, id, configpane, override) { //Creates tickbox element with info and optional (new) config pane (see guesspractice). Override autoappends to tweaksmenu and does not return
window.entry = document.createElement("div")
window.tickbox = document.createElement("input")
window.tickbox.type = "checkbox"
window.tickbox.id = id
window.configElements.push(id)
window.entry.appendChild(window.tickbox)
window.window.label = document.createElement("label")
window.label.innerText = " " + name //spacing fix
window.entry.appendChild(window.label)
if (configpane != undefined) { //If any configpane was passed through try and create a button to attach it.
window.configbutton = document.createElement("button")
window.configbutton.innerText = "Configure"
window.configbutton.style.marginLeft = "7px"
window.configbutton.style.border = "1px solid #5f5f5f"
window.configbutton.style.boxShadow = "inset 0 0 5px rgba(0, 0, 0, 0.6)"
window.configbutton.style.backgroundColor = "rgb(39, 39, 39)"
window.configbutton.style.color = "#f9a619"
window.configbutton.style.borderRadius = "3px"
window.configbutton.onclick = function () {
if (document.getElementById(configpane).style.visibility == "unset") { //visiblitly handler for configpane button
document.getElementById(configpane).style.visibility = "hidden"
} else {
document.getElementById(configpane).style.visibility = "unset"
}
}
window.entry.appendChild(window.configbutton)
}
window.desc = document.createElement("p")
window.desc.innerHTML = info;
window.entry.appendChild(window.desc)
if (override == 1) { //override
window.document.getElementById("tweaksmenu").appendChild(window.entry);
}
else return window.entry;
}

.clone().appendTo - Replace element styles not working?

I have individual three arrows. on click; I want the div below them (letsChat) to change styles and I want to clone and append relevant information in that div. I also want it to revert back to it's original state when it is clicked again or if orientation is changed to portrait.
document.querySelector('#compositionArrow').onclick = function(){
var letsChat = document.querySelector('.lets-chat');
var letsChatButton = document.querySelector('.lets-chat a');
var compositionArrow = document.querySelector('#compositionArrow')
var compositionText = document.querySelector('.composition-text');
if (letsChatButton.style.display='flex' && window.matchMedia("(orientation: landscape)").matches) {
compositionArrow.style.transform='rotate(180deg)';
//letsChat.appendChild(compositionText).cloneNode(true);
//compositionText.clone().appendTo.letsChat; return false;
document.querySelector('.composition-text').clone().appendTo(document.querySelector('.lets-chat'));
letsChat.style.background='#00BCD4';
letsChatButton.style.display='none';
}
else if (letsChatButton.style.display='none' || window.matchMedia("(orientation: portrait)").matches){
compositionArrow.style.transform='rotate(180deg)';
letsChat.style.background='#ff8f00';
letsChatButton.style.display='flex';
}
}
example can be found below: (you may have to play with window
artpenleystudios.com
Here's something that demonstrates part of what you asked. It doesn't take into account orientation change, but it handles the click part. As far as I know, there's no straightforward way to detect orientation change, but here's an article that talks about a few options. Another idea would be to use jQuery Mobile as it fires orientationchange events.
So after much back and forth and after looking at your site more closely, this is what I managed to cobble together.
jQuery('#compositionArrow').click(function() {
var $letsChat = jQuery('.lets-chat');
var letsChat = $letsChat[0];
var letsChatButton = $letsChat.find('a')[0];
// Remove old composition text if it exists.
$letsChat.find('.composition-text').remove();
if (letsChatButton.style.display !== 'none' && window.matchMedia("(orientation: landscape)").matches) {
this.style.transform = 'rotate(180deg)';
$letsChat.append(jQuery('.composition-text').clone());
letsChat.style.background = '#00BCD4';
letsChatButton.style.display = 'none';
}
else if (letsChatButton.style.display === 'none' || window.matchMedia("(orientation: portrait)").matches) {
this.style.transform = '';
letsChat.style.background = '#ff8f00';
letsChatButton.style.display = 'flex';
}
});
It works for me in FireFox on a downloaded version of your site.
Cheers!

Trouble reading data from JSON file and displaying it on Canvas

Background
(New to JS and 1st time using canvas)
I am trying to read a JSON file from https://analytics.usa.gov/ and display it using a canvas. I want just the first 8 records to be populated in a drop down.
I was successful in getting a dump of the file locally on my machine. Code is here (https://jsfiddle.net/uh8jamdo/)
What I was trying to do is :
1) Page Title from the data should be populated in Drop Down
2) When the User selects one and clicks submit. I want to display the Page Title, URL and active users of that particular Page Title.
Below is my attempt. Can some one please guide me. I have written code to display canvas, text and update the data.
window.onload = function() {
var button = document.getElementById("previewButton");
button.onclick = previewHandler;
}
function previewHandler() {
var canvas = document.getElementById("analytics");
var context = canvas.getContext("2d");
drawText(canvas, context);
}
// draws all the text, including the Analytics
function drawText(canvas, context) {
context.font = "50px serif";
context.fillStyle = "black";
context.font = "bold 1em sans-serif";
context.textAlign = "left";
context.fillText("No of People online on Govt Websites", 20, 40);
// draw the analytics!
selectObj = document.getElementById("site");
index = selectObj.selectedIndex;
var site = selectObj[index].value;
context.font = "italic 1.2em serif";
context.fillText(site, 30, 100);
}
function updateAnalytics(site) {
var siteSelection = document.getElementById("site");
// add all data to the site dropdown
for (var i = 0; i < site.length; i++) {
site = site[i];
// create option
var option = document.createElement("option");
option.text = site.text;
// strip any quotes out of the site so they don't mess up our option
option.value = site.text.replace("\"", "'");
// add option to select
siteSelection.options.add(option);
}
// make sure the top tweet is selected
siteSelection.selectedIndex = 0;
}
canvas {
border: 1px solid black;
}
<canvas width="600" height="200" id="analytics">
<p>You need canvas to see the Analytics Data</p>
<p>This example requires a browser that supports the HTML5 Canvas feature.</p>
</canvas>
<p>
<label for="site">Pick a Site</label>
<select id="site"></select>
</p>
<p>
<input type="button" id="previewButton" value="Preview">
</p>
</form>
</br>
<script src="https://analytics.usa.gov/data/live/top-pages-realtime.json">
</script>
You basically have it, but there are enough strange things that I figure I can modify your code and you can study what I've done. A few issues I spotted:
Instead of hardcoding a script into the html document, we can fetch the contents of URL's through XMLHttpRequest. You are going to run into some timing issues.
There is no real need to use form and submit these days. Modern web design will usually maintain a stateful object on the client, and will communicate with various back ends using things like XMLHttpRequest, above. By doing this, we don't have to redraw the page every time we get a response back from the server. When the user clicks submit, you can catch that event, but there is a protocol you need to follow (return false from the handler) to prevent the page from reloading and blowing away the user's selection. The user will not get to see your canvas, because you'll be reloading a fresh canvas every time. They also will not see their selection because you'll be resetting it after every submit.
We don't need to strip quotes when setting the javascript value. First, because these things will usually get escaped for you, but second, because it's actually easier in your case to just store the index of the selection. You really don't need value at all. It may cause issues if you use this modified value as a key.
Minimize the number of global variables. Javascript has really good support for closure, which is a powerful programming construct that allows us to limit the visibility of variables, among other things. This will make it a lot easier to test your code in the debugger because everything will be grouped in one place. (More of a style than an actual issue).
Make sure to clear out your canvas if you plan to reuse it. Successive calls to fillText will clobber the previous text.
There are plenty of other things we could explore, but hopefully this will get you started.
Also, it's great that you are doing all of this without resorting to external libraries, but you should also check them out -- javascript can do some pretty exciting things. I recommend D3.js
Finally, here is the revised javascript, which I believe does the things you've specified, and which takes into account the advice I've given:
(you can play with the jsfiddle, here:
https://jsfiddle.net/dancingplatypus/L92fq305/6/)
var site_analytics = {
run: function () {
var ANALYTICS_SITE = 'https://analytics.usa.gov/data/live/top-pages-realtime.json';
var elem_select = document.getElementById("site");
var elem_title = document.getElementById("site_title");
var elem_preview = document.getElementById("previewButton");
var site_data = null;
elem_preview.onclick = render_selection;
elem_select.onchange = render_selection;
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
console.log('heya');
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
site_data = JSON.parse(xmlhttp.responseText);
sync_selector();
}
}
xmlhttp.open("GET", ANALYTICS_SITE, true);
xmlhttp.send();
function sync_selector() {
console.log('boyo');
elem_select.innerHtml = null;
if (site_data) {
for (var loop = 0; loop < Math.min(8, site_data.data.length); loop++) {
var item = site_data.data[loop];
var option = document.createElement('option');
option.text = item.page_title;
option.value = loop;
elem_select.add(option);
}
}
selected_index = (site_data.data.length > 0) ? 0 : null;
render_selection();
}
function render_selection() {
var index = elem_select.selectedIndex;
var item = site_data ? site_data.data[index] : null;
elem_title.innerText = item ? item.page_title : 'n/a';
var canvas = document.getElementById("analytics");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
drawText(item, canvas, context);
};
// draws all the text, including the Analytics
function drawText(item, canvas, context) {
context.font = "50px serif";
context.fillStyle = "black";
context.font = "bold 1em sans-serif";
context.textAlign = "left";
context.fillText("No of People online on Govt Websites", 20, 40);
// draw the analytics!
context.font = "italic 1.2em serif";
context.fillText(item ? item.active_visitors : '', 30, 100);
}
}
};
window.onload = function () {
site_analytics.run();
};

Greasemonkey script seems to ignore setInterval?

I'm trying to make a toy script in GreaseMonkey that will cause my screen to repeatedly jump to the top of my screen when I click a button, and stop jumping when I click the button again.
This is my code:
var perpetualScroll = function () {
var scrolling = false;
var scroll = function () {
if (scrolling) {
window.scrollTo(0, 0);
}
};
var scrollDiv = document.createElement("div");
scrollDiv.id = "topScroll0x2a";
scrollDiv.innerHTML = '<a class="topScroll" onclick="scrolling = !scrolling;" style="display:block; position:fixed; bottom: 1em; right: 1em; color:#fff; background-color:#000; padding:.5em;" href="#">Start scroll</a>';
document.body.appendChild(scrollDiv);
var intervalId = window.setInterval(scroll, 50);
};
perpetualScroll();
When I click the button in the lower corner the script creates, it does jump to the top of the screen, but doesn't continue to perpetually do so.
I'm really new to Javascript and GreaseMonkey, so I'm not quite sure what the problem is. I suspect it might be due to issues in the onclick part of the link, but if it is, I can't seem to figure it out.
Doing onclick like that will not work like you expect. Your innerHTML is just a string, so JS has no idea that it is scoped within your perpetualScroll function.
onclick handlers that are strings are evaluated in the global scope, so what you have is equivalent to this:
window.scrolling = !window.scrolling;
The scrolling variable you want is different.
You should create an actual function like this:
var a = document.createElement('a');
a.className = (a.className || "") + ' topScroll';
a.style.display = 'block';
a.style.position = 'fixed';
a.style.bottom = '1em';
a.style.right = '1em';
a.style.color = '#FFF';
a.style.backgroundColor = '#000';
a.style.padding = '0.5em';
a.href = '#';
a.onclick = function(e){
scrolling = !scrolling;
return false;
};
scrollDiv.appendChild(a);
Obviously setting that CSS is terrible, so you should really put that in a separate stylesheet anyway.

copy, drag & drop bug : item stops moving

I'm trying to drag and drop items on a page, but insteads of moving the item itself, I create a copy of it.
Here is my code. "copyDragDrop" is a div at the bottom of the page. It remains empty until the user strats dragging something.
function coordSouris()
{
return {
x:event.clientX + document.body.scrollLeft - document.body.clientLeft,
y:event.clientY + document.body.scrollTop - document.body.clientTop
};
}
function drag()
{
var pos = coordSouris(event);
copie = event.srcElement.cloneNode(true);
document.getElementById('copieDragDrop').appendChild(copie);
copie.style.position = 'absolute';
copie.style.display = 'block';
document.onmousemove = mouseMove;
document.onmouseup = drop;
}
function mouseMove()
{
if (copie != null)
{
var pos = coordSouris(event);
copie.style.left = pos.x;
copie.style.top = pos.y;
}
}
function drop()
{
var divCopie = document.getElementById('copieDragDrop');
if (divCopie.hasChildNodes() )
{
while ( divCopie.childNodes.length >= 1 )
{
divCopie.removeChild(divCopie.firstChild);
}
}
}
This code creates the copy, starts to move it, but after a few pixels, the copy stops following the mouse. If I release the mouse, "onmouseup" is not fired, but the copy starts to follow the mouse again ! I've tried the code on several items, the same bug occurs
I don't understand anything, any help is more than welcome.
UPDATE : I juste realised that all elements I tried the code on had something in common : they contained or were included in an ASP.net hyperlink control. The same code works well on regular HTML elements. There must be some auto-generated javascript for links that interferes with my code.
Couldn't find the auto-generated code responsible for the issue, so I simply solvec this by replacing Hyperlink controls by standard HTML anchors.

Categories