Integration Basics

How DiXon Works

The DiXon compiler parses XHTML pages enhanced with embedded code and custom XML-based markup elements providing client-side presentation logic. The compiler itself is written in XSLT 1.0, but because there is no standard way to perform XSLT transformations from JavaScript code, and some popular browsers either have limited support for this capability or no support at all, the DiXon compiler needs to run on the server. In addition to addressing compatibility issues, this approach improves performance by reducing back-and-forth traffic and by storing compiled pages on the server's hard drive and serving them verbatim until the page is modified.

Loading JavaScript Client Pages

The host application is the Web application or a collection of static pages that uses JavaScript Client Pages to display some of its content ot to respond to certain user actions.

Prerequisites

Before a JavaScript client page can be used from a Web page in the host application, the following requirements need to be met:

  1. DiXon should be available to the Web application
  2. The page should have requested the page from DiXon
  3. DiXon should be able to successfully compile the page.

Before you begin using JavaScript Client Pages, you will need to give your Web application to DiXon. In order to do so, you will need to copy the contents of the DiXon distribution for your platform to your application's Web root.

If you have access to one of the platforms for which DiXon has been released, but your application runs on a different platform, you will sill be able to use it. However, you will then need to install it separately and then make your Web pages point to your DiXon installation when requesting pages.

Including the JSClientPages library

The code generated by DiXon uses some functionality that is not readily available in browsers. All this functionality is implemented in standards-based ECMAScript / JavaScript code with minimal use of non-standard features only for non-essential functionality (e.g. debugging stack traces) and bundled in a JavaScript library called JSClientPages.jsTo include this library, insert the following code in the <head> your Web pages:

<html>
<head>
<title>My Web Application</title>
<script src="JSClientPages.js" type="text/javascript"></script>
</head>
<body>
<!-- My Web Application's content -->
</body>
</html>

Warning:Make sure that the above script tag is not a broken link. If you installed DiXon in a directory other than your Web root, you should adjust the path accordingly. Also, adjustments might need to be made for applications that rely on URL rewriting to map client requests to a single dispatcher, such as Ruby on Rails, the Zend Framework, CakePHP and other "push-MVC" frameworks with a similar architecture.

Where Did language="JavaScript" Go?

In modern Web standards, the language attribute is neither required nor considered valid, since browsers can determine the language being used from the content type defined in the type attribute. However, many Web developers still include it because "old habits die hard". Due to the forgiveness of most Web browsers, its inclusion is unlikely to break anything except for validation.

This manual focuses on recent Web standards supported in "6th-generation" and newer browsers.

If you would like to continue using obsolete attributes and elements, you can feel free to do so, but they are beyond the scope of this manual and, thertore, they will not be used in examples regardless of how common they are in practice.

Requesting Pages from the Compiler

By default, JavaScript Client pages reside in the jscp directory in your document root. For a page called ClientPage.xml residing in [web root]/jscp/ClientPage.xml, the following script tag needs to be added:

<html>
<head>
<title>My Web Application</title>
<script src="JSClientPages.js" type="text/javascript"></script>
<script src="JSClientPage.ashx?page1=ClientPage.xml" type="text/javascript"></script>
</head>
<body>
<!-- My Web Application's content -->
</body>
</html>

Loading Multiple Pages

The DiXon compiler has the ability to load multiple JavaScript Client Pages in a single HTTP request. Therefore, if your Web page uses two or more JavaScript Client Pages for its dynamic content, it should include them all at the same time regardless of whether they are always invoked by the page in question.

The general template for a multi-page DiXon request is as follows:

<script src="JScriptClientPage.ashx?page1=Page1.xml&page2=Page2.xml&...&pagen=PageN.xml></script>

Where n is the number of the page wiithin the request.

Platform Adjustments

JSClientPages.ashx is the name of the DiXon invoker for the .NET platform, which was the first platform binding developed for the DiXon-JSClientPages project and is therefore considered to be its reference implementation.

Given below is the name of the DiXon invoker for each platform supported at the time of writing:

Platform Flavor Invoker Name Notes
.NET Microsoft JSClientPage.ashx Both implementations use the same code base. Since the Mono implementation tends to be a few releases behind the one from Microsoft, you should ensure that you are using an up-to-date version of Mono.
.NET Mono JSClientPage.ashx
PHP The PHP Group JSClientPage.php For PHP applications running on UNIX-like platforms, it is recommended to use the PHP implementation.
For "WIMP" systems (PHP on Windows + IIS), the .NET version could be used as well. Systems that use CGI to invoke PHP might obtain better performance if the .NET implementation is used regardless of the platform on which the host application is running.
PHP Phalanger JSClientPage.php
or
JSClientPage.ashx
Unlike the official implementation of the PHP language, Phalanger integrates into the .NET framework and supports both Microsoft .NET and Mono. Therefore, the .NET handler can be used with Phalanger.

Invoking Pages from Target Code

Where to Invoke JavaScript Client Pages

Normally, JavaScript Client Pages are invoked from within event handlers in client-side code that respond to user-triggered events such as:

Choosing a Target

Although a JavaScript Client Page might have a semantic resemblance to a complete XHTML page, in most cases, only a portion of a page appearing in the user's browser at a given time actually needs to be refreshed. In fact, like with most AJAX-type technologies, complete page reloads are very uncommon with DiXon-JSCP.

The target refers to an element within an XHTML document's Document Object Model (DOM) to which DiXon-generated content will be added. Although any element can theoretically be used as a target, most applications will use a block-level element, such as a <div>

Naming the JavaScript Client Page

The name of the JavaScript Client Page used in invocations from client scripts is completely independent from its file system name, which makes it possible to have several versions of the same page with similar logic but different presentation styles.

The name of each page is defined in the <head> section. by means of an XHTML <meta> tag named JSClientPage.

Given below is a sample page name declaration:

<html>
<head>
<title>JSCP - Message Page</title>
<meta name="JSClientPage" Content="Message" />
</head>
<body>
<div class="message">
<h1><js:output value="input.subject" /></h1>
<div class="body">
<js:output value="input.body" />
</div>
</div>
</body>
</html>

Rendering a Page

Rendering a JavaScript Client Page refers to the process of displaying some content using the presentation logic contained in a JavaScript Client Page in a target element.

Additive Rendering

The static render method of the JSClientPages method renders the JavaScript Page specified by the invoker in the target element by appending any elements emitted by the page as new child elements without removing any existing elements. Thus, if the selected target already contains elements, they will not be removed, modified or otherwise "touched".

Common Scenarios:

Rendering a Page

Consider the following HTML page:

<html>
<head>
<title>My Messages</title>
<script type="text/javascript" src="JSClientPages.js"></script> <script type="text/javascript" src="JSClientPages.ashx?page1=Message.xml"></script>
</head>
<body>
<h1>My Messages</h1>
<h2>Add a Message</h2>
<form id="message-form" onsubmit="Message.submit(); return false;" action="SubmitMessage.ashx">
<h3>Subject</h3>
<input id="message-form-subject" type="text" name="subject" width="30" />
<h3>Body</h3>
<textarea id="message-form-body" rows="5" cols="50"></textarea>
<div class="button-panel">
<input type="submit" name="submit" value="Post" />
<input type="reset" name="reset" value="Reset" />
</div>
</form>
<h2>Your Posted Messages</h2>
<div id="posted-messages"></div>
</body>
</html>

This page was designed to enable the user to post a simple message using an asynchronous AJAX request. When the form is submitted, instead of POSTing its contents directly to a server-side handler, the browser will invoke a script function named Message.submit(), which will issue the AJAX request and register a handler that will render the page when the response comes back.

The highlighted <div> tag is just a container to which messages will be added dynamically using JavaScript Client Pages code. It is referred ro as a rendering target.

Given below is a code example showing how a JavaScript Client Page will be rendered, and the final contents will then be added to the posted-messages element.

Message =
{
submit : function()
{
var message =
{
subject: document.getElementById('message-form-subject').value,
body: document.getElementById('message-form-body').value
};
this.send(message);
},
send : function(message) {
var request = new XMLHttpRequest();

var form = document.getElementById('message-form');

var url = form.action; request.onreadystatechange = function(transport) {
if (request.readystate == 4) {
var messageElement =
transport.responseXml.getElementsByTagName('message')[0];
var message = {
subject: messageElement.getElementsByTagName('subject')[0].data,
body: messageElement.getElementsByTagName('body')[0].data
};
Message.render(message);
}
};
},
render : function(message) {
JSClientPage.render(
'Message',
'posted-messages',
message
);
}
}

Warning: The above example was coded to a very recent standard and, therefore, requires IE7 and above, a Gecko browser, Safari 2.x and above or any other browser that exposes the XMLHttpRequest object in the global namespace (i.e. as a property of the window). Earlier versions of Internet Explorer will require an explicit ActiveX instantiation of that object, which is usually provided as a fall-back option in popular JavaScript frameworks and toolkits, such as Prototype and YUI.

If a user submits multiple messages using the message form, all the messages will appear in the posted-messages container one after another.

Replacement Rendering (a.k.a. Refreshing)

Replacement rendering uses the same logic and semantics as additive rendering, except that the contents of the rendering target are removed from the document before the page is render. In order to replace any existing content, the JSClientPages library will call the removeChild() method on the rendering target for all of its child notes and then render the page in an empty target element.

Given below is a list of scenarios where replacement rendering is useful:

Refreshing Containers

Replacement rendering is invoked the same way as additive rendering except that JSClientPage.render needs to be replaced with JSClientPage.refresh.

Best Practices

Client-Side

Consolidate Script Requests
Instead of writing a script element for every page you are planning to include, create one script element for all pages on which your page depends.
<script type="text/javascript src="JSClientPage.ashx?page=Employees.xml"><script>
<script type="text/javascript src="JSClientPage.ashx?page=Resumes.xml"><script>
<script type="text/javascript src="JSClientPage.ashx?page1=Employees.xml&page2=Resumes.xml"><script>
Don't Write Your Main Page in JSCP
DiXon-JSClientPages is a lightweight client-side technology that was designed to render page fragments for information that is either created directly in client-side code or by means of an AJAX request. In most browsers, DOM manipulation takes longer than parsing, and while this difference is negligible for a fragment, it might take a considerable amount of time to render a page with a few megabytes of content using DOM manipulation. Furthermore, JavaScript Client Pages does not provide any of the productivity and security features found in advanced Web development frameworks.
Do Not Use document.write()

Reasons:

  1. In many browsers, if the page is served as application/xml or application/xhtml+xml, document.write() will overwrite the entire page instend of appending to the current context. This is because the page is not guaranteed to stay well-formed after its use.
  2. document.write() will not respect the rendering target, but in some cases, it might work (somewhat) correctly if the code that calls the page happens to be located in the rendering target itself.

Alternatives (in decreasing order of preference)

  1. Text and markup with elements from the js namespace
  2. DOM Assembly Functions
    • startElement()
    • endElement()
    • attribute()
    • text()
  3. The raw() function

Warning: the raw() function makes it possible to programmatically insert raw HTML into a page by creating an empty element and adding custom HTML to it using its innerHTML property.

Because of its popularity, this element is available in all major browsers. However, it is not part of any final W3C recommendation.

Do Not Refresh the Whole Page
While it is acceptable to refresh a small fragment of a page, such as a news feed or a list of items, re-rendering massive amounts of content can cause performance problems on some systems.
Keep the Bulk of JavaScript Code in Separate Files
Not only do large amounts of inline JavaScript difficult to understand, but they also cause problems with special characters if the page is served as text/html or is otherwise interpreted by a multipurpose HTML engine that uses a traditional ("tag soup") parser rather than requiring strict XML compliance. Consider the following examples:

Invalid XHTML

<script type="text/javascript">
for (var i = 0; i < items.count ; i++) { // Invalid because an angle bracket signals the beginning of an element
process(items[i]);
}
</script>

Invalid JavaScript

<script type="text/javascript">
for (var i = 0; i &lt; items.count ; i++) { // The JavaScript engine interprets this as "&lt;" instead of "<"
process(items[i]);
}
</script>

Valid But Uncommon JavaScript and XHTML

While wrapping the script in a CDATA section solves the problem of using characters that have a special meaning in XML, XHTML and SGML, this technique is rather uncommon and, therefore, might cause problems with some JavaScript frameworks like Prototype

<script type="text/javascript">
//<![CDATA[
for (var i = 0; i < items.count ; i++) {
process(items[i]);
}
// ]]>
</script>

Server-Side

Use What's Best For Your Platform

Generally, ports of popular platforms to other systems where they do not have a large user base are inferior to their original versions. For JSClientPages rendering, Unix/Linux users developing PHP applications on Apache should prefer PHP over Mono. Windows Server developing Web applications on the .NET framework should use the .NET bindings even if PHP is available on the server.

Apart from platform stability, is should be noted that all platform bindings will be tested on the platforms where they are used most frequently, and common issues and gotchas will be addressed with solutions posted on the project page. However, unresolved issues may exist on uncommon platform configurations such as PHP on ISAPI or various Unix ports of .NET running on Apache. However, full support for the Mono Project's implementation of the .NET framework is one of the project goals.

If it's Top Secret, Keep It On the Server

Like any other scripting solution, all JavaScript code generated by DiXon is transferred to the client's machine and then interpreted by the browser's scripting engine. The integrity of this process cannot be relied on, since various tools exist that allow even non-technical users to manipulate Web pages directly in the browser.

Common pitfalls include:

  • Trusting input from AJAX calls to leave all server-supplied data intact
  • Embedding authentication tokens in Web pages
  • Generating server-side code from a client page and sending it to the server for execution.
  • Exposing Web services or AJAX-callable routines that allow users to fetch arbitrary content from the database, including content that they are not allowed to access.