JavaScript terminate script without throw error - javascript

I have site with AJAX navigation.
main.js handle AJAX navigation and few another tasks.
Some of my subpages require own scripts, lets take gallery for example.
In main.js i have function which loads gallery content and gallery.js (gallery.js is just added to head tag).
Everything works fine until i leave gallery and enter gallery again. As result i have two gallery.js working which ruin down everything.
I tried:
remove <script type="text/javascript" src="js/gallery.js"></script> on gallery leave but this doesn't change anything
use throw but it terminate both gallery.js and main.js, so AJAX navigation die
There is way to terminate/stop gallery.js without terminate main.js?

That's actually more about code architecture than anything else.
Your code really should look like this
function loadGalleryFor(element) {
var active = true;
// async load here while active == true
return {
stop:function() { active = false; }
loading:function() { return active; }
};
}
And you call it as:
var galleryCtl = loadGalleryFor(...);
and when you need you can stop it simply as:
galleryCtl.stop();

Based on the code in your comment, first check to see if the gallery script is already in the head section:
if ($("head>script[src='gallery.js']").length === 0) {
$("head").append("<script src='gallery.js'></script>");
}

Related

How to inject userscripts into embedded web page content?

I have a userscript I'd like to inject after clicking a link to open an embedded web page. Specifically, I'd like to know how I should go about injecting this script:
Array.from(document.querySelectorAll('span')).filter(i => /(\d+)\spoint/.test(i.innerHTML)).forEach(i => i.style.display = 'none');
Array.from(document.querySelectorAll('div')).filter(i => /moreComments-/.test(i.id)).forEach(i => i.querySelector('p').click());
setTimeout(function() {
Array.from(document.querySelectorAll('span')).filter(i => /(\d+)\spoint/.test(i.innerHTML)).forEach(i => i.style.display = 'none');
},7000)
Into all embeddable Reddit subpages, i.e. all linked threads loaded from a subreddit's main page:
An image illustrating an embedded Reddit subpage in contrast to a standard fully-loaded page
I assume this requires an event listener or MutationObserver, but I don't know how to go about specifying the solution. Reading the Reddit source is deeply confusing and I'm not a coder. This is just something I think would be useful to know for myself and other everyday web users.
What are the right steps to follow in problem-solving a case like this? What kind of code should I consider?
You need to process the userscript on a selected group of page nodes. Because your code is only executed once per page load event, the nodes that load dynamically later on remain unaffected.
There are several ways to achieve your goal. One of the simplest approaches involves the use of the setInterval function. This calls your function periodically (by using a reasonable time span, say 500ms). With this function, you have to select the nodes you want and process only new arrival nodes. You can mark your node's DOM objects with something like the _is_processed property. And finally this can be wrapped into another function, say doForEachOnce. For example:
function doForEachOnce(list,theFunc) {
list.forEach(i => {
if (!i._is_processed) { i._is_processed = true; return theFunc(i); } else { return null; }
});
}
doForEachOnce(Array.from(document.querySelectorAll('span')).filter(i => /(\d+)\spoint/.test(i.innerHTML)), i => i.style.display = 'none');
doForEachOnce(Array.from(document.querySelectorAll('div')).filter(i => /moreComments-/.test(i.id)), i => i.querySelector('p').click());
setInterval(function() {
doForEachOnce(Array.from(document.querySelectorAll('span')).filter(i => /(\d+)\spoint/.test(i.innerHTML)), i => i.style.display = 'none');
},500);
I tested this userscript successfully with Tampermonkey. It expands all comments, hides the karma on page load, and then hides the karma again for each new arrival. Hope this is what you need.
Your question is too general, but I assume you asking something basic. If targeting some specific platform, please clarify your question.
I assume you want just inject javascript code into the web HTML page or part of HTML page.
Usually this done via script tag
<script>
/* Your code is here */
Array.from(document.querySelectorAll.......
</script>
To force a link to call your code, you have to wrap your code inside function and format href attribute of a tag as javascript:func_name()
<script>
function my_func()
{
/* Your code is here */
Array.from(document.querySelectorAll.......
}
</script>
click me

How to make sure that a javascript function is called first?

I am working on a SaaS platform. I do not have access to the app.js file. However, I am able to upload my own JS in the footer. Currently, I have a function that on click tests to see if the menu is open by checking if the main wrapper has a class of menu-active. One of two things happen, if the menu is active I remove the overlay and if it is not I add a class of overlay. Unfortunately, the app.js, which I do not have access, uses toggleClass removes the menu-active class for CSS. Occasionally, the app.js removes the class which I am checking first and messes up my function. However, most of the time it works. How can I make my function click called first 100% of the time? I am using JQuery 2.1.1
$(".menu-toggle").first().click(function () {
if (!$("#wrapper").hasClass("menu-active")) {
$("#wrapper").find("div:first").addClass("overlay");
}
if ($("#wrapper").hasClass("menu-active")) {
$("#wrapper").find("div:first").removeClass("overlay");
}
});
You could wrapping the check in a setTimeout:
$(".menu-toggle").first().click(function () {
setTimeout(function() {
if (!$("#wrapper").hasClass("menu-active")) {
$("#wrapper").find("div:first").addClass("overlay");
}
if ($("#wrapper").hasClass("menu-active")) {
$("#wrapper").find("div:first").removeClass("overlay");
}
}, 1);
});
That should cause the check to happen after the browser has updated the DOM.
Make the following,
<link rel="preload" href="path-to-your-script.js" as="script">
<script>
var scriptPriority =
document.createElement('script');
scriptPriority.src = 'path-to-your-script.js';
document.body.appendChild(scriptPriority);
</script>
About: Link rel Preload
Link rel preload is method that is used by a few developers, its something that almost nobody known and its use to give priority to a script or link css.
More info in:
https://developers.google.com/web/updates/2016/03/link-rel-preload
https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content

Re-run an html <script> in React

I'm making a component in React that has Facebook data pulled from an API call. The API call returns and updates a list, which render() will then populate with tags that are supposed to be converted to actual images by a script from Facebook's website. Something like this:
<a data-pin-do={'embedData'} href={'https://www.facebook.com/data/12345'} />
My html file includes this script, which I assume runs through the HTML code and converts the tags to something viewable.
<script async defer src="//assets.pinterest.com/js/pinit.js"></script>
However, the problem I'm running into is that the script only runs when the webpage initially loads, and then never again. Since I'm adding more tags in an API call and then updating the list via the props, it means I'm left with a bunch of tags that don't get converted when the call returns.
I've inspected the React console & html and can confirm the tags are there, it's just that the dynamically converted tags don't show up as pins.
I've already tried using jquery and document.appendChild() to add/get the script in componentDidUpdate(), but it doesn't seem to be working. Anybody have any clue how I can get around this?
If you look in your devtools you should see that when the html page loads this script it is just making a GET request to the script src (http://assets.pinterest.com/js/pinit.js). So, you should be able to recreate that behavior by making a simple http GET request to that url each time you need to rerun the script.
Try using:a do-while in your script:
var repeat = 0
Do {
// Your code goes here
repeat = repeat + 1
} while(repeat <= 10)
Note: replace 10 with times you want the script to repeat
If you wan't to add a rule to this (so it only runs when...) do:
var repeat = 'yes'
Do {
// Your code goes here
} while(repeat == 'yes')
Now your code will only run when repeat is equal to yes
In action
Stop repeating
Start repeating
<script>
var repeat = 'yes'
Do {
// Your code goes here
If(var1 == var2) { repeat = 'no' }
} while(repeat == 'yes')
</script>

If user came from previous page on site then this, else do this

What would be a viable way to accomplish the following:
A website has two pages; Parent page and Inside page. If user came to the Inside page directly by typing in the address or by following a link from a page other than Parent page, then show "foo". If user came to the Inside page from the parent page, then show "bar".
I would need this done in JS if possible. If not, PHP is a secondary choice.
You can get the page the user came from with document.referrer.
So you could implement your solution like this:
if (document.referrer === 'yoursite.com/parentpage') {
// do bar
} else {
// do foo
}
Please try this
This code in second page
jQuery(window).load(function() {
if (sessionStorage.getItem('dontLoad') == null) {
//show bar
}
else{
//show foo
}
});
This code in parent page
jQuery(window).load(function() {
sessionStorage.setItem('dontLoad','true')
});
with php:
There is a simple way is to create a mediator page which redirect to inner page after make a session / cookie.. then if you'll get session / cookie, you show foo & unset session.
if someone directly come from url, no session / cookie found & it show bar..
You can use the document.referrer but this is not always set. You could add a parameter to the URL on the parent page and then check for its existance in the child page
Link on the parent page:
<a href='myChildPage.html?fromParent=1'>My Child Page</a>
JS code on your child page:
var fromParent=false;
var Qs = location.search.substring(1);
var pairs = Qs.split("&");
for(var i = 0; i < pairs.length; i++){
var pos = pairs[i].indexOf('=');
if(pos!==-1){
var paramName = pairs[i].substring(0,pos);
if(paramName==='fromParent'){
fromParent=true;
break;
}
}
}
if(fromParent){
alert("From Parent");
}else{
alert("NOT From Parent");
}
This method isnt 100% foolproof either as users could type in the same URL as your parent page link. For better accuracy check the document.referrer first and if not set use the method i've outlined above
intelligent rendering with jQuery
After using #Rino Raj answer, i noticed it needed improvement.
In javascript, the load() or onload() event is most times much slower,
since it waits for all content and images to load before executing your attached functions.
While an event attached to jQuery’s ready() event is executed as soon as the DOM is fully loaded, or all markup content, JavaScript and CSS, but not images.
Let me explain this basing, on code.
When i used #Rino Raj's code, with load() event, it works but on the second/called page, the content appears before class="hide fade" is added (which I don't really want).
Then i refactored the code, using the ready() event, and yes,
the content that i intended to hide/fade doesn't appear at all.
Follow the code, below, to grasp the concept.
<!-- Parent/caller page -->
<script type="text/javascript">
$(document).ready(function() {
sessionStorage.setItem('dontLoad', 'true');
});
</script>
<!-- Second/called page -->
<script type="text/javascript">
$(document).ready(function() {
if(sessionStorage.getItem('dontLoad') == null) {
$("#more--content").removeClass("hide fade");
} else {
$("#more--content").addClass("hide fade");
}
});
</script>

Embeded script only running properly on second pageview

I am having a bit of my website only properly work whenever you visit the page the second time. 3 fields are not shown in the page the first time you view it, but after going to another section of the site and coming back, so long as you do not reload the page, the fields will properly display.
To reproduce the issue, go to http://imperialgaming.tech/.
Click on the Minecraft logo. Take note of the seemingly bad grammar in at the bottom of the area of text as the page tries to inform you about the status of the server. Now, click on the teamspeak logo at the bottom of the page, and then click again on the minecraft icon at the bottom of the page. You will now notice that the message at the bottom of the text has much better grammar, and more information to it. Refreshing the page resets this back to the broken version. You can find the code here. I apologize, squarespace breaks my indentation. Let me know if you have any idea what causes this or how to fix it.
Thanks!
I think the problem is because the script is running before the elements have been created in the DOM. Try adding the script section after this div block instead of before it:
<div class="server-status">
Our server is currently <span class="server-online"></span>!
There are <span class="server-players"></span> of <span class="server-max-players"></span> online.
</div>
<script>
MinecraftAPI.getServerStatus('mc.imperialgaming.tech', {
port: 25565 // optional, only if you need a custom port
}, function (err, status) {
if (err) {
return document.querySelector('.server-status').innerHTML = 'Error loading status';
}
document.querySelector('.server-online').innerHTML = status.online ? 'up' : 'down';
document.querySelector('.server-players').innerHTML = status.players.now;
document.querySelector('.server-max-players').innerHTML = status.players.max;
});
</script>
Updated
If within squarespace you are unable to move the script to be after (as I see that it is in the <head>) then try wrapping the entire code in jquery document ready block (this way the script will wait for the DOM to load) and use jquery selectors:
<script>
jQuery(document).ready(function($) {
MinecraftAPI.getServerStatus('mc.imperialgaming.tech', {
port: 25565 // optional, only if you need a custom port
}, function (err, status) {
if (err) {
return document.querySelector('.server-status').innerHTML = 'Error loading status';
}
$('.server-online').innerHTML = status.online ? 'up' : 'down';
$('.server-players').innerHTML = status.players.now;
$('.server-max-players').innerHTML = status.players.max;
});
});
</script>

Categories

Resources