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.
Related
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.
I think I have a major fault in my webpage design. I need to save the content if I reboot the computer or close the webpage.
I do not have access to any type of a database server only MS Access. I was thinking of utilizing localstorage as the page will be constantly viewed from the same computer.
I found this example [link]Edit functionality using javascript and local storage however I am not sure if it will work.
Can someone look at my example and let me know if I can do this or if I need to abandon this and start over.
$(document).ready(function () {
var id = 0;
// Add button functionality
$("table.dynatable button.add").click(function () {
id++;
var master = $(this).parents("table.dynatable");
// Get a new row based on the prototype row
var prot = master.find(".prototype").clone(true);
prot.attr("class", "")
prot.find(".id").attr("value", id);
master.find("tbody").append(prot);
});
// Remove button functionality
$(document).on("click", "table.dynatable button.remove", function () {
$(this).parents("tr").remove();
});
});
http://jsfiddle.net/deaconf19/csL68/
Thanks
If you are running the web page from a web-server -- that is, your URL begins with http:// or https://, then yes, you can use localStorage to save data.
If you are running the file directly from your hard drive, that is, your url begins with file:, then you'll have trouble. Chrome won't let you use localStorage -- I don't remember if Firefox does.
(If you need to run this from your local hard drive and not a server, and you are running under Windows, you can turn the file into an HTA and save data to a regular file.)
I want to preload a large JS file after a page has loaded, so that when I link to that JS file on the required page it is already downloaded and cached.
I'm basically doing this at the moment, and it works, but of course it's not the right way:
preload_js = new Image();
preload_js = "http://domain.com/files/file.js";
This seems such a quick and simple method, no Ajax needed etc. and it works great.
What's the proper way to do this? Surely not with Ajax as that seems overkill for this.
I know there's lots of methods for loading JS but they all seem to actually run the code after the script has loaded, which I don't want.
I don't want to use jQuery (or any library), it must be plain JS. Thanks for any help.
From this blog post:
Preloading components in advance is good for performance. There are
several ways to do it. But even the cleanest solution (open up an
iframe and go crazy there) comes at a price - the price of the iframe
and the price of parsing and executing the preloaded CSS and
JavaScript. There's also a relatively high risk of potential
JavaScript errors if the script you preload assumes it's loaded in a
page different than the one that preloads.
After a bit of trial and lot of error I think I came up with something
that could work cross-browser:
in IE use new Image().src to preload all component types
in all other browsers use a dynamic <object> tag
In this example I assume the page prefetches after onload some
components that will be needed by the next page. The components are a
CSS, a JS and a PNG (sprite).
window.onload = function () {
var i = 0,
max = 0,
o = null,
// list of stuff to preload
preload = [
'http://tools.w3clubs.com/pagr2/<?php echo $id; ?>.sleep.expires.png',
'http://tools.w3clubs.com/pagr2/<?php echo $id; ?>.sleep.expires.js',
'http://tools.w3clubs.com/pagr2/<?php echo $id; ?>.sleep.expires.css'
],
isIE = navigator.appName.indexOf('Microsoft') === 0;
for (i = 0, max = preload.length; i < max; i += 1) {
if (isIE) {
new Image().src = preload[i];
continue;
}
o = document.createElement('object');
o.data = preload[i];
// IE stuff, otherwise 0x0 is OK
//o.width = 1;
//o.height = 1;
//o.style.visibility = "hidden";
//o.type = "text/plain"; // IE
o.width = 0;
o.height = 0;
// only FF appends to the head
// all others require body
document.body.appendChild(o);
}
};
See the post for more details.
EDIT: Looking at the comments on that post, someone mentions this link, which talks about the problems with the new Image() preload method in IE and other browsers. Here's an excerpt:
When IE encounters an IMG tag, it creates an image object and assigns
the download request to it. As data arrives from the image download,
it’s fed into the browser's image decoders. The decoders will reject
data as malformed if you feed them plaintext, which seems reasonable,
since they can't possibly make use of such data. When the decoders
reject the data as "Not possibly an image," the image object will
abort its processing. As a part of that abort, if the download has not
yet completed, it too is aborted.
This explains the behavior mentioned by the OP in the comment below (IE9 only downloading 4KB of the file).
It seems like your only reliable cross-browser option may be to use Ajax...
USE
window.document.onload =function(){
preload_js = "http://domain.com/files/file.js";
}
window.document.onload make sure the java script will not run until you dom is ready
Considering the cross domain issues with Ajax, especially since there really is no way to load a file on a server you have no control over (e.g. Google CDN hosting jQuery), this is my solution:
(1) Use the document.createElement('object') part in Simon M's solution for Firefox as that works great.
(2) Use the new Image.src thing for every other browser. Opera, Safari and Chrome love it. Also, I mentioned earlier that Mobile Safari doesn't work. Well it does, but for some reason takes 100ms verifying something (it is properly cached and it isn't just returning a 304 not modified). I can live with 100ms.
I've not tested other mobile browsers.
(3) Bollocks to IE as nothing works.
I'd like to inject a couple of local .js files into a webpage. I just mean client side, as in within my browser, I don't need anybody else accessing the page to be able to see it. I just need to take a .js file, and then make it so it's as if that file had been included in the page's html via a <script> tag all along.
It's okay if it takes a second after the page has loaded for the stuff in the local files to be available.
It's okay if I have to be at the computer to do this "by hand" with a console or something.
I've been trying to do this for two days, I've tried Greasemonkey, I've tried manually loading files using a JavaScript console. It amazes me that there isn't (apparently) an established way to do this, it seems like such a simple thing to want to do. I guess simple isn't the same thing as common, though.
If it helps, the reason why I want to do this is to run a chatbot on a JS-based chat client. Some of the bot's code is mixed into the pre-existing chat code -- for that, I have Fiddler intercepting requests to .../chat.js and replacing it with a local file. But I have two .js files which are "independant" of anything on the page itself. There aren't any .js files requested by the page that I can substitute them for, so I can't use Fiddler.
Since your already using a fiddler script, you can do something like this in the OnBeforeResponse(oSession: Session) function
if ( oSession.oResponse.headers.ExistsAndContains("Content-Type", "html") &&
oSession.hostname.Contains("MY.TargetSite.com") ) {
oSession.oResponse.headers.Add("DEBUG1_WE_EDITED_THIS", "HERE");
// Remove any compression or chunking
oSession.utilDecodeResponse();
var oBody = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);
// Find the end of the HEAD script, so you can inject script block there.
var oRegEx = oRegEx = /(<\/head>)/gi
// replace the head-close tag with new-script + head-close
oBody = oBody.replace(oRegEx, "<script type='text/javascript'>console.log('We injected it');</script></head>");
// Set the response body to the changed body string
oSession.utilSetResponseBody(oBody);
}
Working example for www.html5rocks.com :
if ( oSession.oResponse.headers.ExistsAndContains("Content-Type", "html") &&
oSession.hostname.Contains("html5rocks") ) { //goto html5rocks.com
oSession.oResponse.headers.Add("DEBUG1_WE_EDITED_THIS", "HERE");
oSession.utilDecodeResponse();
var oBody = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);
var oRegEx = oRegEx = /(<\/head>)/gi
oBody = oBody.replace(oRegEx, "<script type='text/javascript'>alert('We injected it')</script></head>");
oSession.utilSetResponseBody(oBody);
}
Note, you have to turn streaming off in fiddler : http://www.fiddler2.com/fiddler/help/streaming.asp and I assume you would need to decode HTTPS : http://www.fiddler2.com/fiddler/help/httpsdecryption.asp
I have been using fiddler script less and less, in favor of fiddler .Net Extensions - http://fiddler2.com/fiddler/dev/IFiddlerExtension.asp
If you are using Chrome then check out dotjs.
It will do exactly what you want!
How about just using jquery's jQuery.getScript() method?
http://api.jquery.com/jQuery.getScript/
save the normal html pages to the file system, add the js files manually by hand, and then use fiddler to intercept those calls so you get your version of the html file
I have about 100 static HTML pages that I want to apply some DOM manipulations to. They all follow the same HTML structure. I want to apply some DOM manipulations to each of these files, and then save the resulting HTML.
These are the manipulations I want to apply:
# [start]
$("h1.title, h2.description", this).wrap("<hgroup>");
if ( $("h1.title").height() < 200 ) {
$("div.content").addClass('tall');
}
# [end]
# SAVE NEW HTML
The first line (.wrap()) I could easily do with a find and replace, but it gets tricky when I have to determine the calculated height of an element, which can't be easily be determined sans-JavaScript.
Does anyone know how I can achieve this? Thanks!
While the first part could indeed be solved in "text mode" using regular expressions or a more complete DOM implementation in JavaScript, for the second part (the height calculation), you'll need a real, full browser or a headless engine like PhantomJS.
From the PhantomJS homepage:
PhantomJS is a command-line tool that packs and embeds WebKit.
Literally it acts like any other WebKit-based web browser, except that
nothing gets displayed to the screen (thus, the term headless). In
addition to that, PhantomJS can be controlled or scripted using its
JavaScript API.
A schematic instruction (which I admit is not tested) follows.
In your modification script (say, modify-html-file.js) open an HTML page, modify it's DOM tree and console.log the HTML of the root element:
var page = new WebPage();
page.open(encodeURI('file://' + phantom.args[0]), function (status) {
if (status === 'success') {
var html = page.evaluate(function () {
// your DOM manipulation here
return document.documentElement.outerHTML;
});
console.log(html);
}
phantom.exit();
});
Next, save the new HTML by redirecting your script's output to a file:
#!/bin/bash
mkdir modified
for i in *.html; do
phantomjs modify-html-file.js "$1" > modified/"$1"
done
I tried PhantomJS as in katspaugh's answer, but ran into several issues trying to manipulate pages. My use case was modifying the static html output of Doxygen, without modifying Doxygen itself. The goal was to reduce delivered file size by remove unnecessary elements from the page, and convert it to HTML5. Additionally I also wanted to use jQuery to access and modify elements more easily.
Loading the page in PhantomJS
The APIs appear to have changed drastically since the accepted answer. Additionally, I used a different approach (derived from this answer), which will be important in mitigating one of the major issues I encountered.
var system = require('system');
var fs = require('fs');
var page = require('webpage').create();
// Reading the page's content into your "webpage"
// This automatically refreshes the page
page.content = fs.read(system.args[1]);
// Make all your changes here
fs.write(system.args[2], page.content, 'w');
phantom.exit();
Preventing JavaScript from Running
My page uses Google Analytics in the footer, and now the page is modified beyond my intention, presumably because javascript was run. If we disable javascript, we can't actually use jQuery to modify the page, so that isn't an option. I've tried temporarily changing the tag, but when I do, every special character is replaced with an html-escaped equivalent, destroying all javascript code on the page. Then, I came across this answer, which gave me the following idea.
var rawPageString = fs.read(system.args[1]);
rawPageString = rawPageString.replace(/<script type="text\/javascript"/g, "<script type='foo/bar'");
rawPageString = rawPageString.replace(/<script>/g, "<script type='foo/bar'>");
page.content = rawPageString;
// Make all your changes here
rawPageString = page.content;
rawPageString = rawPageString.replace(/<script type='foo\/bar'/g, "<script");
Adding jQuery
There's actually an example on how to use jQuery. However, I thought an offline copy would be more appropriate. Initially I tried using page.includeJs as in the example, but found that page.injectJs was more suitable for the use case. Unlike includeJs, there's no <script> tag added to the page context, and the call blocks execution which simplifies the code. jQuery was placed in the same directory I was executing my script from.
page.injectJs("jquery-2.1.4.min.js");
page.evaluate(function () {
// Make all changes here
// Remove the foo/bar type more easily here
$("script[type^=foo]").removeAttr("type");
});
fs.write(system.args[2], page.content, 'w');
phantom.exit();
Putting it All Together
var system = require('system');
var fs = require('fs');
var page = require('webpage').create();
var rawPageString = fs.read(system.args[1]);
// Prevent in-page javascript execution
rawPageString = rawPageString.replace(/<script type="text\/javascript"/g, "<script type='foo/bar'");
rawPageString = rawPageString.replace(/<script>/g, "<script type='foo/bar'>");
page.content = rawPageString;
page.injectJs("jquery-2.1.4.min.js");
page.evaluate(function () {
// Make all changes here
// Remove the foo/bar type
$("script[type^=foo]").removeAttr("type");
});
fs.write(system.args[2], page.content, 'w');
phantom.exit();
Using it from the command line:
phantomjs modify-html-file.js "input_file.html" "output_file.html"
Note: This was tested and working with PhantomJS 2.0.0 on Windows 8.1.
Pro tip: If speed matters, you should consider iterating the files from within your PhantomJS script rather than a shell script. This will avoid the latency that PhantomJS has when starting up.
you can get your modified content by $('html').html() (or a more specific selector if you don't want stuff like head tags), then submit it as a big string to your server and write the file server side.