To be specific(MathJax is not what I am looking for)I have a web-page with some MathML in it.The "FireFox" browser parses it fine but when I try to add the same code through javascript,it doesn't parse it.How can I notify the browser to parse the content of the web page again?Even if it is in some other language than javascript
Here is the javascript code:
var b=document.createElement("math");
b.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML");
var msup=document.createElement("msup");
var c=document.createElement("mi");
c.innerHTML="c";
var p=document.createElement("mn");
p.innerHTML="6";
msup.appendChild(c);
msup.appendChild(p);
b.appendChild(msup);
document.body.appendChild(b);
Here is the HTML that it generates
<math xmlns="http://www.w3.org/1998/Math/MathML">
<msup>
<mi>c</mi>
<mn>6</mn>
</msup>
</math>
You need to use document.createElementNS() rather than document.createElement() in order to create the element in the proper namespace. Setting the xmlns attribute after the fact doesn't actually do it. So here is an example that works for me
<!DOCTYPE html>
<html>
<head>
<title>Test adding MathML</title>
</head>
<body>
<script>
var MML = "http://www.w3.org/1998/Math/MathML";
var b=document.createElementNS(MML,"math");
var msup=document.createElementNS(MML,"msup");
var c=document.createElementNS(MML,"mi");
c.appendChild(document.createTextNode("c"));
var p=document.createElementNS(MML,"mn");
p.appendChild(document.createTextNode("6"));
msup.appendChild(c);
msup.appendChild(p);
b.appendChild(msup);
document.body.appendChild(b);
</script>
</body>
</html>
I've also switched your use of innerHTML to use document.createTextNode() for consistency with the way you are creating the other nodes.
I was able to force the rebuilding by setting the innerHTML of a div element :
myDiv.innerHTML = b.outerHTML;
Demonstration (click "Run on JS")
Of course it works only on some browsers.
Related
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!
I am using KaTeX to render math in the browser.
Right now I am using something like
document.getElementById('el').innerHTML = function () {
const span = document.createElement('span');
katex.render('2+\frac{1}{x}', span);
return span.innerHTML;
});
but it seems really stupid that I have to apply it to an element, and then take the html from this element and insert in my string.
I have looked through the KaTeX documentation, but I cannot find anything to help me just rendering some text directly in the browser with something like katex.render('2+3+4').
I don't know if you're still looking for an answer but maybe this will be helpful.
First, I link to katex.min.js and katex.min.css from a cdn.
I wrap everything I want rendered in katex inside span tags and give them the class 'math'
For example:
<span class='math'>2+\frac{1}{x}</span>
Then inside a pair of script tags I include something like this:
var math = document.getElementsByClassName('math');
for (var i = 0; i < math.length; i++) {
katex.render(math[i].textContent, math[i]);
}
So as long as I write my math text inside an element with the class math, it gets rendered by katex.
EDIT: We should use textContent instead of innerHTML. I've run into issues using innerHTML. See using katex, '&' alignment symbol displays as 'amp;'
Use KaTeX's auto-render extension, which will let you add your KaTeX directly to the HTML with a delimiter like $$ and then render it all at once:
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/contrib/auto-render.min.js"></script>
</head>
<body>
<div id="el"><span>$$2+\frac{1}{x}$$</span></div>
<script>
renderMathInElement(document.body);
</script>
</body>
</html>
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.
I'm trying to generate a list of core-label elements with javascript.
In the documentation(https://www.polymer-project.org/docs/elements/core-elements.html#core-label) it is written, that I may add the attribute for in an input-element inside the core-label to connect them.
If I code it static like this, it is possible:
<core-label>
<core-image></core-image>
<paper-checkbox for></paper-checkbox>
<span>Text</span>
</core-label>
But if i try to add those elements dynamic inside a script, those elements are not connected...
var catLayout = document.createElement("core-label");
var img = document.createElement("core-image");
var chk = document.createElement("paper-checkbox");
chk.setAttribute("for","");
var label = document.createElement("span");
var labelcontent = document.createTextNode("text");
label.appendChild(labelcontent);
catLayout.appendChild(img);
catLayout.appendChild(chk);
catLayout.appendChild(label);
May anyone tell me, whats wrong?
What you're doing should work. I wonder if you're running into a timing issue due to the way you're script is being executed within the larger context of your application. But here's a functionally equivalent snippet that does the job:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="//www.polymer-project.org/webcomponents.js"></script>
<link rel="import" href="//www.polymer-project.org/components/core-label/core-label.html">
<link rel="import" href="//www.polymer-project.org/components/paper-checkbox/paper-checkbox.html">
<div>
<core-label>
<paper-checkbox for></paper-checkbox>
<span>Created via Markup</span>
</core-label>
</div>
<div id="container"></div>
<script>
var coreLabel = document.createElement('core-label');
var paperCheckbox = document.createElement('paper-checkbox');
paperCheckbox.setAttribute('for', '');
var text = document.createElement('span');
text.textContent = 'Created via JavaScript';
coreLabel.appendChild(paperCheckbox);
coreLabel.appendChild(text);
document.querySelector('#container').appendChild(coreLabel);
</script>
</body>
</html>
That being said, I'm curious as to why you need to create these elements via JavaScript. I personally find Polymer code much easier to read and maintain when as much as possible is handled via the DOM using Polymer's <template> logic. For instance, if you're resorting to JavaScript element creation because you want to include these elements conditionally, wrapping <template if="{{your_condition}}"> around that section of your DOM could take care of that for you. Similarly, if you're doing this from JavaScript because you want to repeat the logic multiple times for each element in an array, <template repeat="{{item in your_array}}"> can handle that for you. The data-binding section of the docs is great if you haven't seen it.
We have page like this:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="abc"></div>
</body>
</html>
I want to insert script in div and run it.
So im doing something like this:
document.getElementById("abc").innerHTML="<script>alert('sup');</script>";
Good, script is inside that div, but how can i run it now?
I propably didn't make it clear:
I have an external script that i need to put in specified place on the page.
I don't have access to the website, so i can't put it on the page code.
I want to do this, becouse this script makes new objects on the place where it is putted.
I don't have access to that script. I just have link (not direct) to it.
Make it a function. Use <script>function myAlert(){alert('sup');}</script> instead. You can then call it with myAlert();.
Please use createElement for that
var div = document.getElementById('abc');
var script = document.createElement('script');
var code = document.createTextNode('alert("sup");');
script.appendChild(code);
div.appendChild(script);
To put a script in a div is only useful for document.write And please don't do that. :-)