How do I display Javascript code as page content? - javascript

I made a webpage that needs javascript. More specifically if anyone has heard of it, I am using an Ajax-Solr API to make a good user interface for an Apache Solr/Lucene Search Engine. For some of the results that come up (which are webpages that have been crawled), javascript is embedded on some of the webpages, and that is messing up part of my subsequent html/javascript. Help me out. Here is some of my code:
AjaxSolr.theme.prototype.snippet = function(doc) {
var output = '' + doc.id;
if (doc.text.length > 300) {
output += doc.text.substring(0, 300);
output += '<span style="display:none;">' + doc.text.substring(300);
output += '</span> <br id="aftsnippet"/><button id = "expand' + doc.id + '">Expand/Contract</button>';
} else {
output += doc.text + '<br/>';
}
output+='<a id="goToSite"><button>Go to Site</button></a><button id = "sitedetailsbutton' + doc.id + '">Site Details</button>';
return output;
};
I don't know if that helps, but pretty much what happens is that doc.text might contain some random javascript from a javascript file online, and then that causes the buttons from
<button>Go to Site</button></a><button id = "sitedetailsbutton' + doc.id + '">Site Details</button>';
to not show up. What could I do to fix this?

You need to HTML-encode the JavaScript. You can do that with the following.
function htmlEncode(s) {
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
}
Also, you can replace newline characters with <br />, as appropriate:
function htmlEncode(s) {
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\n/g,'<br />');
}

Related

Having trouble applying event listeners to <divs>

Hey guys I'm creating an email app and I have an issue when I'm printing out the emails to the inbox screen for each user. Each email in the inbox is a preview of the email in a . I want to attach an onclick event listener to each in order to have it clickable where if you click it you get a page of the actual full body of the email.
My function open_email() takes an argument that is the email ID. this is what I will use to bring up the email. But I need to pass the proper ID in.
The way it's working now is the ID is always '1' which is the ID first email I created.
I can't figure out why it's changing each ID to '1'. There has to be something wrong with my code in the loops that I am missing.
Can anyone find it? Thanks!
if (mailbox == "inbox") {
fetch('/emails/inbox')
.then(response => response.json())
.then(emails => {
const element = document.getElementById("emails-view");
for (index = 0; index < emails.length; index++) {
var x = emails[index].id
if (emails[index].read == false) {
element.innerHTML += '<div class="emails unread">' + "From:" + JSON.stringify(emails[index].sender) +
"<p class='subject'>" + "Subject: " + JSON.stringify(emails[index].subject) + "</p>" + JSON.stringify(emails[index].timestamp) + '</div>';
element.onclick = () => open_email(x)
}else{
element.innerHTML += '<div class="emails">' + "From:" + JSON.stringify(emails[index].sender) +
"<p>" + "Subject: " + JSON.stringify(emails[index].subject) + "</p>" + JSON.stringify(emails[index].timestamp) + '</div>';
element.onclick = () => open_email(x)
}
}
});
You're adding an event listener to the whole container and overwriting it every iteration of the loop. Instead, add a listener to the appended element.
A problem is that using innerHTML += will corrupt existing listeners inside the container, so use appendChild instead:
const container = document.getElementById("emails-view");
for (const email of emails) {
const { read, id, timestamp, sender, subject } = email;
const emailDiv = container.appendChild(document.createElement('div'));
emailDiv.className = read ? 'emails' : 'emails unread';
emailDiv.innerHTML = `
From: ${JSON.stringify(sender)}
<p class='subject'>Subject: ${JSON.stringify(subject)}</p> ${timestamp}
`;
emailDiv.onclick = () => open_email(id);
}
That's the general idea - but there's another problem. Concatenating HTML strings from user input can result in arbitrary code execution. To prevent unsafe code from being run, make sure that the values being put into the HTML don't contain HTML tag delimiters (< and >).
const clean = str => str
.replaceAll('<', '<')
.replaceAll('>', '>');
and use, eg:
From: ${JSON.stringify(clean(sender))}
Or, even better, sanitize the text before putting it into the database.
(do you really need JSON.stringify everywhere? that seems strange, remove it if you can)

Regex, doesnt stop matching

I'm working on a bbcode example, but i cannot seem to get it to work.
the regex matches all the [img] tags and make it all look wierd. I'm trying to have the option to click on the image and get it full size and when I do, everything becomes a link (when i have more than once img-tag).
Here's my text:
[img size="small" clickable="no"]img1.jpg[/img]
[img size="large" clickable="yes"]img2.jpg[/img]
Here's my source code:
var bbArray = [/\n/g,
/\[img size="(.*?)" clickable="yes"\](.*?)\[\/img\]/g,
/\[img size="(.*?)" clickable="no"\](.*?)\[\/img\]/g];
var bbReplace = ['<br>',
'<img src="'+path+'img/$1_$2?'+ new Date().getTime() +'" alt="$2">',
'<img src="'+path+'img/$1_$2?'+ new Date().getTime() +'" alt="$2">'];
The operation:
for (var i = 0; i < content_text_bb.length; i++) {
content_text_bb = content_text_bb.replace(bbArray[i], bbReplace[i]);
}
the result:
<img src="localhost/img/small" clickable="no" ]img1.jpg[="" img]
[img size="large_img2.jpg?1423317485160" alt="img2.jpg">;
I'm not that familiar with regex and I really need someone to look at it, I'm lost.
Something that may be of interest to you, Extendible BBCode Parser. An example of use.
var bbcArr = [
'[img size="small" clickable="no"]img1.jpg[/img]',
'[img size="large" clickable="yes"]img2.jpg[/img]'
];
XBBCODE.addTags({
"img": {
openTag: function(params, content) {
params = (params.match(/(\S+?=".*?")/g) || [])
.reduce(function(opts, item) {
var pair = item.match(/(\S+?)="(.*?)"/);
opts[pair[1]] = pair[2];
return opts;
}, {});
var html = '<img src="http://localhost/img/';
if (params.clickable === 'yes') {
html = '<a href="http://localhost/img/' + content +
'" alt="' + content + '">' + html;
}
if (params.size === 'small' || params.size === 'large') {
html += params.size + '/';
}
html += content + '" />';
if (params.clickable === 'yes') {
html += '</a>';
}
return html;
},
closeTag: function(params, content) {
return '';
},
displayContent: false
}
});
bbcArr.forEach(function(item) {
var result = XBBCODE.process({
text: item,
removeMisalignedTags: false,
addInLineBreaks: false
});
this.appendChild(document.createTextNode(result.html + '\n'));
}, document.getElementById('out'));
<script src="https://rawgithub.com/patorjk/Extendible-BBCode-Parser/master/xbbcode.js"></script>
<pre id="out"></pre>
First thing first, your loop should be:
for (var i = 0; i < bbArray.length; i++) {
(not content_text_bb.length)
Secondly, the issue you have is with this size="(.*?). This says: match any content non-greedily till I find the first "thing-that-follow" (in this case the thing-that-follows is the first occurrence of " clickable="yes"
If you look at your input text, the search for [img size="{ANYTHING}" clickable="yes"] means that {ANYTHING} is: small" clickable="no"]img1.jpg[/img][img size="large and you can see how that returns your results, and breaks everything.
So, it should firstly be noted that regexps are not the best tool for language processing (plenty of posts on SO and the internet at large on the topic). In this particular case, you can fix your problem by being very specific about what you want matched.
Do NOT match "anything". If you want to match a size attribute, look for digits only. If you want to match any property value, look for "{ANYTHING_NOT_DOUBLE_QUOTES}". So, with that said, if you change bbArray to the code below, it should work in the particular example you have given us:
var bbArray = [/\n/g,
/\[img size="([^"]*)" clickable="yes"\](.*?)\[\/img\]/g,
/\[img size="([^"]*)" clickable="no"\](.*?)\[\/img\]/g];
Just to be clear: while this should work on your current input, it is by no mean robust bbcode processing. It will only match [img] bbcode tags that have exactly one size attribute and one clickable attribute, in that order!! Most free-to-type bbcode out-there will have much broader variations, and this code obviously won't work on them.

Append dymanic data from sessionStorage (JSON) to Listview

I have the following bit of data(JSON) stored in a session:
Prescription: [{"medID":"id1","medName":"name1","medQty":"qty1","medDirec":"Directions1"}, {"medID":"id2","medName":"name2","medQty":"qty2","medDirec":"Directions2"}]
I want to get these information automatically "displayed" inside a Listview (jQuery Mobile) on page load, for this I have come up with the following:
$(document).ready(function () {
window.addEventListener('load', OnStorage, false);
});
function OnStorage(event) {
if (window.sessionStorage) {
var retrievedData = sessionStorage.getItem("Prescription");
var PrescriptionJSON = JSON.parse(retrievedData);
var prescLength = PrescriptionJSON.Length();
for (var i = 0; i < PrescriptionJSON.Length(); i++) {
var text = '<h2>' + PrescriptionJSON[i].medName + '</h2>' +
'<p><strong>Quantity: </strong>' + PrescriptionJSON[i].medQty + '</p>' +
'<p><strong>Directions: </strong>' + PrescriptionJSON[i].medDirec + '</p>'
$('<li />', {
html: text
}).appendTo("#summaryList ul");
//$("#summaryList").append(text);
//alert(retrievedData);
}
$('#summaryList').listview("refresh");
$('#summaryList').trigger("create");
}
}
When I uncomment //alert(retrievedData); I get the JSON inside an alert popup, but when I call //alert(PrescriptionJSON); (the parsed variable) I get something like [object, Object]. Nonetheless, I don't know if this is worth mentioning but just in case I am.
Basically I don't know what is wrong in the script above, because I don't get anything from the JSON data appended to the listview.
Just for reference I have this on my HTML side.
<ul id="summaryList" data-role="listview" data-inset="true">
<li data-role="list-divider" style="text-align:center">Prescription Summary</li>
</ul>
Please note that the length of the data (Prescription) will be dynamically created so the length may not always be 2 like the example above.
I have gone through a good 2 hrs researching online and have found similar questions but none could help me solve my problem. I've also had a look at http://www.copterlabs.com/blog/json-what-it-is-how-it-works-how-to-use-it/ and learned a few more things but still have not be able to work my way around my problem.
Any suggestions or questions are greatly welcomed!
var PrescriptionJSON = '[{"medID":"id1","medName":"name1","medQty":"qty1","medDirec":"Directions1"}, {"medID":"id2","medName":"name2","medQty":"qty2","medDirec":"Directions2"}]';
localStorage.setItem("PrescriptionJSON", PrescriptionJSON);
function OnStorage(event) {
if (window.localStorage) {
var retrievedData = localStorage.getItem("PrescriptionJSON");
var obj = $.parseJSON(retrievedData);
var li = "";
$.each(obj, function(key, value) {
li += '<li><h2>' + value.medName + '</h2><p><strong>Quantity: </strong>' + value.medQty + '</p><p><strong>Directions: </strong>' + value.medDirec + '</p></li>'
})
$('#summaryList').append(li).trigger("create");
$('#summaryList').listview("refresh");
}
}

Javascript functions. variable result. why undefined or doesn't if else statement function?

I need the values of the name, address, size, and topping fields to appear in a text box. Without problems the name and address appears correctly. However I can't seen to get the size function to work. It is a radio button, and thus I need only one size to appear. I haven't even tried an if else for the checkbox yet. Here is my code
<html>
<head>
<script>
function pizza() {
document.pizzaboy.comments.value = "Name:" + " " + pizzaboy.name.value + "\n" + "Address:" + " " + pizzaboy.address.value + "\n" + document.getElementById("small").value + document.getElementById("medium").value + document.getElementById("large").value + "\n" + pizzaboy.toppings.value;
{
var rslt = "";
if (document.pizzaboy.size[0].checked) {
rslt = rslt + "Size=Small\n";
} else if (document.pizzaboy.size[1].checked) {
rslt = rslt + "Size=Medium\n";
} else rslt = rslt + "Size=Large\n";
return rslt;
}
}
</head>
The second Javascript bracket might be throwing you an error, keeping your code from running correctly.
In this post, several (more general) ways to get values of radio buttons are explained:
Checking Value of Radio Button Group via JavaScript?
The first answer is using jQuery, but the following answers will help you i think.
You should try this. Answer here if you need further assistance.

attempting to split string dynamically keep getting error?

I'm attempting to split a string I'm passing into
$("#groupUL").append("<li>" + "<h2>About Item:</h2> " + response.data[i].message + "<br /> " + "<h2>Posted By:</h2> <a href='#' onclick='splitName('" + response.data[i].from.name + "');'>" + response.data[i].from.name + "</a>" + "<br />");
Seems to be passing me the error
SyntaxError: syntax error
splitName(
Not sure how that's wrong...Here is the splitname function if that helps
function splitName(txt){
var myString = txt;
var mySplitResult = myString.split(" ");
console.log("The first element is " + mySplitResult[0]);
console.log("<br /> The second element is " + mySplitResult[1]);
console.log("<br /> The third element is " + mySplitResult[2]);
};
It's too hard to get it right when you put quotes in quotes in quotes and you try to escape it right. You got it wrong.
A solution is to make it in small parts :
var action = "splitName('" + response.data[i].from.name + "');";
$("#groupUL").append("<li>" + "<h2>About ... onclick=\""+action+"\">...");
But the best solution would be to follow best practice, that is not inline the javascript but use jQuery's binding function :
$("#groupUL").append("... <a id=myid ...");
$("#myid").click(function(){ splitName(response.data[i].from.name) });
I think the only problem with your code is with your readability issue. So I would suggest please improve it. Lets have a look at it. My code example # JSbin.
Here is the code :- (which i think is better)
var response = {
data : {
message: 'Cleaning code',
from: {
name: 'Clean Code works'
}
}
};
var li = $('<li>'); //Create empty li (Not Appending to DOM now due to performance issues)
$('<h2>').html('About Item:' + response.data.message + '<br />').appendTo(li);
$('<h2>').html('Posted By:').appendTo(li);
$('<a>').attr('href', '#')
.html(response.data.from.name)
.appendTo(li)
.click(function() {
splitName(response.data.from.name);
});
$('<br>').appendTo(li);
// Append li to ul (Final operation to DOM)
li.appendTo('#groupUL');
function splitName(txt){
var myString = txt;
var mySplitResult = myString.split(" ");
console.log("The first element is " + mySplitResult[0]);
console.log("The second element is " + mySplitResult[1]);
console.log("The third element is " + mySplitResult[2]);
}

Categories

Resources