How to fix unclosed div issue in javascript? - javascript

In a page I am getting from a server, part of the html code has this
<div class="item" />
Apparently browsers don't like the self closed div, and renders as if the slash is not there, which means there is a unclosed div tag. This results on the whole page looking terrible.
Also we can assume that I can't modify the code in the server side that returns that. So basically I am looking for a javascript hack that can fix it.
I tried a string replace on the innerHTML, but it seems to not reform and fix the page after. After it loads the first time, it seems like its permanent.
Does anyone know anyway to fix this?
Thanks

This will "fix" all divs with class item
[].forEach.call(document.querySelectorAll('.item'), function(root) {
var frag = document.createDocumentFragment();
while(root.firstChild) {
frag.appendChild(root.firstChild);
}
root.parentNode.insertBefore(frag, root.nextSibling);
});

You can't fix it properly with JS. JS accesses the DOM resulting from parsing the source code. And then it's too late, the HTML parser has alredy messed up your well-formed XHTML.
What you should do is serve your XHTML as XHTML, not as HTML.
If you can't do that, and really want a JS solution, I guess you could use AJAX to retrieve the source code of the same page, parse it with a DOMParser, and replace the malformed tree with that one.
var ajax = new XMLHttpRequest();
ajax.addEventListener("load", function() {
var code = this.responseText;
var doc = new DOMParser().parseFromString(code, "application/xhtml+xml");
document.replaceChild(doc.documentElement, document.documentElement);
});
ajax.open("GET", location.href);
ajax.send();
But that would download the same code twice, what a waste. And it's not foolproof, HTML parsers are allowed to abort at the first parse error that they encounter.

If you have access to the source code, say:
function fixClosedDivs(src) {
return src.replace(new RegExp('<div([^<]*)\/>', 'gi'), '<div$1></div>');
}
var htm = '<div class="item"/>Hi<br/>Bye<div class="item"/>Hi<div/>Bye';
console.log(fixClosedDivs(htm));
// <div class="item"></div>Hi<br/>Bye<div class="item"></div>Hi<div></div>Bye

Related

How to access local XML in javascript?

I have a html file, where I keep some notes and other info, I frequently update it, so it got quite big. The problem with that was, that if I change something in the layout, it gets really cumbersome, because I have to change it in so many places. So I had the idea, to put all the data into a XML and transform it into HTML with XSLT.
This immediately brought me to the first issue: I'm not able to access the XML.
The first thing I tried was loading it through XMLHttpRequest:
function loadXMLDoc(filename)
{
if (window.ActiveXObject)
{
xhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
else
{
xhttp = new XMLHttpRequest();
}
xhttp.open("GET", filename, false);
xhttp.setRequestHeader('Content-Type', 'application/xml');
try {xhttp.responseType = "msxml-document"} catch(err) {} // Helping IE11
xhttp.send("");
return xhttp.responseXML;
}
But this gets blocked with "Reason: CORS request not HTTP". I know why I get it and I also know that there most likely is no way around that when using XMLHttpRequest. (except tampering with local browser security, which I don't want to do).
My next idea was to put the XML as string directly into the script and just parse it into a XML doc. Something like:
var rawXml = "
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar/>
<bar/>
</foo>
";
But this gets me a "Uncaught SyntaxError: "" string literal contains an unescaped line". So apparently javascript doesn't support any form of verbatim strings and I have to escape all the linebreaks with a \n. My problem with that is, that I'm going to loose the pretty formatting. So reading and editing the XML is going to be a pain. That's definitely something I want to avoid.
EDIT:
Thanks to #Taplar for pointing out, that I can use a template literal, which makes the latter approach work.
This solution is not optimal, since I use NotePad++ and I can either use syntax highlighting for HTML or XML, plus XML Tools syntax autocheck gets screwed over by all the HTML code. But so far it is the best solution I have. Should there be any other options left, I'd like to hear them!
(As other people already pointed out to use input type=file, this is no real viable solution for me. I want to open the HTML document and read it. But with the input elements I have to first pick the XML and the pick the XSL. That's kinda cumbersome over which I prefer the xml-as-string solution)
You should set the XMLHttpRequestInstance.responseType to 'document':
function loadXMLDoc(filename, func){
const x = new XMLHttpRequest;
x.open('GET', filename); x.responseType = 'document';
x.onload = d=>{
func(d);
}
x.send();
return x;
}
// here's how you would execute
loadXMLDoc('yourFile.xml', d=>{
const productNodeList = d.getElementsByTagName('product');
});

How to SSI include Variable Filename

I have recently discovered SSI and don't really fully know how it works. I have written this javascript code, shown below, that is supposed to turn the end of the link into a text file name (which it does just fine). Then all of the characters necessary to escape are escaped, code below.
var path = window.location.pathname;
var page = path.split("/").pop();
var res = path.replace(".html", ".txt");
var res = res.replace("/Iliad/", "");
console.log(res);
element = document.getElementById('book');
element.innerHTML = "\<\!\-\-\#include virtual="+res+" \-\-\>";
According to the console (inspect element), <!--#include virtual=1.txt --> is added perfectly correctly to an html div container's innerHTML, but it does not incldue the .txt file that it references. I have searched the internet and cannot find a solution to this. Is there something I'm doing wrong? If so, how do I accomplish this. Thanks!
Server-side includes are processed on the server (hence the name), so long as the server is properly configured.
Modifying the data in the browser (long after it has left the server) cannot trigger processing of the SSI on the server.
Look to Ajax and DOM manipulation instead.
Thanks to #Quentin for his speedy answer. After being told exactly what SSI is meant to do, I searched for another solution.
This worked for me! I modified the code as follows...
var request = new XMLHttpRequest();
request.open('GET', res, false);
request.send();
var textfileContent = request.responseText;
element = document.getElementById('book');
element.innerHTML = textfileContent;
Hope this helps anyone else!

How to prevent resource loading of unattached elements in Chrome

I'm working on Chrome extension and I have following problem:
var myDiv = document.createElement('div');
myDiv.innerHTML = '<img src="a.png">';
What happens now is that Chrome tries to load the "a.png" resource, even If I don't attach the "div" element to document. Is there a way to prevent it?
_In the extension I need to get data from a site that doesn't provide any API, so I have to parse the whole HTML to get the necessary data. Writing my own simple HTML parser could be tricky so I would rather use the native HTML parser. However, in Chrome when I put the whole source code to some temporary non-attached element (so it would get parsed and I could filter the necessary data), ale the images (and possibly other resources) start to load as well, causing higher traffic or (in case of relative paths) lots of errors in console. _
To prevent the resources from being loaded, you'll need to create your Node in an entirely new #document. You can use document.implementation.createHTMLDocument for this.
var dom = document.implementation.createHTMLDocument(); // make new #document
// now use this to..
var myDiv = dom.createElement('div'); // ..create a <div>
myDiv.innerHTML = '<img src="a.png">'; // ..parse HTML
You can delay parsing/loading html by storing it in non-standard attribute, then assigning it to innerHtml, "when the time comes":
myDiv.setAttribute('deferredHtml', '<img src="http://upload.wikimedia.org/wikipedia/commons/4/4e/Single_apple.png">');
global.loadDeferredImage = function() {
if(myDiv.hasAttribute('deferredHtml')) {
myDiv.innerHTML = myDiv.getAttribute('deferredHtml');
myDiv.removeAttribute('deferredHtml');
}
};
... onclick="loadDeferredImage()"
I created jsfiddle illustrating this idea:
http://jsfiddle.net/akhikhl/CbCst/3/

Is there a way to refresh just the javascript include while doing development?

While doing development on a .js file I'd like to just refresh that file instead of the entire page to save time. Anyone know of any techniques for this?
Here is a function to create a new script element. It appends an incremented integer to make the URL of the script unique (as Kon suggested) in order to force a download.
var index = 0;
function refreshScript (src) {
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.src = src + '?' + index++;
document.getElementsByTagName('head')[0].appendChild(scriptElement);
}
Then in the Firebug console, you can call it as:
refreshScript('my_script.js');
You'll need to make sure that the index itself is not part of the script being reloaded!
The Firebug Net panel will help you see whether the script is being downloaded. The response status should be "200 OK" and not "304 Not Modified. Also, you should see the index appended in the query string.
The Firebug HTML panel will help you see whether the script element was appended to the head element.
UPDATE:
Here is a version that uses a timestamp instead of an index variable. As #davyM suggests, it is a more flexible approach:
function refreshScript (src) {
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.src = src + '?' + (new Date).getTime();
document.getElementsByTagName('head')[0].appendChild(scriptElement);
}
Alexei's points are also well-stated.
I suggest you to use Firebug for this purpose.
See this video, it helped me a lot.
http://encosia.com/2009/09/21/updated-see-how-i-used-firebug-to-learn-jquery/
If you're talking about the unfortunate case of client-side/browser caching of your .js file, then you can simply version your .js file. You can:
Rename the .js file itself (not preferred)
Update the include line to reference yourfile.js?1, yourfile.js?2, etc.. Thus forcing the browser to request the latest version from the server. (preferred)
Unfortunately, you have to refresh the web page to see edits to your JavaScript take place. There is no way that I know of to edit JavaScript in "real-time" and see those edits effect without a refresh.
You can use Firebug to insert new JavaScript, and make real-time changes to DOM objects; but you cannot edit JavaScript that has already been run.
If you just fed up refilling the forms while developing just use form recover extensions like this one https://addons.mozilla.org/ru/firefox/addon/lazarus-form-recovery/

Simplest possible method: html break in XML doc

I have a c program which outputs a number of lines to another c program which stuffs them in a PHP page which is loaded with AJAX. The problem is that the output is a number of lines, which is fine to look at, but which, when viewed as HTML, lack line breaks.
The initial thought I had was obviously to put line breaks in with the output. -- That worked fine, especially since I was using responseText to handle the AJAX output. Now I have discovered that along with the raw text, a bit of metadata also needs to be part of the AJAX response. I jumped over to using responseXML, only to find that the tags no longer worked correctly. At this point I could slog through any number of tutorials to figure out how to work some more complicated mechanism, but I really just want a hack. Could I embed the metadata in an html comment and use the DOM to dig it out (I looked and don't see a good method to get to comments using the dom...)? Could I use the xml directly as html somehow? Could I use CDATA in the xml document(this doesn't seem hopeful)? Could I just use newlines until the code reaches the webpage and then have JS insert the br tags?
I don't need any other formatting, just line breaks, and all this needs to do is work, the less complex the better.
How about using a XSLT stylesheet to format your incoming XML. Save the following as an .html file for an example. Sources : http://www.w3schools.com/xsl/xsl_client.asp & http://www.w3schools.com/dom/dom_parser.asp
<html>
<head>
<script>
//YOUR XML FROM AJAX
var XML = "<top><meta><itemone>test meta</itemone></meta><rows><row>line one</row><row>line two</row><row>line three</row></rows></top>";
//A stylesheet to format the lines that come back.
var XSLT = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><h2>Lines</h2><xsl:for-each select="descendant::row"><xsl:value-of select="self::*"/><br /></xsl:for-each></xsl:template></xsl:stylesheet>'
function loadXMLDoc(xml)
{
var tempXML;
//IE
if (window.ActiveXObject)
{
tempXML=new ActiveXObject("Microsoft.XMLDOM");
tempXML.loadXML(xml);
}
else if(window.DOMParser)
{
parser=new DOMParser();
tempXML=parser.parseFromString(xml,"text/xml");
}
return tempXML;
}
function displayResult()
{
var xmlDoc = loadXMLDoc(XML);
var xsltDoc = loadXMLDoc(XSLT);
// code for IE
if (window.ActiveXObject)
{
var ex=xmlDoc.transformNode(xsltDoc);
document.getElementById("example").innerHTML=ex;
}
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation && document.implementation.createDocument)
{
var xsltProcessor=new XSLTProcessor();
xsltProcessor.importStylesheet(xsltDoc);
var resultDocument = xsltProcessor.transformToFragment(xmlDoc,document);
document.getElementById("example").appendChild(resultDocument);
}
}
</script>
</head>
<body onload="displayResult()">
<div id="example" />
</body>
</html>
Thanks for all the good suggestions, but I eventually decided to just prepend a fixed number of descriptor bytes to each text response and then use the substring command to get either the descriptor bytes or the main text response.
This allows me to keep using the simpler response-text mechanism, and is otherwise uncomplicated.
I would have used custom headers but I realized that that would have required buffering the whole output in yet ANOTHER place since the php script actually only contains a single system() call, and has no idea what the C program behind it is doing.

Categories

Resources