Forum Moderators: open

Message Too Old, No Replies

Implementing IE patch to append AJAX XML element?

Script works save for IE, have an answer though no clue how to use it?

         

JAB Creations

7:40 am on Mar 5, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Before I ask my question I'd like to say I've learned a heck of a lot by working on this one project alone. My initial goal was to load XHTML via AJAX and have that XML code added to the DOM so I could interactive with it after everything was said and done. For the most part I've achieved that however it doesn't work in Internet Explorer...and the only possible solution I've sound seems overly hairy. Well apparently it works which is great and all however the author of the article completely failed to mention how to actually implement it in to an existing example. I'm only vaguely familiar with anonymous functions and I think the issue is related to the parameters which he never really explained in the article which is on A List Apart (mods: is it ok to link to an article on that site?)

Well any way another person also gave me a scrap of code to try so I'll post both bits along with my test case.

This is the solution suggested on A List Apart...

/* is this stuff defined? */
if (!document.ELEMENT_NODE) {
document.ELEMENT_NODE = 1;
document.ATTRIBUTE_NODE = 2;
document.TEXT_NODE = 3;
document.CDATA_SECTION_NODE = 4;
document.ENTITY_REFERENCE_NODE = 5;
document.ENTITY_NODE = 6;
document.PROCESSING_INSTRUCTION_NODE = 7;
document.COMMENT_NODE = 8;
document.DOCUMENT_NODE = 9;
document.DOCUMENT_TYPE_NODE = 10;
document.DOCUMENT_FRAGMENT_NODE = 11;
document.NOTATION_NODE = 12;
}

document._importNode = function(node, allChildren) {
/* find the node type to import */
switch (node.nodeType) {
case document.ELEMENT_NODE:
/* create a new element */
var newNode = document.createElement(node.nodeName);
/* does the node have any attributes to add? */
if (node.attributes && node.attributes.length > 0)
/* add all of the attributes */
for (var i = 0, il = node.attributes.length; i < il;)
newNode.setAttribute(node.attributes.nodeName, node.getAttribute(node.attributes[i++].nodeName));
/* are we going after children too, and does the node have any? */
if (allChildren && node.childNodes && node.childNodes.length > 0)
/* recursively get all of the child nodes */
for (var i = 0, il = node.childNodes.length; i < il;)
newNode.appendChild(document._importNode(node.childNodes[i++], allChildren));
return newNode;
break;
case document.TEXT_NODE:
case document.CDATA_SECTION_NODE:
case document.COMMENT_NODE:
return document.createTextNode(node.nodeValue);
break;
}
};

...and this is the solution that someone suggested...

document._fastClone = function(node, allChildren) {
// a1test++;
var newNode = node.cloneNode(false);
if(node.onclick) {
newNode.onclick = node.onclick;
}
if(node.locinfo) {
newNode.locinfo = node.locinfo;
}
if(node.onchange) {
newNode.onchange = node.onchange;
}
if(node.onblur) {
newNode.onblur = node.onblur;
}
if(node.onkeyup) {
newNode.onkeyup = node.onkeyup;
}
if(node.onsubmit) {
newNode.onsubmit = node.onsubmit;
}
/* are we going after children too, and does the node have any? */
if (allChildren && node.childNodes && node.childNodes.length > 0) {
/* recursively get all of the child nodes */
for (var i = 0, il = node.childNodes.length; i < il;) {
newNode.appendChild(document._fastClone(node.childNodes[i++], allChildren));
}
}
return newNode;
};

...the issue being IE doesn't like appendChild from a source loaded via AJAX...I think. Well I'm not sure how to pass what information is needed to this function.

Here is what I have that works perfectly in Firefox, Opera, and Safari...and following at the bottom I'll mention where I tried adding this patch to get IE to work...

This will all correctly work (you will want to get an image and rename it to "malia-fallen_angel.jpg"). This will let you load something via AJAX when you click the button...and then click the spans to change classes and such to test the browser to see if it can see the elements in the DOM.

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>XMLHttpRequest: responseXML Example</title>
<style type="text/css">
body, html {background-color: #456978; color:#dee; font-family: Verdana;}
a:link, a:visited {color:#234; font-family: Verdana;}
a:focus, a:hover, a:active {color:#fff;}
div.test {background-color: #f00;}
img.imgborder {border: #f0f solid 30px;}
img.test {border: #0ff dotted 30px;}
span.test {background-color: #ff0; color: #000;}
</style>
<script language="javascript" type="text/javascript" src="XMLHttpRequest_responseXML.js"></script>
<script type="text/javascript">
//<![CDATA[
function change(id, newClass) {var identity=document.getElementById(id); identity.className=newClass;}

function getElementByIdMXL(the_node,the_id)
{
//get all the tags in the doc
var node_tags = the_node.getElementsByTagName('*');

for (i=0;i<node_tags.length;i++)
{
//is there an id attribute?
if (node_tags[i].hasAttribute('id'))
{
//if there is, test its value
if (node_tags[i].getAttribute('id') == the_id)
{
//and return it if it matches
return node_tags[i];
}
else
{
return '?';
}
}
}
return false;
}

function getElementByIdXML(node,id)
{
//var nodes = node.getElementsByTagName('*');
//var nodes = xmlDoc.getElementsByTagName('*');
var nodes = document.getElementById('ajax_here').getElementsByTagName('*');

for (var i=0;i<nodes.length;i++)
{
if (nodes[i].hasAttribute('id'))
{
if (nodes[i].getAttribute('id') == id)
{
return nodes[i]; //matching id
}
}
}
return false;
}
//]]>
</script>
</head>

<body>

<div style="background:#487987; border:1px solid #112233; margin: auto; padding:10px; width:770px;">

<div id="ajax_here"></div>

<div><a href="javascript:alert(getElementByIdXML('xmlDoc','test_span').getAttribute('title'))">Alert AJAX span element title.</a></div>
<div><a href="javascript:alert(getElementByIdXML('xmlDoc','response').getAttribute('class'))">Alert AJAX span element class.</a></div>
<div><span onclick="getElementByIdXML('xmlDoc','response').className='test';return false;">Change class of 'test_span' to class 'test'.</span></div>
<div><span onclick="change('response','test');" style="color: #ff0; font-size: 22px;">Change class of 'test_span' to class 'test1'.</span></div>
<div><span onclick="change('response','test'); change('img_test','test');" style="color: #ff0; font-size: 22px;">Change class of 'test_span' to class 'test2'.</span></div>

<h3>XMLHttpRequest: &nbsp; responseXML Example</h3>

<div><span style=" font:13px/12pt verdana; letter-spacing:1px">Complete Example demonstrating the use of XML HttpRequest's "responseXML"</span></div>
<div><span style="color:#334455; font:8pt verdana; letter-spacing:1px" >( By Kostas Zotos &nbsp; 8/2008 ) </span></div>

<form>
<textarea name="CellData" id="CellData" style="background:#659aa7; border:1px solid #234; height:110px; margin: 2px auto 2px auto; width: 100%;">
This text will be replaced by the XML sent by PHP...

(Click the button to send some data to PHP..)
</textarea>

<div>
<input type="button" style="background:#659aa7; border:1px solid #234; height:25px; margin: 2px auto 2px auto; width: 100%;" value="Click to send the current Date and Time" onclick="SendData(new Date())" />
</div>
</form>

</div>

</body>
</html>

XMLHttpRequest_responseXML.php

<?php
header('Content-Type: text/xml');
header ('Cache-Control: no-cache');
header ('Cache-Control: no-store' , false); // false => this header not override the previous similar header

//-------------- If want to read an existing .xml file -------------------------

// $XmlFile="Data.xml";

/*// Using the DOM Functions
$doc=new DOMDocument();
$doc->formatOutput=true;

$doc->load($XmlFile);

// echo $doc->saveXML(); // Returns the xml as string
*/

// OR: Directly open the file:
// readfile($XmlFile); // Output directly the given file to browser

//-------------- If want to read an existing .xml file (END) -----------------


if (isset($_GET['Date'])){
$Date=trim($_GET['Date']); // Reads the GET request "Date" variable (removes leading/trailing whitespaces)
$Date=strip_tags($Date); // Removes possible html and php tags (to prevent possible malicious code)
} else {
$Date=@date("l, d F Y ( H:i:s A )");
}

// Manually create a string representation of a new xml document
// Inserting also the GET variable

/*<?xml version="1.0" encoding="UTF-8"?>*/
$xmlStr='<div xmlns="http://www.w3.org/1999/xhtml" id="response">1234
<div>aa<span class="test" id="test_span" title="TITLE TEXT HERE!">bb</span></div>
<div><img alt="test image" class="imgborder" src="malia-fallen_angel.jpg" title="test image" /></div>
<data id="ajax_id1"><Date id="ajax_id2">'.$Date.'</Date><ip>'.$_SERVER['REMOTE_ADDR'].'</ip></data>
</div>
';

echo $xmlStr;
?>

XMLHttpRequest_responseXML.js

<?php header("content-type: application/javascript");?>

var xmlhttp;
function SendData(Arg)
{
xmlhttp=null;
var Url='XMLHttpRequest_responseXML.php';// THE SERVER SCRIPT TO HANDLE THE REQUEST

if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();// For all modern browsers
}
else if (window.ActiveXObject)
{
xmlhttp=new ActiveXObject('Microsoft.XMLHTTP');// For (older) IE
}

if (xmlhttp!=null)
{
xmlhttp.onreadystatechange=onStateChange;
Url=Url+'?Date='+escape(Arg)+'&NoCache='+new Date().getTime();
// '&NoCache' => Append the timestamp to avoid cashing
// Also escape the input argument (Arg) to properly url-encode the characters (to be sure)
xmlhttp.open('GET', Url, true);// (httpMethod, URL, asynchronous)
// xmlhttp.overrideMimeType('text/xml');
xmlhttp.send(null);
/*
// How to send a POST request
xmlhttp.open('POST', Url, true); // (httpMethod, URL, asynchronous)
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
xmlhttp.send( 'Date=' + escape(Arg) );
*/
}
else
{
alert('The XMLHttpRequest not supported');
}
}

function onStateChange()
{
if (xmlhttp.readyState==4)
{
if (xmlhttp.status==200)
{
var xmlDoc=xmlhttp.responseXML;// 'xmlDoc' the returned xml object
var DateNode=xmlDoc.getElementsByTagName('Date')[0].firstChild.nodeValue // The <Date> element's node value (the sent date)
var Xml2String // Convert the xml to string just to display it
if (xmlDoc.xml) {Xml2String=xmlDoc.xml}// Converts the xml object to string ( For IE)
else {Xml2String= new XMLSerializer().serializeToString(xmlDoc);}// Converts the xml object to string (For rest browsers, mozilla, etc)
//alert(Xml2String);
//alert(xmlhttp.responseText);
document.getElementById('CellData').value=Xml2String;
//alert(xmlDoc.getElementsByTagName('div')[0].firstChild.nodeValue);
document.getElementById('ajax_here').appendChild(xmlDoc.getElementsByTagName('div')[0]);
//document.getElementById('ajax_here').appendChild(document.importNode(xmlDoc.getElementsByTagName('div')[0],true));
//document.getElementById('ajax_here').innerHTML = xmlDoc.getElementsByTagName('div')[0];
//alert(xmlDoc.getElementById('response').nodeValue);
}
else
{
//ajax_here
//document.getElementById('ajax_here').appendChild(element_new);
document.getElementById('ajax_here').appendChild(Xml2String);
//alert('statusText: ' + xmlhttp.statusText + '\nHTTP status code: ' + xmlhttp.status);
}// End of: if (xmlhttp.status==200)
}
}

If you count 11 rows from the very end going up in to the file [i]XMLHttpRequest_responseXML.js inside the last if statement is where I tried to append the script by setting a node variable to xmlDoc in example...I'm shooting blind at this point to be honest. I'm not looking for a straight out answer to the problem though...it would be nice but I won't know how to approach a similar situation in the future and at this point I would really appreciate some terminology as far as what is being referenced so I know what I should be looking up to figure out how to get this to play nicely together. Thoughts please? Also Mods: is a link to the article in compliance with the forum TOS?

- John

JAB Creations

4:09 am on Mar 6, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I was unfamiliar with that style of function and figured out how to call it correctly.

- John

if (document.importNode) {alert('standard'); document.getElementById('ajax_here').appendChild(document.importNode(xmlDoc.getElementsByTagName('div')[0],true));}
else {alert('ie'); document.getElementById('ajax_here').appendChild(document._importNode(xmlDoc.getElementsByTagName('div')[0],true));}