bookmarklet: click for random specified links from a host domain - javascript

tl;dr: A bookmarklet that opens in a new tab: random link (with specified multiple html-classes) from a specified domain and code that works with current logins. Thank you.
short version of butchered code:
javascript:
(
var % 20 site = domain.com
function() {
window.location.host == site
void(window.open(document.links[Math.floor(document.querySelectorAll("a.class1, a.class2"))].href, '_blank'))
}();
//beautified with: http://jsbeautifier.org/
To whom it may concern:
I have searched around for a while and even considered switching services but although some come close or are similar to my particular request, none have served to address everything the request entails.
Execute the script on a specific domain even when no page from said domain is currently open. If login authentication for attaining the information or data for execution is required, read or work in conjunction with existing session.
Fetch from a specific domain host, a random link out of all links on that domain with a certain html-class (or indeed otherwise) using preferably, css-selectors.
Open the results in a new tab.
From butchering such similarities, the result became something like this:
//bookmarklet
javascript:
//anonymous function+ wrapped code before execution
(
// function global variables for quick substitution
var %20 site = domain.com
function(){
//set domain for script execution
window.location.host == site
//open new tab for
void(window.open(document.links
//random link
[Math.floor
//with specific classes (elements found with css selectors)
(document.querySelectorAll("a.class1, a.class2"))
]//end random-query
.href,'_blank' //end page-open
)//end link-open
)//end "void"
}//end function defintion
//execute
();
//(tried) checked with:
//http://www.javascriptlint.com/online_lint.php
Lastly, i have attained at most, basic css knowledge. I apologise if this request has anybody headdesking, palming or otherwise in gtfo mode. It is only too sad there is apparently no tag for "Warning: I DIY-ed this stuff" in StackExchange. However, i still would like answers that go into a bit of depth of explaining why and what each correction and modification is.
Thank you presently, for your time and effort.

Theoretically, the following code should do what you want:
window.addEventListener('load', function ( ) {
var query = 'a.class1[href], a.class2[href]';
var candidates = document.querySelectorAll(query);
var choice = Math.floor(Math.random() * candidates.length);
window.open(candidates.item(choice).href, 'randomtab');
}, true);
window.location.href = 'http://domain.com';
But it doesn't, because the possibility to retain event listeners across a page unload could be abused and browsers protect you against such abuse.
Instead, you can manually load the domain of your choice and then click a simpler bookmarklet with the following code:
var query = 'a.class1[href], a.class2[href]';
var candidates = document.querySelectorAll(query);
var choice = Math.floor(Math.random() * candidates.length);
window.open(candidates.item(choice).href, 'randomtab');
You could wrap the above in javascript:(function ( ) { ... })(); and minify as before, but it already works if you just minify it and only slap a javascript: in front.
I understand your situation of being an absolute beginner and posting "DIY" code, but I'm still not going to explain step-by-step why this code works and yours doesn't. The first version of the code above is complex to explain to a beginner, and the list of issues with the code in the question is too long to discuss all of them. You'll be better off by studying more Javascript; a good resource with tutorials is MDN.

Related

Share webpages on social media with counter

I'm creating a website that's going to have hundreds of pages. I want each page to be shareable on Facebook and Twitter. I've already created these buttons but I also want to have their respective share counters next to my share buttons. I don't want to use the standard Facebook method they provide because the coding looks bloated.
Right, so after doing some research, I found this example on codepen.
This looks exactly what I want - very simple!
However, I need some clarification and basic help with how this javascript code works:
var permalink = 'http://codepen.io';
var getTwitterCount = function () {
$.getJSON('http://urls.api.twitter.com/1/urls/count.json?
url='+permalink+'&callback=?', function(data){
var twitterShares = data.count;
$('.twitter .share-count').text(twitterShares);
});
};
getTwitterCount();
var getFacebookCount = function () {
$.getJSON('http://graph.facebook.com/?ids='+permalink+'&callback=?',
function(data){
var facebookShares = data[permalink].shares;
$('.facebook .share-count').text(facebookShares);
});
};
getFacebookCount();
This bit of code:
var permalink = 'http://codepen.io';
Does this have to be:
1) the url of the actual page I want shared, eg: http://www.example.com/page-1/
OR
2) Must this be the root of the domain name, eg: http://www.example.com/
?
Or am I missing something else?
If the answer is #1 above, then that means I have to include + edit this line for each page which isn't ideal because I have all my javascript code + plugins in ONE .js file to reduce http requests, so I'd prefer it that I don't have to add this javascript on-page for every page.
It would be the page that you want to share, but you could get around it without using a separate variable for each page by setting it to something like document.location.href for example?

Making insecure images sources secure client-side

I let users on my VanillaForums forum choose whether or not to use the https protocol and I want to test if I can change image sources on the client's side using jQuery.
I want this code to change the protocol in the image source links to // instead of http:// and load before the images have loaded, so I used .ready():
$(document).ready(function () {
if (window.location.protocol == "https:") {
var $imgs = $("img");
$imgs.each(function () {
var img_src = $(this).prop("src");
if (img_src.indexOf("http://") < 0) return;
var new_img_src = img_src.replace("http:", "");
$(this).prop("src", new_img_src);
});
}
});
While it does work in changing the image sources, the URL bar still shows this:
And the console gives a warning that http://someimageurl... is not secure.
Do I need to move the code to the top of the page or will that not make a difference?
It needs to be done server side for the browser not to throw an insecure connection warning. The file with the responsible code is /library/core/functions.render.php, which you can see here.
$PhotoURL is the variable that needs to be changed. Using the following makes sure all images are loaded over the https: protocol: str_replace('http://', 'https://', $PhotoURL).
I usually don't mind global scope on smaller software but in something as big as Vanilla it's like finding a needle in a haystack.
I couldn't find any other fixes for Vanilla in particular so I hope this helps people.

How to append timestamp to the javascript file in <script> tag url to avoid caching

I want to append a random number or a timestamp at the end of the javascript file source path in so that every time the page reloads it should download a fresh copy.
it should be like
<script type="text/javascript" src="/js/1.js?v=1234455"/>
How can i generate and append this number? This is a simple HTML page, so cant use any PHP or JSP related code
Method 1
Lots of extensions can be added this way including Asynchronous inclusion and script deferring. Lots of ad networks and hi traffic sites use this approach.
<script type="text/javascript">
(function(){
var randomh=Math.random();
var e = document.getElementsByTagName("script")[0];
var d = document.createElement("script");
d.src = "//site.com/js.js?x="+randomh+"";
d.type = "text/javascript";
d.async = true;
d.defer = true;
e.parentNode.insertBefore(d,e);
})();
</script>
Method 2 (AJZane's comment)
Small and robust inclusion. You can see exactly where JavaScript is fired and it is less customisable (to the point) than Method 1.
<script>document.write("<script type='text/javascript' src='//site.com
/js.js?v=" + Date.now() + "'><\/script>");</script>
If you choose to use dates or a random numbers to append to your URI, you will provide opportunities for the end user to be served the same cached file and may potentially expose unintended security risks. An explicit versioning system would not. Here's why:
Why "Random" and Random Numbers are both BAD
For random numbers, you have no guarantee that same random number hasn't been generated and served to that user before. The likelihood of generating the same string is greater with smaller "random" number sets, or poor algorithms that provide the same results more often than others. In general, if you are relying on the JavaScript random method, keep in mind it's pseudo-random, and could have security implications as well if you are trying to rely on uniqueness for say a patch in one of your scripts for XSS vulnerabilities or something similar. We don't want Johnny to get served the old cached and unpatched JS file with an AJAX call to a no-longer trusted 3rd-party script the day Mr. Hacker happened to be visiting.
Why dates or timestamps are bad too, but not as bad
Regarding Dates as "unique" identifiers, JavaScript would be generating the Date object from the client's end. Depending on the date format, your chances for unintended caching may vary. Date alone (20160101) allows a full day's worth of potential caching issues because a visit in the morning results in foo.js?date=20160101, and so does a visit in the evening. Instead, if you specify down to the second (20160101000000) your odds of an end user calling the same GET parameter go down, but still exist.
A few rare but possible exceptions:
Clocks get reset (fall behind) once a year in most time zones
Computers that reset their local time on reboot for one reason or another
Automatic network time syncing causing your clock to adjust backwards a few seconds/minutes whenever your local time is off from the server time
Adjusting time zones settings when traveling (The astronauts on the IIS travel through a zone every few minutes...let's not degrade their browsing experience :P)
The user likes resetting their system clock to mess with you
Why incremental or unique versioning is good :)
For a fontend only solution, my suggestion would be to set an explicit version, which could be simply hard-coded by you or your team members every time you change the file. Manually doing exactly as you had done in your same code of your question would be a good practice.
You or your team should be the only ones editing your JS files, so the key take away isn't that your file needs to be served fresh every time, I just needs to be served fresh when it changes. Browser caching isn't a bad thing in your case, but you do need to tell the end user WHEN it should update. Essentially, when your file is updated, you want to ensure the client gets the updated copy. With this, you also have the added bonus of being able to revert to previous versions of your code without worry of client caching issues. The only drawback is you need to use due diligence to make sure you actually update the version number when you update your JS files. Keep in mind just because something isn't automated, doesn't mean it is necessarily bad practice or poor form. Make your solution work for your situation and the resources you have available.
I suggest using a form like Semantic Versioning's rules to easily identify backwards or breaking compatibility by looking at the file name (assuming nobody in the development process fudged up their version numbering) if possible. Unless you have an odd use case, there is no good reason to force a fresh copy down to the client every time.
Automated version incrementing on the client side with Local Storage
If what you were after was frontend way to automate the generation of a unique version number for you so you don't have to explicitly set it, then you would have to implement some sort of local storage method to keep track of, and auto increment your file versions. The solution I've shown below would lose the ability for Semantic versioning, and also has the potential to be reset if the user knows how to clear Local Storage. However, considering your options are limited to client-side only solutions, this may be your best bet:
<script type="text/javascript">
(function(){
/**
* Increment and return the local storage version for a given JavaScript file by name
* #param {string} scriptName Name of JavaScript file to be versioned (including .js file extension)
* #return {integer} New incremented version number of file to pass to .js GET parameter
*/
var incrementScriptVer = function(scriptName){
var version = parseInt(localStorage.getItem(scriptName));
// Simple validation that our item is an integer
if(version > 0){
version += 1;
} else {
// Default to 1
version = 1;
}
localStorage.setItem(scriptName, version);
return version;
};
// Set your scripts that you want to be versioned here
var scripts = ['foo.js', 'bar.js', 'baz.js'];
// Loop through each script name and append our new version number
scripts.map(function(script){
var currentScriptVer = incrementScriptVer(script);
document.write("<script language='text/javascript' type='text/javascript' src='http://yoursite.com/path/to/js/" + script + "?version=" + currentScriptVer + " '><\/script>");
});
})();
</script>
I'm going to mention for completeness, if you are converting from an old system of generating "random" numbered or dated GET variables, to an incrementing versioned system, be sure that you will not step over any potentially randomly generated files names with your new versioning system. If in doubt, add a prefix to your GET variable when changing methods, or simply add a new GET variable all together. Example: "foo.js?version=my_prefix_121216" or "foo.js?version=121216&version_system=incremental"
Automated versioning via AJAX calls and other methods (if backend development is a possiblity)
Personally, I like to stay away from local storage options. If the option is available, it would be the "best" solution. Try to get a backend developer make an endpoint to track JS file versions, you could always use the response to that endpoint determine your version number. If you are already using version control like Git, you could optionally have on of your Dev Ops team bind your versioning to your commit versions for some pretty sweet integration as well.
A jQuery solution to a RESTful GET endpoint might look like:
var script = "foo.js";
// Pretend this endpoint returns a valid JSON object with something like { "version": "1.12.20" }
$.ajax({
url: "//yoursite.com/path/to/your/file/version/endpoint/" + script
}).done(function(data) {
var currentScriptVer = data.version;
document.write("<script language='text/javascript' type='text/javascript' src='http://yoursite.com/path/to/js/" + script + "?version=" + currentScriptVer + " '><\/script>");
});
Insert the script dynamically via document.createElement('script'), then when you set the URL, you can use new Date().getTime() to append the extra parameter.
If you are worried about your javascript executing before the script is loaded, you can use the onload callback of the script element (note that there are a few hoops to jump for IE though)
If you can't user server side code then you can use getScript method to do the same.
$(document).ready(function(){
var randomNum = Math.ceil(Math.random() * 999999);
var jsfile = 'scripts/yourfile.js?v=' + randomNum;
$.getScript(jsfile, function(data, textStatus, jqxhr) { });
});
Reference URL: http://api.jquery.com/jQuery.getScript/
(Please don't forget to mark as answer.)
Load scripts manually or with jQuery http://api.jquery.com/jQuery.getScript/. It also provides option to prevent chaching
You can replace the source of the script doing this with pure Javascript
// get first script
var script = document.getElementsByTagName('script')[0]
var new = document.createElement("script");
// add the source with a timestamp
new.src = 'yoursource.js?' + new Date.getTime().toString();
new.type = 'text/javascript'
script.parentNode.insertBefore(new,script);
Replace regular expression if not alphanumeric
Date.prototype.toISOString()
var today = new Date();
"MyFile_" + today.toISOString().replace(/[^\w]/g, "") + ".pdf"
MyFile_20191021T173426146Z.pdf
Old post but here is a one liner:
<script src="../Scripts/source/yourjsname.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>

Re-Direct with document.url.match

My goal is to redirect my website to (/2012/index.php)
ONLY IF the user goes to ( http://www.neonblackmag.com )
ELSE IF
the user goes to ( http://neonblackmag.com.s73231.gridserver.com ) they will not be re-directed... ( this way i can still work on my website and view it from this url ( the temp url )
I have tried the following script and variations, i have been unsuccessful in getting this to work thus far....
<script language="javascript">
if (document.URL.match("http://www.neonblackmag.com/")); {
location.replace("http://www.neonblackmag.com/2012"); }
</script>
This should work:
<script type="text/javascript">
if(location.href.match(/www.neonblackmag.com/)){
location.replace("http://www.neonblackmag.com/2012");
}
</script>
You should use regular expression as an argument of match (if you're not using https you can drop match for http://...
In your solution the semicolon after if should be removed - and I think that's it, mine is using location.href instead of document.URL.
You can also match subfolders using location.href.match(/www.neonblackmag.com\/subfolder/) etc
Cheers
G.
document.url doesn't appear to be settable, afaict. You probably want window.location
<script type="text/javascript">
if (window.location.hostname === "www.neonblackmag.com") {
window.location.pathname = '/2012';
}
</script>
(Don't use language="javascript". It's deprecated.)
Anyone at any time can disable JavaScript and continue viewing your site. There are better ways to do this, mostly on the server side.
To directly answer your questions, this code will do what you want. Here's a fiddle for it.
var the_url = window.location.href;
document.write(the_url);
// This is our pretend URL
// Remove this next line in production
var the_url = 'http://www.neonblackmag.com/';
if (the_url.indexOf('http://www.neonblackmag.com/') !== -1)
window.location.href = 'http://www.neonblackmag.com/2012/index.php';
else
alert('Welcome');
As I said, this can be easily bypassed. It'd be enough to stop a person who can check email and do basic Google searches.
On the server side is where you really have power. In your PHP code you can limit requests to only coming from your IP, or only any other variable factor, and no one can get in. If you don't like the request, send them somewhere else instead of giving them the page.
header('Location: /2012/index.php'); // PHP code for a redirect
There are plenty of other ways to do it, but this is one of the simpler. Others include, redirecting the entire domain, or creating a test sub domain and only allow requests to that.

Why does dojo.xhrGet needs different kinds of url to work on different computers (pc/mac)?

i'm writing an greasemonkey script for somebody else. he is a moderator and i am not. and the script will help him do some moderating things.
now the script works for me. as far as it can work for me.(as i am not a mod)
but even those things that work for me are not working for him..
i checked his version of greasemonkey plugin and firefox and he is up to date.
only thing that's really different is that i'm on a mac and he is pc, but i wouldn't think that would be any problem.
this is one of the functions that is not working for him. he does gets the first and third GM_log message. but not the second one ("got some(1) ..").
kmmh.trackNames = function(){
GM_log("starting to get names from the first "+kmmh.topAmount+" page(s) from leaderboard.");
kmmh.leaderboardlist = [];
for (var p=1; p<=(kmmh.topAmount); p++){
var page = "http://www.somegamesite.com/leaderboard?page="+ p;
var boardHTML = "";
dojo.xhrGet({
url: page,
sync: true,
load: function(response){
boardHTML = response;
GM_log("got some (1) => "+boardHTML.length);
},
handleAs: "text"
});
GM_log("got some (2) => "+boardHTML.length);
//create dummy div and place leaderboard html in there
var dummy = dojo.create('div', { innerHTML: boardHTML });
//search through it
var searchN = dojo.query('.notcurrent', dummy).forEach(function(node,index){
if(index >= 10){
kmmh.leaderboardlist.push(node.textContent); // add names to array
}
});
}
GM_log("all names from "+ kmmh.topAmount +" page(s) of leaderboard ==> "+ kmmh.leaderboardlist);
does anyone have any idea what could be causing this ??
EDIT: i know i had to write according to what he would see on his mod screen. so i asked him to copy paste source of pages and so on. and besides that, this part of the script is not depending on being a mod or not.
i got everything else working for him. just this function still doesn't on neither of his pc's.
EDIT2 (changed question): OK. so after some more trial and error, i got it to work, but it's still weird.
when i removed the www-part of the url thats being use in the dojo.xhrGet() i got the finally the same error he got. so i had him add www to his and now it works.
the odd thing is he now uses a script with the url containing "www" and i'm using a script with an url without "www"...
so for me:
var page = "http://somegamesite.com/leaderboard?page="+ p;
and for him:
var page = "http://www.somegamesite.com/leaderboard?page="+ p;
Why don't you have him try logging into an account that is not a moderator account so that you eliminate one of your variables from your problem space.
It's possible that the DOM of the page is different for a moderator than for a regular user. If you're making assumptions about the page as a regular user that are not true as a moderator, that could cause problems.
I suspect that to fix it, you may need access to a moderator account so you can more easily replicate the behavior.
ooops. it seemed that the url of this gamesite is accessible as www.gamesite.com as well as gamesite.com (without the www.part). this caused the problem.
sorry to bother you'all.
i go hide in shame now...

Categories