Helpful Information
 
 
Category: Coding tips & tutorials threads
Segmented Includes/Updates, plus an Ajax-replacement

I. Ajax-includes
Client side Ajax-includes normally use innerHTML or document.write, and have lines like document.write(....responseText), see here (http://www.dynamicdrive.com/dynamicindex17/ajaxincludes.htm) or document.getElementById('some_id').innerHTML = ....responseText, see here (http://www.dynamicdrive.com/dynamicindex17/ajaxcontent.htm). But the use of a string (responseText) for representing not just text, but also code, is bad practice, see common code errors (http://www.dynamicdrive.com/forums/showthread.php?t=35911) and document.write issues (http://www.dynamicdrive.com/forums/blog.php?b=29), and it explains why the DynamicDriveAnylink Css Menu (http://www.dynamicdrive.com/dynamicindex1/anylinkcss.htm) cannot be included with Ajax in any 'normal Ajax way' (it won't work in IE; try for yourself).

To be honest: it's not Ajax itself wich is at fault, because it does not force us indeed to use responseText as a string containing code. Nevertheless, Ajax 'invites' us, so to say, to incorrectly use responseText, since it is so easy to include a whole file by just associating, for instance, the innerHTML of a div or another part of the text with responseText. But the right way of doing Ajax-includes, or any include, is to keep code out of strings.

Suppose we have a standalone list menu called standalone-list-menu.html that we want to include in a page:
standalone-list-menu.html: ...<head> js and css for the list menu </head> <body> listmenu </body> </html>
We should only use Ajax for including the text part, which is the list menu itself (part in green; for reasons of simplicity, I assume that there are no scripts in that part). We should not use Ajax for (also) including the code (part in red). As a consequence, if we want to have standalone-list-menu.html on every page of a site, we should:

- create a file containing the body part of standalone-list-menu.html; let's call it list-menu-bodypart.html;
- for each page P in which we want to include list-menu-bodypart.html we should:
--put the head-part of standalone-list-menu.html in the head of P (Ajax-include: no!);
--use Ajax to include list-menu-bodypart.html in P (Ajax-include: yes).
- throw away standalone-list-menu.html: we won't need it anymore (or we'll keep it in a vault somewhere: we may want to reuse it).

Each page of our site will now contain the menu we took from standalone-list-menu.html (i), the responseText-string will only contain text, not code (ii), which will not prevent the menu from functioning properly, since in the head of each page we have the js and css that has been taken from the head of standalone-list-menu.html (iii).
Including external content in a page has now become a segmented include technique, since we include different segments of an external page.

II. An Ajax-replacement
But everything isn't right yet. Suppose we want to dynamically change certain things in our included menu, and also assume that those changes cannot be handled by the css and/or js that we imported from standalone-list-menu.html. Then we have a big problem, because what is left from our original list menu isn't html-text anymore: it's just a string (responseText). In other words, (client side) Ajax-includes have the bad property of producing something that is inaccessible 'afterwards'. That is why I propose another method for segmented includes. We can do it with the following script, which should be put at the top of the head section of the encompassing page:


<script type="text/javascript">
if(window.opera || navigator.userAgent.toLowerCase().indexOf('chrome')>-1)
{document.write('<iframe src="list-menu-bodypart.html" width="0" height="0" name="menu" id="menu" style="display:none"><\/iframe>');}
else document.write('<object type="text/html" data="list-menu-bodypart.html" width="0" height="0" name="menu" id="menu" style="display:none"><\/object>');
function extractMenu(){
if(/*@cc_on!@*/false){
document.getElementById('some_id').innerHTML=window.frames['menu'].documentElement.innerHTML;
//this is also possible: document.getElementById('some_id').innerHTML=document.getElementById('menu').object.documentElement.innerHTML;
}
else
{document.getElementById('some_id').innerHTML=window.frames.menu.window.document.documentElement.innerHTML;}
}

/* Instead of the onload, you could use an onclick. Transform the last line of the script into a comment, and make a link like this: <a href="javascript:void()" onclick="extractMenu()">open menu</a> */
window.onload=extractMenu;
</script>

In this script, window.frames['menu'].documentElement.innerHTML and window.frames.menu.window.document.documentElement.innerHTML are the equivalents of the responseText of an Ajax-script. Now, we can easily access any part of the string associated with window.frames['menu'].documentElement.innerHTML (IE) and window.frames.menu.window.document.documentElement.innerHTML (non-IE), since the iframe / object in the script remains just there, and can be accessed.

Using the segmented include technique for including a standalone menu (standalone-list-menu.html) now implies the following:
- create a file containing the body part of standalone-list-menu.html; let's call it list-menu-bodypart.html;
- for each page P in which we want to include list-menu-bodypart.html:
-- put the head-part of standalone-list-menu.html in the head of P;
-- use the script given above to include list-menu-bodypart.html in P.
- throw away etc.

In other words:
Head of page P:

<head>

<script type="text/javascript">
if(window.opera || navigator.userAgent.toLowerCase().indexOf('chrome')>-1)
{document.write('<iframe src="list-menu-bodypart.html" width="0" height="0" name="menu" id="menu" style="display:none"><\/iframe>');}
else document.write('<object type="text/html" data="list-menu-bodypart.html" width="0" height="0" name="menu" id="menu" style="display:none"><\/object>');
function extractMenu(){etc. see above
...
</script>

JS and CSS contained in the head of the original standalone-list-menu.html.

</head>

III. Particular cases
a. The original standalone-list-menu.html has a script in the body for making the menu work:
If that's the case, then in page P we put that script at the very end of the head section, or in the body.

b. The original standalone-list-menu.html has a script in the head with one or more init functions for making the menu work:
We do not only have that script in the head of page P, but we also put the lines of that script (= everything between the script tags) just before the closing curly bracket ('}') of function extractMenu().

IV. Updates
We can do updates just like includes, except for the fact that (i) we don't use 'onload' but 'onclick', for instance, see the comment just before the last line of the script given in II; (ii) we use variables for the url-to-be-loaded and the output-id. Something like this (replacing the include script given above; we have to create a dummy blank.html to make it work):
<script type="text/javascript">
if(window.opera || navigator.userAgent.toLowerCase().indexOf('chrome')>-1)
{document.write('<iframe src="blank.html" width="0" height="0" name="some_external" id="some_external" style="display:none"><\/iframe>');}
else document.write('<object type="text/html" data="blank.html" width="0" height="0" name="some_external" id="some_external" style="display:none"><\/object>');
function bring_in(url,id){
if(/*@cc_on!@*/false){
window.frames['some_external'].location.replace(url);
// or: document.getElementById('some_external').location.replace(url);
document.getElementById(id).innerHTML=window.frames['some_external'].documentElement.innerHTML;
//this is also possible: document.getElementById(id).innerHTML=document.getElementById('some_external').object.documentElement.innerHTML;
}
else
{
window.frames.some_external.window.location.replace(url);
document.getElementById(id).innerHTML=window.frames.some_external.window.document.documentElement.innerHTML;}
}
</script>
Usage: <a href="javascript:void(0)" onmousedown="bring_in('bla.html', 'some_id')" onmouseup="bring_in('bla.html','some_id')">import external</a>

Note that, here again, we have to use the segmented include method. So if bla.html contains code, it must be brought in separately, according to what has been said above about the matter.
Demos HERE (http://www.let.rug.nl/molendyk/include_segmented/any_include/includer_any.html), HERE (http://www.let.rug.nl/molendyk/include_segmented/smooth_include/includer_smooth.html) and HERE (http://www.let.rug.nl/molendyk/include_segmented/twinhelix_include/includer_twinhelix.html).
===
Arie Molendijk










privacy (GDPR)