Why the error alert still displayed event the HTML elements are sanitized? - javascript

The below are my use case scenario.
Collect the user input.(the input must be HTML sting element)
Form the HTML element with some style.
After creating the HTML element, need to sanitize it and append it into the target DOM element.
The DOM element rendered the sanitized element. but the error alert stil displayed.
The user input is
<img src="http://url.to.file.which/not.exist" onerror="alert(document.cookie);">
This always shows the alert.
Can someone help me to resolve this?
function createEle() {
const wrapElement = document.createElement('div');
wrapElement.innerHTML = document.getElementById("html-input").value;
const html = showSanitizedHTML(wrapElement);
console.log(html.outerHTML)
document.getElementById("sanitized-html").innerHTML = html.innerHTML;
}
function showSanitizedHTML(value) {
const sanitizedHTML = DOMPurify.sanitize(value.outerHTML);
const tempWrapElement = document.createElement('div');
tempWrapElement.innerHTML = sanitizedHTML;
return tempWrapElement.firstElementChild;
}
<script src="https://cdn.jsdelivr.net/npm/dompurify#2.0.16/dist/purify.min.js"></script>
<textarea id="html-input"></textarea>
<button onclick="createEle()">Show Sanitized HTML</button>
<div id="sanitized-html"></div>

The script content executes on this statement
wrapElement.innerHTML = document.getElementById("html-input").value;
So here is how to fix it
function createEle() {
const wrapElement = document.createElement('div');
wrapElement.innerHTML = DOMPurify.sanitize(document.getElementById("html-input").value);
console.log(wrapElement.outerHTML)
document.getElementById("sanitized-html").innerHTML = wrapElement.innerHTML;
}
<script src="https://cdn.jsdelivr.net/npm/dompurify#2.0.16/dist/purify.min.js"></script>
<textarea id="html-input"></textarea>
<button onclick="createEle()">Show Sanitized HTML</button>
<div id="sanitized-html"></div>
or shorter, assuming you want to keep using the wrapper:
document.getElementById("sanitized-html").innerHTML = wrapElement.innerHTML;

This is the sequence of events:
You read the raw user input
You inject the raw user input into the DOM (wrapElement.innerHTML =)
You read the normalised user input back from the DOM
You pass the normalised user input though DOMPurify.sanitize
You inject the sanitized user input into the DOM
The alert fires due to step 2.

Because you're using unsanitized HTML here:
const wrapElement = document.createElement('div');
wrapElement.innerHTML = document.getElementById("html-input").value;
Don't jump through those hoops, just pass the text directly to DOMPurify:
function createEle() {
const element = showSanitizedHTML(document.getElementById("html-input").value);
// Your `showSanitizedHTML` is returning an **element**, not HTML,
// so you wouldn't use `innerHTML` to put it in the DOM.
const output = document.getElementById("sanitized-html");
output.innerHTML = "";
output.appendChild(element);
}
function showSanitizedHTML(html) {
const sanitizedHTML = DOMPurify.sanitize(html);
// Not sure what the purpose of this wrapper element is, but since
// it only uses sanitized HTML, I left it in place.
const tempWrapElement = document.createElement("div");
tempWrapElement.innerHTML = sanitizedHTML;
return tempWrapElement.firstElementChild;
}
<script src="https://cdn.jsdelivr.net/npm/dompurify#2.0.16/dist/purify.min.js"></script>
<textarea id="html-input"></textarea>
<button onclick="createEle()">Show Sanitized HTML</button>
<div id="sanitized-html"></div>
Or more simply:
function createEle() {
const html = showSanitizedHTML(document.getElementById("html-input").value);
document.getElementById("sanitized-html").innerHTML = html;
}
function showSanitizedHTML(html) {
const sanitizedHTML = DOMPurify.sanitize(html);
return sanitizedHTML;
}
<script src="https://cdn.jsdelivr.net/npm/dompurify#2.0.16/dist/purify.min.js"></script>
<textarea id="html-input"></textarea>
<button onclick="createEle()">Show Sanitized HTML</button>
<div id="sanitized-html"></div>
Or even more simply:
function createEle() {
document.getElementById("sanitized-html").innerHTML = DOMPurify.sanitize(
document.getElementById("html-input").value
);
}
<script src="https://cdn.jsdelivr.net/npm/dompurify#2.0.16/dist/purify.min.js"></script>
<textarea id="html-input"></textarea>
<button onclick="createEle()">Show Sanitized HTML</button>
<div id="sanitized-html"></div>

Related

Switch Content of two Textareas using JavaScript

I have two textareas and I like to switch the content of these, so content of the first textarea shall be the content of the second textarea and vice versa. Following code just copy the content of the first textarea into the second, but the second step is not performed, so both textareas comprise the same content afterwards. No error occurs.
function switch_text_content(){
var src_text_memory = src_form.src_message.value;
var trgt_text_memory = trgt_form.trgt_message.value;
console.log(src_text_memory);
src_form.src_message.innerHTML = trgt_text_memory;
trgt_form.trgt_message.innerHTML = src_text_memory;
//switch_text_content2(trgt_text_memory);
}
You are doing in wrong way because you are using .innerHTML to set value instead you can to use .value property to set value of textarea. Like Below Example:
const switchBtn = document.querySelector('#switch-btn');
const firstTextarea = document.querySelector('#first-textarea');
const secondTextarea = document.querySelector('#second-textarea');
switchBtn.addEventListener('click', function() {
const firstContent = firstTextarea.value;
const secondContent = secondTextarea.value;
firstTextarea.value = secondContent;
secondTextarea.value = firstContent;
});
<textarea id="first-textarea">First Content</textarea>
<textarea id="second-textarea">Second Content</textarea>
<br/>
<button type="button" id="switch-btn">Switch</button>

How to copy and paste HTML/text by JavaScript

I want to copy a text that has the CSS class copytext
and want to paste on the same page that's has CSS class pastehere.
I am using the following code, but with no result.
function copyToClipboard(text) {
const elem = document.createElement('.copytext');
elem.value = text;
document.body.appendChild(elem);
elem.select();
document.execCommand('.pastehere');
document.body.removeChild(elem);
}
I think you want to get the value of an HTML tag or something? with DOM Element innerHTML you can get the value of the Tag. eg:
html:
`<p id="myTag">hello world</p>`
javascript:
`let var1 = document.getElementById("myTag").innerHTML;`
the 'hello world' is now stored in the variable 'var1' and you can continue to work with it normally
If you want to copy text from all elements .copytext to the element .pastehere:
HTML:
<div class="copytext">Line 1</div>
<div class="copytext">Line 2</div>
<div class="copytext">Line 3</div>
JS:
function fun(text){
let copiedText = "";
text.forEach(element => {
copiedText += element.textContent + "\n";
});
const resault = document.createElement('div');
resault.classList.add('pastehere');
resault.innerText = copiedText;
document.body.appendChild(resault);
}
let copyFrom = document.querySelectorAll('.copytext');
fun(copyFrom);
You'll get:
<div class="pastehere">
Line 1 <br>
Line 2 <br>
Line 3 <br>
</div>
If you want to create element with the text you pass to the function as an argument:
JS:
function fun(text){
let resault = document.createElement('div');
resault.classList.add('pastehere');
resault.innerText = text;
document.body.appendChild(resault);
}
let text = "My text";
fun(text);
You'll get:
<div class="pastehere">
My text
</div>
!! Note that you can only type a tag name in document.createElement('');
You can use
document.getElementById("ID NAME")
To copy.
To change you can use
document.getElementsByClassName("class-name").style[0] = "max-width: 10%;"

Saving values to localStorage() and making them stay when I reload the page in Javascript

I am currently making a note writing app and need your help.
I'm struggling to understand how localStorage() works and how exactly I saved things to it. I would like to reload the page and have every note that I've written not dissappear.
Thank you.
//// Declare Variables ////
const noteBtn = document.querySelector('.add-note-btn');
const writeNote = document.querySelector('.note-input');
const allSavedNotes = document.querySelector('.added-notes');
//// Write new note and add to list ////
noteBtn.addEventListener('click', function(e){
// Create new paragraph element
let newNote = document.createElement('p');
// Add clas name to element
newNote.className = 'saved-note';
// Add the text input
newNote.textContent = writeNote.value;
// Append element to div
allSavedNotes.appendChild(newNote);
e.preventDefault();
})
<div class="all">
<div>
<div class="title">
<h1 class="heading">Notes List</h1>
</div>
<div>
<div class="writing-notes">
<textarea class="note-input" cols="35" rows="10"></textarea>
Add note
</div>
<div class="added-notes">
</div>
</div>
</div>
</div>
You can save all notes in localStorage by appending the state to an empty array.
I've intitally created a state variable that contains earlier undefined or an empty array.
Then appendNotes function appends a paragraph to the allSavedNotes DOM selector.
//// Declare Variables ////
const noteBtn = document.querySelector('.add-note-btn');
const writeNote = document.querySelector('.note-input');
const allSavedNotes = document.querySelector('.added-notes');
const state = JSON.parse(localStorage.getItem('notes')) || [];
function appendNotes(text) {
let p = document.createElement('p');
p.textContent = text;
// Append element to div
allSavedNotes.appendChild(p);
}
// append notes on page load
state.map(s => appendNotes(s));
//// Write new note and add to list ////
noteBtn.addEventListener('click', function(e) {
// Create new paragraph element
let newNote = document.createElement('p');
// Add class name to element
newNote.className = 'saved-note';
const text = writeNote.value.trim();
// Add the text input
newNote.textContent = text;
// if there are no `notes` in `localStorage` then use empty array
if (text !== "") {
state.push(text)
localStorage.setItem('notes', JSON.stringify(state));
}
// Append element to div
appendNotes(text);
newNote.textContent = "";
e.preventDefault();
})
<div class="all">
<div>
<div class="title">
<h1 class="heading">Notes List</h1>
</div>
<div>
<div class="writing-notes">
<textarea class="note-input" cols="35" rows="10"></textarea>
Add note
</div>
<div class="added-notes">
</div>
</div>
</div>
</div>
The above code won't from StackOverflow directly as it gives a cross-origin error:
Uncaught SecurityError: Failed to read the 'localStorage' property from 'Window': The document is sandboxed and lacks the 'allow-same-origin' flag.
But it works on JSFiddle. Here's a working link → https://jsfiddle.net/deadcoder0904/036bp9zy/33/
You can learn more about localStorage in this excellent blog post → https://www.digitalocean.com/community/tutorials/js-introduction-localstorage-sessionstorage

How can i add multi lines together into different different div / span tag through this text box?

How can i add multi lines together into different different span tag through this text box ?
There is an text box, by using this box i can insert a new div / span class content Right ?
But every time when i need to add new class i need to write a new line in this text box and need to press send button, Now i want that if i have 10 lines content together with "Enter" button line break
Like
My Line 1 is here
My Line 2 is here
My Line 3 is here
My Line 4 is here
My Line 5 is here
My Line 6 is here
My Line 7 is here
My Line 8 is here
... and so on
then i want to paste all 10 lines in this text box together and by pressing send button i want that all lines must be add in different different div / span class not all in one class with < br > tag that is working now.
so plz help me to improve my code
Love you Helper and Thanks in Advance
const sendButton = document.getElementById('send-btn');
const textArea = document.getElementById('input');
const innerDiv = document.getElementById('inner');
var message = textArea.value;
sendButton.addEventListener('click', function () {
const message = new MessageContainerBuilder().BuildMessage(textArea.value);
innerDiv.appendChild(message);
textArea.value = '';
});
function encodeHtmlEntity(input) {
var output = input.replace(/[\u00A0-\u9999<>\&]/gim, function (i) {
return '&#' + i.charCodeAt(0) + ';';
});
return output;
}
function MessageContainerBuilder() {
var createDivElement = function (classTest) {
var div = document.createElement('div');
var classAttr = document.createAttribute('class');
classAttr.value = classTest;
div.setAttributeNode(classAttr);
return div;
};
var createSpanElement = function (value, classTest) {
var span = document.createElement('span');
if (classTest) {
var classAttr = document.createAttribute('class');
classAttr.value = classTest;
span.setAttributeNode(classAttr);
}
span.innerText = encodeHtmlEntity(value);
return span;
};
this.BuildMessage = function (text) {
var divContainer = createDivElement('outgoing');
var messageSpan = createSpanElement(text, 'me');
divContainer.appendChild(messageSpan);
return divContainer;
};
}
<div id="inner">
<div class="incoming">
<div class="them">Lorem
</div>
</div>
<div class="outgoing">
<div class="me">Lorem ipsum
</div>
</div>
</div>
<textarea class="input" id="input" placeholder="Message..."></textarea>
<button class="waves-effect waves-light" id="send-btn">Send</button>
so plz help me to improve my code
Love you Helper and Thanks in Advance
I took some liberties and simplified your code as you can see below. It does everything I believe your code was attempting.
Note that I'm using .split("\n") to break your input based on each newline character and then iterate over that as necessary.
Also, you said you were inserting a div/span, but I don't see your code actually creating a span tag. I wrote my code to do that for you though.
const sendButton = document.getElementById('send-btn');
const textArea = document.getElementById('input');
const innerDiv = document.getElementById('inner');
var message = textArea.value;
sendButton.addEventListener('click', function() {
// split the textarea entries into an array
let lines = (textArea.value).split("\n");
// iterate over each line, creating a div/span and inserting into the DOM
lines.forEach( (line) => {
let encodedLine = encodeHtmlEntity(line);
let newElement = `<div class="me"><span>${encodedLine}</span></div>`;
innerDiv.innerHTML += newElement;
});
// reset the textarea
textArea.value = '';
});
function encodeHtmlEntity(input) {
var output = input.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
return '&#' + i.charCodeAt(0) + ';';
});
return output;
}
<div id="inner">
<div class="incoming">
<div class="them">Lorem
</div>
</div>
<div class="outgoing">
<div class="me">Lorem ipsum
</div>
</div>
</div>
<textarea class="input" id="input" placeholder="Message..."></textarea>
<button class="waves-effect waves-light" id="send-btn">Send</button>
You can try using String.prototype.split() so that each text is separated by \n (new line) into an array, then you can iterate over each element like using Array.prototype.forEach(). Here's the code you can use:
sendButton.addEventListener('click', function () {
textArea.value.split('\n').forEach((text) => {
const message = new MessageContainerBuilder().BuildMessage(text);
innerDiv.appendChild(message);
});
textArea.value = '';
});

JavaScript sanitize HTML string and remove ID, class and other attributes

I need help to sanitize my HTML text provided by user. I have following HTML code:
var htmlStr = `<p id="test" class="mydemo">TEhis is test</p>
<pre class="css">
<html>
<body class="test"></body>
</html>
</pre>`;
I want to remove ID, Class or any attribute from all the tags OTHER then <PRE> and <CODE> tags using plain JavaScript.
I tried following but not getting proper output:
sanitizeHtml(html: any) {
let temp = document.createElement('div');
temp.innerHTML = html;
// let t1 = temp.querySelectorAll('*');
temp.querySelectorAll('*').forEach(node => {
if(node.nodeName !== 'PRE') {
return node.removeAttribute('id');
}
})
console.log(temp);
// return html.replace(/\s*(\w+)=\"[^\"]+\"/gim, '').replace(/<script>[\w\W\s\S]+<\/script>/gim);
}
Please let me know if you need further information on it.
This is a little mechanical, and perhaps not the optimal solution, however you could achieve this by chaining .replace() with the following regular expressions to sanitise your HTML string as needed:
function sanitizeHtml(html) {
var htmlSanitized = html
.replace(/<pre[\w\s"=]*>/gi, function(match) {
// Add a place holder to attrbitues on pre elements to prevent
// removal of these in subsequent step
return match.replace(/=/gi, 'EQUALS')
})
.replace(/\w+="\w+"/gi,'')
.replace(/\s+>/gi,'>')
.replace(/EQUALS/i,'=')
return htmlSanitized;
}
var htmlStr = `<p id="test" class="mydemo">TEhis is test</p>
<pre class="css">
<html>
<body class="test"></body>
</html>
</pre>`;
console.log(sanitizeHtml(htmlStr));

Categories