"apex" JavaScript library

Published:
Updated:
I developed my own JavaScript library I call "apex". It is no better or worse than any other library; it is simply tailored to fit my needs.

In developing this library, I borrowed heavily from both Douglas Crockford and Daniel Brockman. Without their insight into JavaScript, my library would never have seen the light of day. I owe both these men a deep debt of gratitude.

That being said, neither Douglas Crockford nor Daniel Brockman are in any way responsible for the code that follows. If you decide to use any or all of the code, you alone bear the burden of responsibility. It is provided "as is" with no warranty or guarantee.


In this article, I will discuss the core functions of "apex". I will discuss the add-in modules in other articles when time permits.

The code is shown in sections, and a discussion follows.

Note: the "" tags at the beginning of each code snippet are artifacts from the article creation process provided by Experts-Exchange; they are not part of my article nor my code.
 

1. Declaration


"apex" begins with a header block, followed by a few functions and declarations:
 
/*
                       ######################################
                       apex.js
                       Universal properties and methods
                       
                       Components
                       ==========
                       .core		Core services
                       .ajax		AJAX methods
                       .event		Event management
                       .json		JSON "to_string" and "to_object"
                       .string	LTrim, RTrim, Trim, Pad, Chop
                       
                       ######################################
                       */
                      
                      // If the "apex" namespace does not exist, create it
                      if (typeof apex === 'undefined') { var apex = {}; }
                      
                      // Create true array from pseudo-array (like "arguments")
                      function to_array(imposter) {
                      	var ra = []; 
                      	for(var i = 0; i < imposter.length; i++) {
                      		ra.push(imposter[i]);
                      	}
                      	return ra;
                      }
                      
                      // Create namespace within "apex"
                      apex.namespace = function() {
                      	var a = to_array(arguments);
                      	var o = null;
                      	
                      	for (var i = 0; i < a.length; i++) {
                      		var d = a[i].split(".");
                      		o = apex;
                      		
                      		for (var j = (d[0] === 'apex') ? 1 : 0; j < d.length; j++) {
                      			o[d[j]] = o[d[j]] || {};
                      			o = o[d[j]];
                      		}
                      	}
                      	return o;
                      };
                      
                      // Known namespaces
                      apex.namespace('core','ajax','event','json','string');

Open in new window

The function "to_array" returns a true Array object from a pseudo array such as the "arguments" collection that is available to every function. Declaring it at the top of the code makes it available to all of the functions in the library.

"apex.namespace" adds a handle for a new add-in.

2. Event Handling


Next we need a way to handle events. I use Daniel Brockman's method, available from the link in the comment block.
 
/*
                       ######################################
                       OO Event Listening through Partial 
                       Application in JavaScript, from
                       http://www.brockman.se/writing/method-references.html.utf8
                       ######################################
                      */
                      (function () {
                      	var destructor = {};
                      	
                      	Function.prototype.bind = function(object) {
                      		var method = this;
                      		var oldArguments = to_array(arguments).slice(1);
                      		
                      		return function(argument) {
                      			if (argument === destructor) {
                      				method = null;
                      				oldArguments = null;
                      			}
                      			else if (method === null) {
                      				throw 'Attempt to invoke destructed method reference';
                      			}
                      			else {
                      				var newArguments = to_array(arguments);
                      				return method.apply(object, oldArguments.concat(newArguments));
                      			}
                      		};
                      	};
                      	
                      	Function.prototype.bindEventListener = function(object) {
                      	    var method = this;
                      	    var oldArguments = to_array(arguments).slice(1);
                      	    return function(event) { 
                      			return method.apply(object, [event || window.event].concat(oldArguments)); 
                      		};
                      	};
                      })();

Open in new window

This function is added to the prototype chain for Function. It allows us to bind a method to an object. It also lets us bind an event handler to an object. It provides a way to un-bind a method by passing in a new Object ("{}"). Finally, it lets us curry a function, that is, to pass a partial list of parameters to a function.

Visit http://www.brockman.se/writing/method-references.html.utf8 for a much more thorough explanation of the inner workings of this code.

3. Core Properties and Methods


Next we have the "core" portion of apex.
 
// ####################################
                      
                      apex.core = function() { 
                      	var site = 'over-engineering';
                      	var PURL = document.location.href;
                      	var URL_BASE = 'http://' + (PURL.indexOf('www.') > 0 ? 'www.' + site + '.com/' : 'localhost/' + site) + '/';
                      	var URL_BROKER = URL_BASE + 'apex/';
                      	var URL_FULL = URL_BASE;
                      	
                      	function enclude(file_name, loaded) {
                      		// File prefix and suffix
                      		var pfx = '<script type="text/javascript" src="' + URL_BROKER;
                      		var sfx = '"><\/script>';
                      		
                      		// Include the file(s)
                      		for (var i = 0; i < file_name.length; i++) {
                      			if (!loaded) {
                      				document.write(pfx + file_name[i] + sfx);
                      			}
                      			else {
                      				var elem = document.createElement('script');
                      				elem.src = pfx + file_name[i] + sfx;
                      				document.body.appendChild(elem);
                      			}
                      		}
                      	}
                      	
                      	function get_node_type(name) { 
                      		var node_name = { 
                      			'ELEMENT'				:'1', 
                      			'ATTRIBUTE'				:'2', 
                      			'TEXT'					:'3', 
                      			'CDATA_SECTION'			:'4', 
                      			'ENTITY_REFERENCE'		:'5', 
                      			'ENTITY'				:'6', 
                      			'PROCESSING_INSTRUCTION':'7', 
                      			'COMMENT'				:'8', 
                      			'DOCUMENT'				:'9', 
                      			'DOCUMENT_TYPE'			:'10', 
                      			'DOCUMENT_FRAGMENT'		:'11', 
                      			'NOTATION'				:'12'
                      		};
                      		return node_name[name.toUpperCase()];
                      	}
                      	
                      	function get_node_name(type) { 
                      		var node_type = { 
                      			'1'	:'ELEMENT', 
                      			'2'	:'ATTRIBUTE', 
                      			'3'	:'TEXT', 
                      			'4'	:'CDATA_SECTION', 
                      			'5'	:'ENTITY_REFERENCE', 
                      			'6'	:'ENTITY', 
                      			'7'	:'PROCESSING_INSTRUCTION', 
                      			'8'	:'COMMENT', 
                      			'9'	:'DOCUMENT', 
                      			'10':'DOCUMENT_TYPE', 
                      			'11':'DOCUMENT_FRAGMENT', 
                      			'12':'NOTATION'
                      		};
                      		return node_type[type];
                      	}
                      	
                      	function get_broker_control() { 
                      		return function(){
                      			return {
                      				'async'				:false, 
                      				'broker_url'		:URL_BROKER,
                      				'broker_dir'		:'apex/', 
                      				'broker_name'		:'xs_sys.asp',
                      				'callback_method'	:null, 
                      				'callback_parms'	:null,
                      				'proc_name'			:'', 
                      				'notify_window'		:null, 
                      				'alert_interval'	:1000, 
                      				'content_type'		:'application/x-www-form-urlencoded', 
                      				'header'			:[],
                      				'mode'				:'' /* Set to 'plain_text' for non-JSON requests */
                      			};
                      		}();
                      	}
                      	
                      	function get_elements_by_className(arg) {
                      		// Expects
                      		//
                      		// arg.node		Location of the elements (default is "document)
                      		// arg.tag =	Tagname (default is "*")
                      		//
                      		// Returns
                      		// arg.result	Array of objects
                      		
                      		arg.node = arg.node || document;
                      		arg.tag = arg.tag || '*';
                      		arg.result = [];
                      		//
                      		var el = arg.node.getElementsByTagName(arg.tag);
                      		var pattern = new RegExp('(^|\\s)' + arg.clas + '(\\s|$)');
                      		//
                      		for (var i = 0; i < el.length; i++) { 
                      			if (pattern.test(el[i].className)) { 
                      				arg.result.push({'type':el[i].tagName, 'id':el[i].id}); 
                      			} 
                      		}
                      		return arg;
                      	}
                      	
                      	function tcelfer(obj) {
                      		// Expects
                      		//
                      		// obj		JSON object
                      		
                      		obj = obj || apex.core;
                      		
                      		var ra = [];
                      		if ((obj.length) || 0 > 0) {
                      			for (var j = 0; j < obj.length; j++) {
                      				ra.push(tcelfer(obj[j]));
                      			}
                      		}
                      		else {
                      			for (var n in obj) {
                      				if (obj.hasOwnProperty(n)) {
                      					ra.push([n, obj[n]]);
                      				}
                      			}
                      		}
                      		return ra;
                      	}

Open in new window

By declaring "apex.core" as a function (or class, if you prefer), we can have private properties and methods and privileged (or public) methods and properties.

4. Private Methods and Properties


The initial declarations set some URL locations.

"enclude" provides us with a way to include external files.

"get_node_type" returns the value of a "nodeName" attribute.

"get_node_name" returns the "nodeName" from a value.

"get_broker_control" returns a JSON object used for Ajax. The default settings are for a Synchronous Ajax call. Changing the "async" property to "true", referencing a Function in "callback_method" and setting the (optional) parameters in "callback_parms" will result in an Asynchronous Ajax call.

"get_elements_by_className" returns an array of JSON objects denoting HTML elements sharing a CSS class name.

"tcelfer" is a rudimentary reflection method. It returns a "name=value" list for any JSON object.

5. Exposed Methods and Properties


These provide access to the private properties and methods.
 
	// Exposed properties and methods
                      	return {
                      		/*
                      		 * ############################
                      		 * Internal methods
                      		 * ----------------------------
                      		 */
                      		'broker_url'	:URL_BROKER,
                      		'region'		:site + '.com',
                      		'region_from_db':false, /* get region from db? */	
                      		
                      		'$'				:function(arg) { return document.getElementById(arg); }, 
                      		'$$'			:function(arg) { return get_elements_by_className(arg); },
                      		'$$$'			:function(tag) { return document.getElementsByTagName(tag); },
                      		
                      		'broker_control':function() { return get_broker_control(); }, 
                      		'enclude'		:function(file_name, mode) { return enclude([file_name], mode); }, /* INCLUDE external file */
                      		'event_control'	:function(cat, ele, eve, han) { return get_event_control(cat, ele, eve, han); }, 
                      		'reflect'		:function(arg) { return tcelfer(arg); },
                      		'error_trap'	:function(desc, url, line) { return trap_error(desc, url, line); },
                      		'node_type'		:function(arg) { return get_node_type(arg); },
                      		'node_name'		:function(arg) { return get_node_name(arg); },
                      		//
                      		'empty'			:null // dummy object closer
                      	};
                      }();

Open in new window

"empty" is an indicator that terminates the exposed methods. Since each exposed method is followed by a comma, "empty" is just a convenience, but it prevents me from forgetting to add a comma if I add a new method.

6. Usage


"apex" is included in a standard
1
5,097 Views

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.