using a small model to test asynchronous processing - javascript

I've received much excellent instruction on Stack Overflow, especially regarding my feeble attempts to incorporate asynchronous processing in a recent web application. To narrow down some issues to their minimum, I created a very small HTML/javascript page to play with getJSON and look at some behavior mentioned by jfriend00. So far as I can see, this is a legitimate program, but although IE9 runs it, FireFox emits some text, then hangs/infinitely loops/whatever, while Chrome shows only the H1 (FireFox declined to do so) and the last string. Obviously, there is something horribly wrong with this code and I'm not seeing it. How about you?
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
</head>
<body>
<h1>testing 2</h1>
<script type="text/javascript">
function buildTree() {
$.getJSON('MurakiMaida.json', function(data) {
document.write("how about here?<br>");
$.each(data.person, function(i, xdata) {
document.write(xdata.id + "<br>");
});
});
document.write("<br>what are we doing here?");
}
buildTree();
</script>
</body>
</html>

document.write is probably the culprit.
I don't understand what exactly you are try to do, but document.write should only be used while the page is loading. Actually it is probably better to never use it.*
Create a <div id='foo'/> and write to it such as $('#foo').append($("<div>"+xdata.id+"</div>")
document.write was the way to use Javascript to add HTML to a document back in the days before the DOM existed. It still exists for backward compatibility, but should be avoided.

Related

Running scripts with content pulled from local storage with innerHTML

I've been playing around with web development and wanted to create a basic application which allows users to enter html into a text area, which is saved in local storage, then later inserted into a document element with .innerHTML.
Minimum working example:
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Prototyping</title>
</head>
<body>
<!--- Using bootstrap v. 5.2.0 --->
<form>
<label for="content"></label>
<textarea class="form-control" id="content"></textarea>
</form>
<div id="displayContent"></div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
crossorigin="anonymous"></script>
<script src="index.js"></script>
</body>
</html>
JavaScript
const userInput = document.getElementById('content');
const displayInput = document.getElementById('displayContent')
userInput.addEventListener('input', (event) => {
localStorage.setItem(event.target.id, event.target.value);
displayInput.innerHTML = localStorage.getItem(event.target.id);
});
Now I was concerned that using .innerHTML would allow users to inject js code <script>alert('HAHA')</script>. However, scripts fail to run. Or at least with my limited knowledge of HTML, I cannot get a script to run. This is what I want, but I don't understand why. When inspecting the page, I will see the <script>. Is this because localStorage converts the input into strings? What is happening that prevents the script from running?
The reason why the alert you try to inject "fails to run", is because at this stage the DOM is already parsed and all the javascript within it is already executed. So, the code would not be executed again.
Still, since you are inserting HTML, any HTML that will be added, will also be rendered. And with that, there are also some ways to execute javascript-code like this. One example is the following snippet as an input:
<img src=z onerror="alert('Injected code')">
Similar results could be achieved with other event-listener-attributes or deferred scripts.
However, if you only save and open the input on the client-side and not expose it to other users, there is no way it could do any damage. It would be the same as if you use the console in the developer-menu that is built-in in every modern browser (F12 in most of them).
If that is still a problem for your use-case or you expose the inputs to other users, I would strongly recommend you to parse the text-input so that no js-code would be executed.
Probably the safest way of achieving this could be to only insert text instead of HTML:
displayInput.textContent = localStorage.getItem(event.target.id)
Another way could be could be to encode the < and > to their html equivilant (source):
let content = event.target.value.replace(/</g, "<").replace(/>/g, ">")
localStorage.setItem(event.target.id, content)
displayInput.innerHTML = localStorage.getItem(event.target.id)
I hope this helps. Keep it up!

6 javascript tasks assigned to me by my lecturer

I am a complete beginner to javascript. I am also new to this website. I am asking for help to complete an assignment. I have been trying for more than 4 hours by looking at lecture material and online for a solution. It is causing me a lot of unnecessary stress. Before javascript we only used CSS and Html. I was given 6 javascript tasks to manipulate the html file (taskc.html) already given to me.
The tasks are as follows
Make a statement to change contents of h1 from "Welcome" to "Text"
2nd statement should make an new alert window when the page loads that delivers a message explaining what the page is about
3rd statement should change the title to "text"
4th statement should log the contents (innerHTML) of the first paragraph element in the console.
5th statement should hide the contents of the second paragraph when the page loads
6th statement should change the contents of the header to have a new colour of your choice
Here is that html.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Task C - The Document Object Mode</title>
</head>
<body>
<h1 id="header">Welcome</h1>
<p id="first">This site uses JavaScript</p>
<p id="second">Javascript is very useful</p>
</body>
</html>
Because the actual coding im meant to add is meant to be in the .js file I was given. so I figured I had to link the js file in the html file so I added
<script type="text/javascript" src="taskc.js"></script>
With that out of the way I went to the lecture notes and I thought I would simply need to modify some of the code given to me there like
document.getElementById('demo').innerHTML = 'Hello World!';
When I put this code in brackets I got the error (document is not defined)
I modified it to match the requirements for task 1
here it is
document.getElementById('header').innerHTML = 'text';
I was confused because I didn't know what this error meant and of course Errors and how to fix them are never explained so I had to lookup how to resolve the error.
I found that to fix it I have to declare it as a variable so I ended up doing this.
var document = 'taskc.html';
When I did this for document, alert and console all the errors went away, but when I did a live preview only statement 1 was working
If anyone could help me fix this I would really appreciate because I don't understand enough javascript to be able to complete this in a reasonable amount of time.
So first: Please use Javascript functions to keep your code tidy and clean.
Example:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Task C - The Document Object Mode</title>
</head>
<body>
<h1 id="header">Welcome</h1>
<p id="first">This site uses JavaScript</p>
<p id="second">Javascript is very useful</p>
<script type="text/javascript" src="taskc.js">test();</script>
</body>
</html>
function test(){
alert("This is a test!");
}
Always implement scripts that are document referenced at the bottom of your html.
If you use JQuery you can use following code to check document is loaded:
$(document).ready(function(){
//foo bar
});

what does "JavaScript sanitization doesn't save you from innerHTML" mean?

I'm learning xss prevention through this ppt:http://stash.github.io/empirejs-2014/#/2/23, and I have a question on this page.
It says "JavaScript sanitization doesn't save you from innerHTML", and I tried a simple test like this:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>
<div id="test"></div>
<script>
var userName = "Jeremy\x3Cscript\x3Ealert('boom')\x3C/script\x3E";
document.getElementById('test').innerHTML = "<span>"+userName+"</span>";
</script>
</body>
</html>
when I opened this html on my browser(chrome), I only saw the name "Jeremy",by using F12, I saw
<div id="test"><span>Jeremy<script>alert('boom')</script></span></div>
Although the script had been added to html, the alert box didn't come out.
"JavaScript sanitization doesn't save you from innerHTML" I think this means that the word "boom" should be alerted. Am I right?
According to MDN, innerHTML prevents <script> elements from executing directly1, which means your test should not alert anything. However, it does not prevent event handlers from firing later on, which makes the following possible:
var name = "\x3Cimg src=x onerror=alert(1)\x3E";
document.getElementById('test').innerHTML = name; // shows the alert
<div id="test"></div>
(script adapted from the example in the article, with escape sequences although I'm not sure those are relevant outside of <script> elements)
Since <script> elements never execute when inserted via innerHTML, it's not clear to me what that slide is trying to convey with that example.
1 This is actually specified in HTML5. MDN links to a 2008 draft; in the current W3C Recommendation, it's located near the end of section 4.11.1, just before section 4.11.1.1 begins:
Note: When inserted using the document.write() method, script elements execute (typically synchronously), but when inserted using innerHTML and outerHTML attributes, they do not execute at all.

Javascript jQuery plugin rendering problems [duplicate]

This question already has an answer here:
Plugin implementation issue with jQuery
(1 answer)
Closed 9 years ago.
Here is my problem. There's a nifty looking plugin here http://lab.smashup.it/flip/ which flips things around. I managed to implement it, but for some odd reason I'm only getting the first half of the animation rendered, the second part is just invisible (or hidden) and then it jumps to the end. To make things even more fun, everything was working fine at some point but then suddenly not. I of course backtracked as far back as possible back to when things were fine, and same problem again. I can't seem to locate the source of the problem. If someone could just please help me out by testing out the plugin and telling me if they managed to get a full animation rendered. For my HTML I based it on the source code of the plugin demo page to make sure, but to no avail.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test#0935</title>
<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// Load jQuery
google.load("jquery", "1");
</script>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="JS/jquery.flip.js"></script>
<script type="text/javascript">
$(function() {
$("#id1").bind("click", function() {
$("#flipo").flip({
direction: "bt"
})
return false;
});
});
</script>
<style type="text/css">
#flipo {
width:100px;
height:70px;
background-color:lightblue;
margin:20px;
}
</style>
</head>
<body>
<div id="flipo"></div>
<div id="id1">left</div>
</body>
</html>
For those of you who recognize this problem, I did try to avoid posting a new thread until I was advised to do so as no one was reading the old post. I've also flagged my initial post for deletion.
Nothing wrong with the basics of what you posted, I set up a quick fiddle and it worked fine, but that was when I noticed that you have not included your JS correctly. I think the issue is with that.
First you are pulling in jQuery from google using google.load. Then you are getting a (potentially different) version from jQuery.com. Also, flip relies on jQuery UI, and I can't see you importing that anywhere in the html snippet you posted.
Why don't you try this and get rid of the google.load and jQuery.com sources and see if that works.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
<script src="JS/jquery.flip.js"></script>
Demo Fiddle
This plugin depend's on jquery and jqueryUI, include both in your code

jQuery not working in Chrome 18

Nothing in jQuery appears to be working in Chrome for me. My version is 18.0.1025.151 m. The javascript is in the file test.js:
$('#paragraph').click(function() {
$('#paragraph').hide();
});
And the html is this:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery Example</title>
<script src="jquery-1.7.1.min.js"></script>
<script src="test.js"></script>
</head>
<body>
<p id="paragraph">This is my paragragh 401!</p>
</body>
</html>
I have triple-checked that the jQuery file is where it's supposed to be. Essentially, the code is supposed to make the paragraph disappear when clicked on. Seems simple enough and syntactically correct. I chose such a simple code because while regular javascript statements and code work fine (such as alert() and whatnot), absolutely nothing in jQuery has worked so far at all.
Here's the strange part though. When using the console in Chrome's developer tools, if I input the exact same jQuery stuff and hit enter, it actually works and functions how it's supposed to.
Does this have anything to do with Chrome's security structure or something?
Edit: Also, I should note that I have not yet uploaded these files on my server yet. This is on localhost (I'm using xammp for what it's worth), so perhaps that may help shed some light on the issue.
Wrap the code in a document ready, or put test.js before the end body tag.
It's executing before the DOM is ready. It should look like this:
$(function(){
$('#paragraph').click(function() {
$('#paragraph').hide();
});
});
To address the comment below:
http://api.jquery.com/ready/
The .ready() method is typically used with an anonymous function:
$(document).ready(function() {
// Handler for .ready() called.
});
Which is equivalent to calling:
$(function() {
// Handler for .ready() called.
});
You have to wrap it in document ready. That's probably your problem. Also you can use $(this) or cache the selector.
$(function () {
$('#paragraph').click(function () {
$(this).hide();
});
});

Categories