I need to access a XML document I created with JavaScript via XPath. If I load an XML file from a server (via XMLHttpRequest) it works fine, but if I use the XML document reference from the local created XML document Chrome didn't show anything, while Firefox did what I expected.
Here a bit of example code:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<script type="text/javascript">
var xml = document.implementation.createDocument("", "", null);
var root = xml.createElement("root");
var level1 = xml.createElement("L1");
var level2 = xml.createElement("L2");
L2txt = xml.createTextNode("here is L2");
level2.appendChild(L2txt);
level1.appendChild(level2);
var level2 = xml.createElement("L2");
level2.setAttribute("id", "myId");
L2txt = xml.createTextNode("here is L2 with id");
level2.appendChild(L2txt);
level1.appendChild(level2);
root.appendChild(level1);
path="//L2[#id='myId']";
var nodes=xml.evaluate(path, root, null, XPathResult.ANY_TYPE, null);
var result=nodes.iterateNext();
while (result) {
document.write(result.textContent);
document.write("<br />");
result=nodes.iterateNext();
}
</script>
</body>
</html>
the Code should output "here is L2 with id".
I use FF 9.0.1 and Chrome 16.0.912.75 m the development tools don't show any error or hint.
Now I don't realy know, is it a bug in Chrome or an 'extra' feature in Firefox. And - most importent - how could I bring Chrome round to act like Firefox. Or do you have another idea how to use XPath on local created XML documents?!
Thanks in advance
I see you have a small problem in your example code.
The root element is never added to the XML document (the xml variable).
Therefore the XPath search cannot work since the xml document object has no root element and therefore no content to search. Try adding :
xml.appendChild(root);
After this:
var root = xml.createElement("root");
That fixes the issue for me in Chrome.
Related
I am trying to access an element in my Edge Animate animation (which is a menu bar) from the parent document. The element has an onClick event which is triggered depending on the #bookmark in the URL of the parent web page. My code works perfectly in Firefox but does not work in Internet Explorer(10). IE is unable to see any elements within the 'Stage' div whereas Firefox can.
This is the JavaScript code on my parent page: -
<script language='javascript'>
var thisPage = window.location.pathname;
var fullurl = document.URL;
var xxx = fullurl.substring(fullurl.indexOf('#'));
var pageString = xxx.replace("#", "");
pageString = pageString.replace("http://www.mydomain.com/portfolio/photography.html", "");
if (pageString == "corporate") {
window.onload = function() {
var iframe = document.getElementById('U10511_animation');
var innerDoc = (iframe.contentDocument) ?
iframe.contentDocument : iframe.contentWindow.document;
var corporateRectangle = innerDoc.getElementById('Stage_Corporate_Rectangle');
corporateRectangle.click();
}
};
</script>
The above code will select the Corporate tab in the menu when viewed in Firefox but not IE when the URL has the suffix #corporate.
When I insert an 'alert' for the variable 'corporateRectangle' in Firefox it returns [HTMLObj] and in IE it returns 'null'.
Any ideas anyone? Thanks.
Have you tried checking the console for an error of some sort to help you and us understand the error?
IE JavaScript often works differently than in other browsers. And iframes are particularly problematical. One possibility is that you are getting the wrong document, such that the documentyou are retrieving either does not exist or does not contain the element you are looking for. So you just have to do some debugging. Here is how I would proceed. Run your script in IE.
1) Determine whether innerDoc is iframe.contentDocument or iframe.contentWindow.document. Make sure innerDoc is not null. If it is, try to get the document a different way.
2) Assuming innerDoc is not null, enumerate all of the elements in innerDoc. You can do that as follows:
for(i = 0; i < innerDoc.all.length; i++) alert(innerDoc.all [i].id);
Make sure that the id you are looking for is actually in the document. I suspect it isn't and that you need to get a different document object under IE.
I assume you are stuck with having to use iframes. If not, I suggest you use a different approach as iframes can be very problematical and browser-specific in how they work.
internet Explorer gets confused over name and id - it is highly recommended to treat these two attributes as if they were the same.
You can fix it either by 1) ensure that there are no id/name conflicts in your document, or 2)
override IE's native getElementById-method.
Read more about it here.
Ok... thanks to everyone who left suggestions.
The issue was that the menu animation has a preloader. Firefox ignores the preloader whereas IE treats the preloader as onLoad being complete. Therefore the attempt to access the element ID is null as it hasn't been loaded yet.
I decided to approach the problem from a different tack and read my bookmark from within the animation. This turned out to be a very simple solution once I figured out that I had to put the code in the first frame of the animation NOT in creationComplete or compositionReady.
This was the code: -
var bookmark = parent.window.location.hash;
bookmark = bookmark.replace("#", "");
if (bookmark == "corporate") {
sym.play("corp");
}
yes, as simple as that.
On a website I'm designing a user searches for hotels in a city, and results are returned as xml then formatted through ajax/javascript/jquery.
The results are displayed almost immediately in Chrome or FF, but in Internet Explorer (I've tried ie6 and ie9) the results take almost a minute to be displayed.
Running the developer tools in IE states that 99% of execution time is spent in function "getElementsByTagName" which is called almost 200,000 times, however I'm unaware of how to fix this if it is the issue.
The page in question is beta.hotelsweep.com and the function being called on search is:
//summarized version of the function
$.get(url, function (xmlResponse) {
$('#results').empty();
var exception = $("Exception", xmlResponse);
if (exception.size() > 0) {
var error = "<h2>We were unable to complete your request</h2>";
$('#results').html(error);
} else {
$('#numResults').html($("resultsNumber", xmlResponse).text() + " hotels found <br>");
var resultsHtml = "<div id='results_list'>";
//set googlem map to center
map.setCenter(new GLatLng($("avgLat", xmlResponse).text(), $("avgLong", xmlResponse).text()), 9);
// Loop through response, creating <li> for each hotel
$("Hotel", xmlResponse).each(function () {
var bookLink = $('affiliateLink', this).text();
var address = $('fulladdress', this).text();
var stars = $('stars', this).text();
resultsHtml += 'Hotel Stars: ' + stars;
});
//put html into results div
$('#results').html(resultsHtml);
}
});
You can't really fix this issue. getElementsByTagName isn't indexed in older versions of IE. You can use element id lookups instead (avoid $("Exception"), $("avgLat"), etc).
If that's not feasible, you can add a script on the server to render the results to HTML.
It turns out the issue was something to do with the document mode. In quirk mode, the javascrit wasn't even fully executing.
Adding this to the top:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
or
<meta http-equiv="X-UA-Compatible" content="IE=9" />
Made Internet Explorer execute as expected. I don't fully understand what is happening, but if you find your javascript executing incorrectly only in IE it could be to do with the document mode.
I want a Javascript function that returns a correct DOM when input is HTML content.
I have used the follwing function for the same. Here input is HTML content and output is DOM.
function htmltoelement(elementHTML)
{
var temDiv = document.createElement('div');
temDiv.innerHTML = elementHTML;
return temDiv;
}
This function works well for Firefox, but not for IE or Chrome, when the HTML is broken.
I need a suggestion for a function that works fine on all the browsers even when HTML is broken.
With "broken" HTML (which I am assuming is invalid) the way it is interpreted is largely up to the browser and the mode that the browser is in. The DOCTYPE at the top will dictate how the innerHTML property is parsed when it is set. For XHTML, it will give you some odd results because "broken" HTML will mess up your entire page. The function you are using is correct, but it seems you need to check your input for compliance before attempting to create the div.
You can achieve this by writing it out to a hidden iframe:
<iframe id="frame" style="display:none"></iframe>
<script type="text/javascript">
function htmltoelement(elementHTML)
{
var temp = document.getElementById('frame');
// Cross-browser way to get the iframe document
var idoc = (temp.contentWindow || temp.contentDocument);
if (idoc && idoc.document) idoc = idoc.document;
// Put the HTML in the iframe
idoc.write("<html><body>" + elementHTML + "</body></html>");
temDiv = document.createElement('div');
temDiv.innerHTML = idoc.body.innerHTML;
return temDiv;
}
document.body.appendChild(htmltoelement('<b><i>hi</b></i>'));
</script>
The hidden IFRAME seems to be necessary, document.createElement('iframe') didn't work in Opera.
I have an issue where the JavaScript source file is loading in popup for IE6, Chrome, Firefox, Safari and Opera. But the same source file is not loading up in IE8.
As a result of this the HTML is not being replaced in the Popup and I am getting an error in IE8 popup saying tinyMCE is not defined
I have referred to Formatting this JavaScript Line and solved issue on all browsers except IE8.
The JavaScript function is as follows:
function openSupportPage() {
var features="width=700,height=400,status=yes,toolbar=no,menubar=no,location=no,scrollbars=yes";
var winId=window.open('','',features);
winId.document.open();
winId.document.write('<html><head><title>' + document.title + '</title><link rel="stylesheet" href="../css/default.css" type="text/css">\n');
var winDoc = winId.document;
var sEl = winDoc.createElement("script");
sEl.src = "../js/tiny_mce/tiny_mce.js";/*TinyMCE source file*/
sEl.type="text/javascript";
winDoc.getElementsByTagName("head")[0].appendChild(sEl);
winId.document.write('<script type="text/javascript">\n');
winId.document.write('function inittextarea() {\n');
winId.document.write('tinyMCE.init({ \n');
winId.document.write('elements : "content",\n');
winId.document.write('theme : "advanced",\n');
winId.document.write('readonly : true,\n');
winId.document.write('mode : "exact",\n');
winId.document.write('theme : "advanced",\n');
winId.document.write('readonly : true,\n');
winId.document.write('setup : function(ed) {\n');
winId.document.write('ed.onInit.add(function() {\n');
winId.document.write('tinyMCE.activeEditor.execCommand("mceToggleVisualAid");\n');
winId.document.write('});\n');
winId.document.write('}\n');
winId.document.write('});}</script>\n');
window.setTimeout(function () {/*using setTimeout to wait for the JS source file to load*/
winId.document.write('</head><body onload="inittextarea()">\n');
winId.document.write(' \n');
var hiddenFrameHTML = document.getElementById("HiddenFrame").innerHTML;
hiddenFrameHTML = hiddenFrameHTML.replace(/&/gi, "&");
hiddenFrameHTML = hiddenFrameHTML.replace(/</gi, "<");
hiddenFrameHTML = hiddenFrameHTML.replace(/>/gi, ">");
winId.document.write(hiddenFrameHTML);
winId.document.write('<textarea id="content" rows="10" style="width:100%">\n');
winId.document.write(document.getElementById(top.document.forms[0].id + ":supportStuff").innerHTML);
winId.document.write('</textArea>\n');
var hiddenFrameHTML2 = document.getElementById("HiddenFrame2").innerHTML;
hiddenFrameHTML2 = hiddenFrameHTML2.replace(/&/gi, "&");
hiddenFrameHTML2 = hiddenFrameHTML2.replace(/</gi, "<");
hiddenFrameHTML2 = hiddenFrameHTML2.replace(/>/gi, ">");
winId.document.write(hiddenFrameHTML2);
winId.document.write('</body></html>\n');
winId.document.close();
}, 300);
}
Additional Information:
Screen shot of the page
Rendered HTML
Original JSPF
please help me with this one.
Why are you using actual DOM functions to add the <script> tag that includes tinymce.js but everything else is using document.write?
I think that's also where your problem lies, as <head> is within <html>, which is not yet closed where you want to append said <script> tag.
Otherwise, you could use the existing <script> tag in the popup to add the code that includes the required external javascript file. If that makes any sense.
So, basically I'm saying, try it the same way as everything else is in your script, using document.write.
(quick addition) I'm not saying this is the 'best' way to do this, I would recommend creating an actual page instead of dynamically creating one in the popup. But in this scenario, I think what I wrote earlier might solve the problem you are having.
for example ,I have the following html
<HTML>
<HEAD>
<script type="text/javascript">
function trackElement(event){
event=event||window.event;
var target = event.explicitOriginalTarget||event.srcElement||document.activeElement;
var targetText = target.nodeValue||target.innerHTML;
alert(targetText);
}
</script>
</HEAD>
<BODY onclick="trackElement(event)">
<div>bbbbbb<div>cccccc</div>dddddddddd<div>eeeeeeeee</div></div>
</BODY>
</HTML>
When I clicked "bbbbbb",
On firefox ,I got "bbbbbb" alerted
which is exactly what I expected.
But on IE, I got
"bbbbbb<div>cccccc</div>dddddddddd<div>eeeeeeeee</div>"
When I clicked "dddddddddd",
On firefox ,I got "dddddddddd"
alerted which is exactly what I
expected.
But on IE, I got
"bbbbbb<div>cccccc</div>dddddddddd<div>eeeeeeeee</div>"
How can I get the same result with firefox on IE?
That's because the property "nodeValue" returns null for element nodes so you return innerHtml instead, which is gonna contain the whole html code inside an element. In Internet Explorer, your target is assigned by event.srcElement and hence is an element node, while it's a text node in FF. One way to solve the problem would be the following code :
function trackElement(event){
event=event||window.event;
var targetText;
var target = event.explicitOriginalTarget||event.srcElement||document.activeElement;
if(target.nodeType==3){
targetText = target.nodeValue
}else{
targetText = target.firstChild.nodeValue;
}
alert(targetText);
}
This way, you'd return the value if your assignment assigned a text node, and the text of the first child (which is what you're after) for an element node.
EDIT: Turns out I'm wrong. The problem is that event.srcElement returns the whole Element that's being clicked (event.explicitOriginalTarget being mozilla specific). From there, you need to retrieve the text. I see no easy way to do that if there are several texts in the element. If there is only one, it's a matter of iterating over the child nodes and displaying the text ones.
Please see comment about explicitoriginaltarget in crossbrowser-equivalent-of-explicitoriginaltarget-event-parameter.
In IE you get the Div element and the second one is in it, does this solution of separating the divs work for you? - the script is the same...
(This works both in IE and in FF)
<BODY onclick="trackElement(event)">
<div>bbbbbb</div>
<div>cccccc</div>
</BODY>
What about just substringing it?
<script type="text/javascript">
function trackElement(event){
event=event||window.event;
var target = event.explicitOriginalTarget||event.srcElement||document.activeElement;
var targetText = target.nodeValue||target.innerHTML.substr(0, target.innerHTML.indexOf("<"));
alert(targetText);
}
</script>
</HEAD>
<BODY onclick="trackElement(event)">
<div>bbbbbb<div>cccccc<p>Hellooo</p></div></div>
This seems to work, clicking ccccc returns "cccccc", and so on. Or did I completely miss the point?
EDIT: You also need to check if the element has any child elements before substringing it...
finally,I use offset to check which text node is clicked as below:
if ($.browser.mozilla) {
el = event.originalEvent.explicitOriginalTarget;
}else{
var parent =event.srcElement;
var left = event.pageX;
var top = event.pageY;
var offset=$(parent).offset();
for(var i=0;i<parent.childNodes.length;i++){
var n = parent.childNodes[i];
if ( n.nodeType == 1 ){
if($(n).offset().top>offset.top){
if($(n).offset().top>top){
el=parent.childNodes[i-1];
break;
}
}else if($(n).offset().top+$(n).height()>offset.top){
if($(n).offset().left>left){
el=parent.childNodes[i-1];
break;
}
}
}
el=n;
}
}