I'm trying to override document.write so i will be able to take the raw html parse it make some manipulations on the code and return the call.
My entire process is async so it's needless to say that when document.write is called if the page has finished loading the document.write will erase the entire document, so i can't recall document.write.
I've searched and found many discussions about that but almost every one of them is very very old so i can't find any good answer.
my code for now is very basic:
const prevDocWrite = document.write;
document.write = function(str,patched) {
if(patched){
prevDocWrite.call(this, str);
}else{
Dom_Parser(str, context).then(newStr => {
prevDocWrite.call(this, newStr);
})};
};
I have added the "patched" part because i'm also calling document.write on my code so i call it like that document.write("str",true) and it will call the original document.write immediately.
I would really appreciate any help or ideas how to make this happen (other projects for reference will be great)
BTW i saw a lot of implementation using innerHtml but that's screwing up the <script> tags:(
Thanks a LOT
Related
I'm just a bit confused. I've been going through a presentation slide deck on Content Security Policies. On slide 10, when discussing the 'strict-dynamic' directive, three examples are given: one good, two bad:
// good
<script nonce="r4nd0m">
var s = document.createElement("script");
s.src = "//example.com/bar.js";
document.body.appendChild(s);
</script>
// bad
<script nonce="r4nd0m">
var s = "<script src=//example.com/bar.js></script>";
document.write(s);
// -OR-
document.body.innerHTML = s;
</script>
Google also advises to make similar changes on their CSP page ("Refactor calls to JS APIs incompatible with CSP").
I understand that the good example loads async while the bad one doesn't (unless async defer is added). But...
If I wanted to load an evil script, wouldn't both ways get me there?
Is the issue that the "bad" way doesn't propagate the nonce (automatically)? Or is it about the "bad" way being a bit like a call to eval() in that you can do pretty much anything with it (although, in HTML 5, a script wouldn't execute unless attached to an event handler, apparently)? Is the assumption that the "bad" way likely uses parser-inserted user input and that's why it's bad (that's what I got from the presentation video I found later)?
Why is one call permissible while the other isn't (when, in the example given, they seem to achieve the same thing - loading an external script)?
So, as a sort of exercise for myself, I'm writing a little async script loader utility (think require.js, head.js, yepnope.js), and have run across a little bit of a conundrum. First, the basic syntax is like this:
using("Models/SomeModel", function() {
//callback when all dependencies loaded
});
Now, I want to know, when this call is made, what file I'm in. I could do it with an ajax call, so that I can mark a flag after the content loads, but before I eval it to mark that all using calls are going to be for a specific file, then unset the flag immediately after the eval (I know eval is evil, but in this case it's javascript in the first place, not json, so it's not AS evil). I'm pretty sure this would get what I need, however I would prefer to do this with a script tag for a few reasons:
It's semantically more correct
Easier to find scripts for debugging (unique file names are much easier to look through than anonymous script blocks and debugger statements)
Cross-domain requests. I know I could try to use XDomainRequest, but most servers aren't going to be set up for that, and I want the ability to reference external scripts on CDN's.
I tried something that almost got me what I needed. I keep a list of every time using is called. When one of the scripts loads, I take any of those using references and incorporate them into the correct object for the file that just loaded, and clear the global list. This actually seems to work alright in Firefox and Chrome, but fails in IE because the load events seem to go off at weird times (a jQuery reference swallowed a reference to another type and ended up showing it as a dependency). I thought I could latch on to the "interactive" readystate, but it doesn't appear to ever happen.
So now I come asking if anybody here has any thoughts on this. If y'all want, I can post the code, but it's still very messy and probably hard to read.
Edit: Additional usages
//aliasing and multiple dependencies
using.alias("ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js", "jQuery");
using(["jQuery", "Models/SomeModel"], function() {
//should run after both jQuery and SomeModel have been loaded and run
});
//css and conditionals (using some non-existant variables here)
using.css({ src: "IEFix", conditionally: browser === "MSIE" && version < 9 });
//should include the IEFix.css file if the browser is IE8 or below
and to expound more on my response below, consider this to be file A (and consider the jquery alias from before to be there still):
using(["jQuery", "B"], function() {
console.log("This should be last (after both jQuery and B have loaded)");
console.log(typeof($));
});
Then this would be B:
using("C", function() {
console.log("This should be second");
});
And finally, C:
console.log("This should be first");
The output should be:
This should be first
This should be second
This should be last (after both jQuery and B have loaded)
[Object Object]
Commendable that you are taking on such an educational project.
However, you won't be able to pull it off quite the way you want to do it.
The good news is:
No need to know what file you are in
No need to mess with eval.
You actually have everything you need right there: A function reference. A callback, if you will.
A rough P-code for your using function would be:
function using(modules, callback) {
var loadedModules = []
// This will be an ajax call to load things, several different ways to do it..
loadedModules[0] = loadModule(modules[0]);
loadedModules[1] = loadModule(modules[1]);
// Great, now we have all the modules
// null = value for `this`
callback.apply(null, loadedModules);
}
Aloha. I have been working on a script and though I understand documentation of each constituent of the problem (and have looked over many other questions on SO), I don't understand this specific behavior in practice. Please be aware that the following code is an abbreviated subset that isolates the specific issue. Here is async.html:
<!doctype html>
<html><head><script type="text/javascript" src="asyncTest.js" async="true"></script></head>
<body><ul id="menu"><li>one</li><li>two</li><li>three</li></ul></body></html>
And here is asyncTest.js:
var _site = function() {
var load = function() {
var menuCategory = document.getElementById('menu').getElementsByTagName('li');
for(var i=0; i<menuCategory.length; i++) { alert(i+'['+menuCategory[i]+']'); }
};
return { load:load };
}();
window.addEventListener('load',_site.load(),false);
The problem is that without the async attribute in the <script> tag, this code does not properly store the <li> elements into menuCategory, as though it were running prior to the DOM being loaded (even though I thought it should fire after the entire window "object" loads). I find that strange because I am using the addEventListener() to try and run this only after the whole thing has been loaded (and it appears to run at the appropriate time in Chromium, FF, and Opera -- at least what appears to be the "appropriate time"). If anything, I think that the opposite would cause this behavior.
Can someone explain this, preferably using the old Einstein "explain it like you're explaining it to a six-year-old"? I'm obviously missing something in my reading. Thanks!
As mentioned by RobG in the comments, the problem here is that using _site.load() (with parenthesis after the call) is causing the function to be executed AND THEN assigned to the onload event. The way to correct this behavior to the desired functionality is to call it without the parenthesis: _site.load (or _site().load).
I'm trying to work with Raphael for some SVG stuff and tried, well, with my limited knowledge, to build something beautiful ;)
I have 3 files:
1x html file and 2xjs files
html file: with an onload function ( + header,body and stuff)
window.onload=function()
{
init();
}
js File1: has the init function and a function to load js files (e.g. Raphael) and a callback to proceed after the file is loaded
function init()
{
getScripts(initTool)
}
function getScripts(callback)
{
$.when($.getScript(scripts[raphael]).then(callback)
}
function initTool()
{
$('body').append("<div id='tool'></div>");
tool=Raphael("tool",5000,5000);
$('body').append("<a href='javascript:void(0)' onclick='newElement'>New element</a>")
}
js File2: Here I have the function newElement which should add (for this example) a single path to the svg element created by Rapahel
function newElement()
{
tool.path("M10,20L30,40");
}
Unfortunately the path does not show up and I have no idea why. I tried referencing the "tool" variable before the onload in case it it related to global/local variables (wild guessing) but this also does not work. changing id's to "tool" to "tool2" for the svg element also does not work.
What else could it be? Where is my (possibly obvious) blind spot?
SHould callback not be declared as a parameter here?
function getScripts(callback)
{
$.when($.getScript(scripts[raphael]).then(callback)
}
To be honest with you I've written quite a bit of javascript and I don't quite grok variables scopes fully yet. However, when calling functions you should use parenthesis to indicate that it should be executed (there are a couple of times when you reference them without parenthesis, but that is beyond the scope of this answer).
So...
$('body').append("<a href='javascript:void(0)' onclick='newElement()'>New element</a>")
But this isn't enough to make it work, you should also declare your function like this:
var newElement = function() {
tool.path("M10,20L30,40");
}
Here is a working solution: http://jsfiddle.net/vAjG2/
(perhaps somebody can expand on why these changes are needed, I don't grasp them myself).
The problem has nothing to do with variable scope. You just need parentheses following the function name in your inline event handler. Rewrite the last line as:
$('body').append("New element")
and you'll be up and running.
However, inline event handlers are frowned upon for a whole variety of reasons. As quirksmode says: "Although the inline event registration model is ancient and reliable, it has one serious drawback. It requires you to write JavaScript behavior code in your XHTML structure layer, where it doesn't belong."
A much cleaner way to do this would separate out the markup and the script, e.g.:
<div id='tool'></div>
<a id="mylink" href='#'>New element</a>
<script>
var tool = Raphael("tool",500,500);
$('#mylink').on("click", function() {
tool.path("M10,20L30,40");
});
</script>
See this jsfiddle for this code in action.
Lastly, as a helpful hint, I would advise running your code on document ready, instead of window load, especially you're using jquery,. Document ready happens when the DOM is first constructed. Window load waits for all assets to be fully loaded, which can take awhile, and typically isn't necessary. It's long considered a best practice.
I encounter this problem in the latest version of Chromium. After the creation of the first element using a font-family embedded via #font-face I am being handed wrong offsetXyz values. By the time the script is executed, the window.onload hook will already have fired and the font will thus have already been loaded.
This is what the script looks like (schematically):
var e = document.createElement("span");
e["innerText" in e?"innerText":"textContent"] = "fooBar";
e.style.fontFamily = "fontFaceEmbeddedFontFamily";
document.body.appendChild(e);
alert(e.offsetWidth); // Returns two different values
setTimeout(function() {
alert(e.offsetWidth); // The latter being correct
}, 1000);
The value is updated "silently". There appears to be no way of waiting for it to correct the values but simply setInterval-check the value and then render the solution. I don't fancy doing dirty stuff like that.
Anyone has any suggestions how to proceed? Happens only when the src: local(" ... ") isn't specified, the issue is hence downloaded-font specific.
You have already given the answer yourself. Set src: local() and it will not happen - in general when you use #font-face, stick to the bulletproof syntax, since it was made to overcome browser issues like the one you are butting heads with here.
I know is almost a year, but I got this problem too and took me half a day to discover the cause. You can just wait for the entire page to load, instead of using a timeout. The src: local() didn't make any difference for me. So you can use:
<body onload="finished()">
or in jQuery:
$(window).load(
function() {
// this only will execute when the entire page is loaded.
}
);