PreParse Documentation
Sections
What is PreParse?

PreParse is a library designed to simplify web development. It does this by running javascript and css through a preprocessor, which will rewrite standards compliant style rules to work in any browser, and extend and standardise javascript, resulting in faster load times, and quicker execution.

Back to Menu

Basic Info

To use PreParse all that is strictly necessary is this line in the <head> of your html page:

<script type="text/javascript" src="pp_ss/preparse.php?script"></script>

This will automatically run any css through the preprocessor, however PreParse does not work on inline css:

<div style="rule:value;"></div>

It only works on css from linked style sheets, or inside <style> tags. This is not likely to change.

This will also give you access to the PreParse javascript object, however it will not run any javascript through the preprocessor. To have javascript parsed you will need a small amount of javascript after the above mentioned line to tell PreParse what to do:

<script type="text/javascript">
	/*
	 * (optional) path to the pp_js and pp_ss directories
	 */
	pp.path = '/preparse';
	/*
	 * scripts you wish to have included on the page
	 * the path is relative to the SCRIPT_PATH_PREFIX constant in
	 * pp_ss/preparse.php
	 *
	 * can either be a single function call, with each script as an
	 * argument
	 */
	pp.require('myscript.js','myscript2.js');
	/*
	 * or one function call per script
	 */
	pp.require('myscript.js');
	pp.require('myscript2.js');
</script>

To have inline scripting parsed, don't use script tags. Instead use the following:

	<section class="preparse_script">
<!--
/* place any scripting here */
-->
	</section>

It must be a <section> tag, and must have preparse_script as it's only class name. The html comments aren't necessary, but are recommended for hiding script from view. You can style the element however you like, although display:none; will probably be all you really want to do.

Back to Menu

What Gets Parsed

In css the following elements get modified:

For Javascript, please see the Javascript section of this document.

Both style and scripting will be minified before sending to the client.

Back to Menu

CSS

As seen above in What Gets Parsed? CSS will get updated without you having to do anything. Just write your standards compliant CSS, and let PreParse worry about browsers doing weird things. Additional css parsing will be added in time, however this will be to improve cross-browser support, rather than adding obtrusive code to your stylesheets

Back to Menu

Javascript

While PreParse is passive in it's css functionality, it is not when it comes to javascript. While it will work on ordinary javascript, this will effectively just result in the script being minimised, and will miss out on the advanced features and extensions that PreParse adds to the javascipt language, such as:

Why does PreParse modify javascript so much? PreParse is designed to improve the speed of javascript, both in loading, and in execution. It does this not only by minifying the script before outputting it, but by removing blocks of code that will not be used by the client's browser.

Back to Menu

Javascript Preprocessor Directives

Preprocessor Directives allow us to modify the code before it gets to the browser. It's probably easier to see it in action than to describe, so let's jump straight into it and do something relatively simple:

We'll just pop up an alert box when a user clicks on a page, and tell them the position of the mouse. In regular javascript that would look something like this:

document.body.onclick = function(e) {
	if (!e) var e = window.event;
	alert(e.clientX+':'+e.clientY);
}

All very simple really, you check to see if e is defined and if not, then define it using the global event object. This will be common fare to most coders out there.

But, that's an extra line of code, and an extra instruction, which most browsers won't need. So why is it there? Cross-browser compatibility of course, but wouldn't it be better if you could remove that line completely if it's not needed? After all most browsers don't require it, but they still have the extra overhead of downloading a few extra bytes of code (and those bytes will add up in a long script), and parsing an instruction that's not needed. We can speed things up by removing that line, but then the code won't work in older browsers.

This is where PreParse's preprocessor directives are handy, the above code can now look like this:

document.body.onclick = function(e) {
#ifndef localevent
	var e = window.event;
#endif
	alert(e.clientX+':'+e.clientY);
}

At first glance this looks like more code than the first example, but when the code is sent to the browser it will be less, and that's what counts right? Smaller code means faster loading, and less instructions means faster execution.

So when PreParse sees this code it will compare the directive against what the browser is capable of, in this case:

#ifndef means 'if not defined' or "does the browser not have support for"

The definition to check against is 'localevent' or local event objects in functions

This is the same as 'if (!e)' in the regular javascript example, but the check is performed before sending the code to the browser

If this evaluates to true "the browser does not support local event objects" then the code between the directives will be included and sent to the browser, otherwise, the code will not be sent to the browser

So if a browser supports local event objects, the code will look like this:

document.body.onclick = function(e) {
	alert(e.clientX+':'+e.clientY);
}

And if the browser does not support local event objects, the code will look like this:

document.body.onclick = function(e) {
	var e = window.event;
	alert(e.clientX+':'+e.clientY);
}

In both cases, this is less code sent to the browser, and less instuctions to execute, resulting in faster load times for any browser, whether it has support for local event objects or not.

Get the idea? Preprocessor Directives allow code to be modified to suit the browser, before sending it to the client.

At present the available directives are:

You can of course nest directives, you might want to check if ajax is supported, then check if xmlHttpRequest or ActiveX should be used:

#ifdef ajax
#ifdef xmlhttp
	var xr = new xmlHttpRequest();
#endif
#ifndef xmlhttp
#ifdef activex
#ifdef msxml2
	var xr = new ActiveXObject("Msxml2.XMLHTTP");
#endif
#ifdef microsoftxml
	var xr = new ActiveXObject("Microsoft.XMLHTTP");
#endif
#endif
#endif
#endif

Worked that out yet? Here's some pseudo code that might help explain it:

if (browser supports ajax) {
	if (browser supports xmlhttp) {
		var xr = new xmlHttpRequest();
	}
	if (browser doesn't support xmlhttp) {
		if (browser supports activex) {
			if (browser supports msxml2) {
				var xr = new ActiveXObject("Msxml2.XMLHTTP");
			}
			if (browser supports microsoftxml) {
				var xr = new ActiveXObject("Microsoft.XMLHTTP");
			}
		}
	}
}

This is a pretty heavily nested example, but if you've tried coding ajax from scratch, you'll know it's incredibly usefull! In addition to nesting though, you can also test for multiple things at once by seperating tags with a comma:

#ifdef cookie,domid
	alert('This browser supports cookies and getElementById!');
#endif
#ifndef docall,domtag
	alert('This browser supports neither document.all nor getElementsByTagName!')
#endif

The directive will only be true if all tags are defined (or not defined for ifndef), so if cookie is defined, but domid is not, the first alert won't show.

Back to Menu

Javascript Class Extensions

Javascipt objects and classes are a common stumbling block, even the most experienced coder can get lost in trying to do things which are common in other languages. To start with there are 3 ways to create an object, either by declaring objects directly, or declaring a constructor function and instantiating a new object:

Examples of javascript object declaration:

var myObject = new Object();
myObject.text = 'blah';

var myObject = {
	text : 'blah'
}

Example of javascript object created using a constructor function

var myObjectConstructor = function() {
	this.text = 'blah';
	return this;
}
var myObject = new myObjectConstructor();

All 3 of the above result in the same thing, an object called myObject with a public variable accessable from myObject.text - they all work, but only the last method allows for private variables and functions. In all cases extending a function becomes messy, there are ways to do it, and if you look around on the net you'll find plenty of blog posts on the subject.

With PreParse, you can still use the above methods if you wish, but you also now have access to a more understandable (and common) method of defining a class:

Class myClass {
	public var text = 'blah';
}

And instantiate an object from the class in the usual way:

var myObject = new myClass();

This should make a lot more sense to coders familiar with other languages, you declare a class, and give it public and private functions and variables:

Class myClass {
	private var secret = 0;
	public var notSecret = 1;

	private function myFunc() {
		return secret+self.notSecret;
	}

	public function getTotal() {
		return myFunc();
	}
}

If you instantiate the above class as myObject you can call myObject.getTotal() and read/write from/to myObject.notSecret, but secret and myFunc are inaccessable: myObject.myFunc() will throw an error saying that it is undefined. Just as it should be. As can be seen above, a function inside a class can call and access private functions and variables.

Also note that you can have a private and public function with the same name, they will remain seperate functions, therefore this is perfectly valid:

Class myClass {
	private var secret = 0;
	public var notSecret = 1;

	private function myFunc() {
		return secret+self.notSecret;
	}

	public function myFunc() {
		return myFunc();
	}
}

PreParse also adds support for constructors and deconstructors:

Class myClass {
	public function __construct() {
	}

	public function __destruct() {
	}
}

The constructor will be called when you instantiate an object from the class. The deconstructor will be called when you delete an object.

var myObject = new myClass(); // creates an object and calls the constructor
delete myObject; // calls the deconstructor then deletes the object

You can of course use arguments in the constructor:

Class myClass {
	public function __construct(name,type) {
	}

	public function __destruct() {
	}
}
/*
 * create an object, and call the constructor with the supplied arguments
 */
var myObject = new myClass('cola','beverage');

Deconstructors do not accept any arguments, as they are called automatically when deleting the object, therefore there's no way to pass the arguments in.

Another feature added by PreParse is extending classes, which allows:

Class myClass {
	public function hello() {
		alert('hello');
	}
}

Class myNewClass Extends myClass {
	public function helloWorld() {
		alert('hello world');
	}
}

var myObject = new myNewClass();
myObject.hello();
myObject.helloWorld();

This gives myNewClass all of the public variables and functions of myClass, as well as any public or private variables defined within itself. Note however that private functions and variables are not inherited by the new class, this is a problem with the underlying javascript object system we hope to resolve in the future.

Back to Menu

Javascript Strings

Need to include a really long string in Javascript? Including newlines, and other special characters? Try this:

var text = <<<EOT
Put any text you want in here, javascript will see it as one string, regardless of what characters you use.

Including newlines/linebreaks...
	and tabs.
EOT;

The string will start after the newline trailing <<<EOT, and end before the newline that preceeds EOT;. Don't put anything (including tabs) before that last EOT, or you'll have problems!

Back to Menu

Inserting Server-Side code in Javascript

There are times when including the output of a function from serverside language in Javascript is useful, that's where PHP() can be used.

var text = 'PHP(myfunction,arg1,arg2,arg3)';

The above will replace PHP(myfunction,arg1,arg2,arg3) with the output of myfunction(arg1,arg2,arg3) from PHP.

Back to Menu

Javascript Extras

Because it's just so useful, PreParse will ensure that document.querySelector() and document.querySelectorAll() works in all browsers, this lets you use css selectors to find elements within the DOM tree.

Back to Menu

Other (non javascript/css) PreParse Items

Other things not directly related to javascript and css that PreParse can do are:

Let you know if html5's <canvas> tag is supported. While not technically a javascript issue, you can use this to exclude canvas related scripting from browsers that don't support it.

#ifdef canvas
	// canvas code here
#endif
#ifndef canvas
	// maybe some script to replace the canvas with a static image?
#endif

Let you know if Java is supported: I'm sure you can work out what to do with this.

Back to Menu

List of PreParse Tags
NAMEMEANING
BROWSERS
khtmlbrowser is most likely khtml based
mozillabrowser is most likely mozilla based
msiebrowser is most likely Microsoft Internet Explorer
operabrowser is most likely opera
webkitbrowser is most likely webkit based
CSS
opacitybrowser supports css opacity
filterbrowser supports filter
border-radiusbrowser supports css border-radius and derivatives
moz-border-radiusbrowser supports -moz-border-radius and derivatives
webkit-border-radiusbrowser supports -webkit-border-radius and derivatives
text-shadowbrowser supports css text-shadow
max-widthbrowser supports css max-width
min-widthbrowser supports css min-width
min-heightbrowser supports css min-height
max-heightbrowser supports css max-height
khtml-opacitybrowser supports -khtml-opacity
JAVASCRIPT
activeXbrowser supports ActiveX
ajaxbrowser supports ajax with either xmlHttpRequest or ActiveX
array-concatbrowser supports Array.concat
array-copybrowser supports Array.copy
array-eachbrowser supports Array.forEach
array-indexbrowser supports Array.indexOf
array-insertbrowser supports Array.insert
array-lastindexbrowser supports Array.lastIndexOf
callglobalevalbrowser supports eval.call(window)
cookiebrowser supports cookies
docallbrowser supports document.all
domchildbrowser supports DOM childNodes
domclassbrowser supports getElementsByClassName
domcreatebrowser supports document.createElement
domidbrowser supports getElementById
domnamebrowser supports getElementsByName
domselbrowser supports querySelector
domselallbrowser supports querySelectorAll
domtagbrowser supports getElementsByTagName
execbrowser supports window.execScript
globalevalbrowser supports window.eval
iframe-contentdocumentbrowser uses contentDocument to access an iframe's content
innerhtmlbrowser supports innerHTML access to element contents
localeventbrowser supports local event objects in functions
microsoftxmlbrowser supports the Microsoft.XMLHTTP ActiveX object for xmlHttpRequests
msxml2browser supports the Msxml2.XMLHTTP ActiveX object for xmlHttpRequests
prototypebrowser supports Object.prototype
string-capitalizebrowser supports String.capitalize
string-countbrowser supports String.count
string-trimbrowser supports String.trim
xmlhttpbrowser supports xmlHttpRequest
OTHER
canvasbrowser supports the canvas element
javabrowser supports java applets

Back to Menu