Home

TypewriterMack Pexton

Introduction

The Typewriter object provides a type() method which "types" the text onto a web page. The millisecond pauses before and after each character typed can be specified in a timing array to make the typing appear more natural. When the typing is complete, a function you specify can be executed or the browser can be redirected to another url.

This version does not use any other outside JavaScript libraries or frameworks. There is another version of this program thats intended to be used as a jQuery addon named typeThis.

Demo

You can test the typewriter function by entering your html text into the input box below and pressing the "Type It" button.

Script

<script>
/**
 * Typewriter style output to screen.
 *
 * Usage:
 * 	var t = new Typewriter(element);
 *	t.type(string,ondone);
 *
 * Parameters:
 * 	string -- HTML string to output
 * 	ondone -- function to execute when typing is done
 *	       or URL to redirect the browser to when done
 *
 * Version 2.1
 * Copyright 2004,2010, Mack Pexton, mackpexton.com
 * License http://www.opensource.org/licenses/mit-license.php
 */

(function(){

var typewriter = function(e) {
	this.e = (typeof e == 'string') ? document.getElementById(e) : e;	// element where typing goes
	this.is_done = false;		// flag set when done typing
}

typewriter.prototype = {
	timing: [	// milli-second pauses before and after characters
			//regexp,   before  after
			[ /[\w,:]/,   50,    50 ],	// regular characters
			[ /&.{2,7};/, 50,    50 ],	// html entities
			[ / /,        50,   300 ],	// space character (pause between words)
			[ /\W/,      750,    50 ],	// punctuation
			[ /./,        50,    50 ]	// everything else
		],
	ondone_pause: 1500,		// pause before invoking function/url when done

	type: function(str,ondone) {
		var sarr = str.split(''),	// make array of individual characters
		    index = 0,			// initialize counter
		    scurr = this.e.innerHTML,	// initialize displayed string
		    beforeChar=1, afterChar=2, state=afterChar,
		    timing = this.timing,
		    pause = this.ondone_pause,
		    t = this,
		    html_tags = function() {
			// return html tags
			var i = index, l = sarr.length,
			    c, s = '',
			    j, lookahead;
			TAG:while (i < l) {
				c = sarr[i];
				if (c != '<') break;

				// Look for tag closing bracket.
				lookahead = c;
				for (j=i+1; j<l; j++) {
					lookahead += sarr[j];
					if (sarr[j] == '>') {
						s += lookahead;
						i = j + 1;
						continue TAG;
					}
				}
				// End bracket of tag not found.
				break;
			}
			index = i;	// readjust global index to sarr array
			return s;
		    },
		    typer = function() {
			var i, l, c, s;

			if (state == beforeChar) {
				state = afterChar;	// next state

				// Search timing array for time to wait before displaying next character.
				c = sarr[index-1];
				for (i=0,l=timing.length; i<l; i++) {
					if (timing[i][0].test(c)) {
						setTimeout(arguments.callee,timing[i][1]);
						return;
					}
				}

				// Should not be here if timing array properly defined. 
				setTimeout(arguments.callee,50);
				return;
			}

			// Add any following html tags to current output.
			scurr += html_tags();

			// Display current output string.
			t.e.innerHTML = scurr + '_';

			if (index < sarr.length) {

				// Process next character.
				c = sarr[index++];
				if (c == '&') {
					// Gather HTML entity
					s = c;
					for (i=index,l=Math.floor(index+7,sarr.length); i<=l; i++) {
						s += sarr[i];
						// Look for entity closing character.
						if (sarr[i] == ';') {
							scurr += s;
							index = i+1;
							c = sarr[index++];
							break;
						}
					}
					// Entity closing semi-colon not found, just output '&'.
					scurr += c;
				}
				else {
					scurr += c;
				}

				state = beforeChar;	// next state

				// Search timing array for time to wait till after displaying next character.
				for (i=0,l=timing.length; i<l; i++) {
					if (timing[i][0].test(c)) {
						setTimeout(arguments.callee,timing[i][2]);
						return;
					}
				}

				// Should not be here if timing array properly defined. 
				setTimeout(arguments.callee,50);
				return;
			}
			else {
				t.is_done = true;
				t.e.innerHTML = scurr+' ';	// remove typing cursor _

				if (ondone) {
					if (typeof ondone == 'function') setTimeout(ondone,pause);
					if (typeof ondone == 'string')   setTimeout('location.href="'+ondone+'"', pause);
				}

				return;
			}
		};
		typer();	// start typing
	},
}

// Expose
this.Typewriter = typewriter;

})();
</script>

Minified Script

The following is the above script minified using the YUI Compressor 2.4.4 made available at http://refresh-sf.com/yui/. It reduces the script size to be only 1185 characters.

<script>
(function(){var a=function(b){this.e=(typeof b=="string")?document.getElementById(b):b;this.is_done=false};a.prototype={timing:[[/[\w,:]/,50,50],[/&.{2,7};/,50,50],[/ /,50,300],[/\W/,750,50],[/./,50,50]],ondone_pause:1500,type:function(j,k){var f=j.split(""),g=0,n=this.e.innerHTML,h=1,d=2,c=d,b=this.timing,m=this.ondone_pause,l=this,e=function(){var q=g,o=f.length,u,r="",p,t;TAG:while(q<o){u=f[q];if(u!="<"){break}t=u;for(p=q+1;p<o;p++){t+=f[p];if(f[p]==">"){r+=t;q=p+1;continue TAG}}break}g=q;return r},i=function(){var p,o,r,q;if(c==h){c=d;r=f[g-1];for(p=0,o=b.length;p<o;p++){if(b[p][0].test(r)){setTimeout(arguments.callee,b[p][1]);return}}setTimeout(arguments.callee,50);return}n+=e();l.e.innerHTML=n+"_";if(g<f.length){r=f[g++];if(r=="&"){q=r;for(p=g,o=Math.floor(g+7,f.length);p<=o;p++){q+=f[p];if(f[p]==";"){n+=q;g=p+1;r=f[g++];break}}n+=r}else{n+=r}c=h;for(p=0,o=b.length;p<o;p++){if(b[p][0].test(r)){setTimeout(arguments.callee,b[p][2]);return}}setTimeout(arguments.callee,50);return}else{l.is_done=true;l.e.innerHTML=n+" ";if(k){if(typeof k=="function"){setTimeout(k,m)}if(typeof k=="string"){setTimeout('location.href="'+k+'"',m)}}return}};i()},};this.Typewriter=a})();
</script>

Examples

Example 1

The following is the simplest use of the typewriter program. It types out "This is a test" into the document element with the id of "typewriter_display".

<script>(new Typewriter('typewriter_display').type("This is a test");</script>

Example 2

The next example is just like the one above with the additional functionality of redirecting the browser to the url "http://company.com/target/path" after it is done typing and pausing for 5 seconds. You could have also specified a function to run instead of the url to redirect to.

<script>
var ondone = 'http://company.com/target/path';
var t = new Typewriter('typewriter_display',ondone);
t.ondone_pause = 5000;	// milliseconds
t.type("This is a test");
</script>

Example 3

The following example is the script that runs the first demo above.

<script></script>