Home > JavaScript > Clib – a basic javascript library

Clib – a basic javascript library

December 17, 2009

Notice: This class is subject to change.


/**
* Clib - a basic javascript library
*
* @author     Costin Trifan 
* @copyright  2009 Costin Trifan
* @licence    MIT License http://en.wikipedia.org/wiki/MIT_License
* @version    1.0
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
============================================================*/


/**
 * PROTOTYPES
 *
 * @see $().ajax()
 */
if ( ! Array.prototype.inArray )
{
    Array.prototype.inArray = function ( theArray ) {
	    var i;
	    for (i=0; i < this.length; i++) {
		    if (this[i] === theArray) {
			    return true;
		    }
	    }
	    return false;
    };
}





/**
 * Clib library - Simple Ajax/Dom/Events/Cookie library
 *
 */
(function()
{

/******************************
*       AJAX RELATED
******************************/

    var xhr = null; /*[ will hold the instance of the XmlHttp object ]*/

    var _createRequest = function()
    {
        try { return new XMLHttpRequest ; } catch(e) {}
        try { return new ActiveXObject('MSXML2.XMLHTTP.3.0') ; } catch(e) {}
        try { return new ActiveXObject('MSXML2.XMLHTTP') ; } catch(e) {}
        try { return new ActiveXObject('Microsoft.XMLHTTP') ; } catch(e) { throw new Error("Details: AJAX is not supported!"); }
    };

    /**
     * Create an image loader
     * @return object   the created DOM Element
     */
    var _createImageLoader = function( imgSrc, parentCtl, loadingText )
    {
        var el = document.createElement("img");
        with (el)
        {
            setAttribute("src", imgSrc);
            setAttribute("title", loadingText);
            setAttribute("alt", loadingText);
            style.width = 'auto';
            style.height = 'auto';
            style.display = 'block';
        }
        parentCtl.appendChild(el);
        return el;
    };

/*>> End AJAX related stuff *******************************************************************************/




    /**
     * Populate the this.elements array
     * @access private
     */
    function _$( els )
    {
        this.elements = [];

        for (var i= 0; i < els.length; ++i)
        {
            var e = els[i];
            if (typeof(e) === "string") {
                e = document.getElementById(e);
            }
            this.elements.push(e);
        }

    }

    _$.prototype =
    {

/*==============================
 * UTILITY
==============================*/


        /**
         * Check to see whether the provided object is an array
         * @return bool
         */
        isArray : function ( obj )
        {
           return (obj.constructor.toString().indexOf("Array") >= 0 );
        },


        /**
         * Execute a given function for each of the elements from the this.elements array
         * @return this
         */
        each : function( fn )
        {
            if (this.elements.length == 0) { return this; }

            for (var i= 0; i < this.elements.length; ++i)
            {
                fn.call(this, this.elements[i]);
            }
            return this;
        },



/*==============================
 * COOKIE
==============================*/

        /*[ Source: http://www.dustindiaz.com/top-ten-javascript/ ]*/
        getCookie : function( name )
        {
	        var start = document.cookie.indexOf( name + "=" );
	        var len = start + name.length + 1;
	        if ( ( !start ) && ( name != document.cookie.substring( 0, name.length ) ) ) {
		        return null;
	        }
	        if ( start == -1 ) return null;
	        var end = document.cookie.indexOf( ';', len );
	        if ( end == -1 ) { end = document.cookie.length; }
	        return unescape( document.cookie.substring( len, end ) );
        },

        setCookie : function( name, value, expires, path, domain, secure )
        {
	        var today = new Date();
	        today.setTime( today.getTime() );
	        if ( expires ) { expires = expires * 1000 * 60 * 60 * 24; }
	        var expires_date = new Date( today.getTime() + (expires) );

	        document.cookie = name+'='+escape( value )
		                        + ( expires ? ';expires='+expires_date.toGMTString() : '' )
		                        + ( path ? ';path=' + path : '' )
		                        + ( domain ? ';domain=' + domain : '' )
		                        + ( secure ? ';secure' : '' );
        },

        deleteCookie : function( name, path, domain )
        {
	        if ( this.getCookie( name ) )
	        {
	            document.cookie = name + '=' +
			        ( (path) ? ';path=' + path : '') +
			        ( (domain) ? ';domain=' + domain : '' ) +
			        ';expires=Thu, 01-Jan-1970 00:00:01 GMT';
            }
        },




/*==============================
 * EVENTS
==============================*/
        
        /**
         * Attach an event listener to each of the elements from the this.elements array
         * @return this
         */
        on : function( type, fn )
        {
            var _add = function( el )
            {
                if (window.addEventListener) {
                    el.addEventListener(type, fn, false);
                }
                else if (window.attachEvent) {
                    el.attachEvent("on"+type, fn);
                }
            };
            this.each(function(el) { _add(el); });
            return this;
        },


        /**
         * Remove an event listener from each of the elements of the this.elements array
         * @return this
         */
        removeEvent : function( type, fn )
        {
            var _remove = function( el )
            {
                if (window.removeEventListener) {
                    el.removeEventListener(type, fn, false);
                }
                else if (window.detachEvent) {
                    el.detachEvent("on"+type, fn);
                }
            };
            this.each(function(el) { _remove(el); });
            return this;
        },


        /**
         * Prevent the default action from occurring
         * @return this
         */
        preventDefault : function( ev )
        {
            ev = ev || window.event;
            if (ev.preventDefault) {
                ev.preventDefault();
            }
            else {
                ev.returnValue = false;
            }
            return this;
        },


        /**
         * Stop the propagation of the event
         * @return this
         */
        stopPropagation : function( ev )
        {
            ev = ev || window.event;
            if (ev.stopPropagation) {
                ev.stopPropagation();
            }
            else {
                ev.cancelBubble = true;
            }
            return this;
        },


        /**
         * Prevent the default action from occurring
         * @return this
         */
        stopEvent : function( ev )
        {
            this.preventDefault( ev );
            this.stopPropagation( ev );
            return this;
        },





/*==============================
 * DOM
==============================*/


        /**
         * Check to see whether or not a given element has a class applied
         * @return bool
         */
        hasClass : function( cssClass )
        {
            var pattern = new RegExp("(^| )" +cssClass+ "( |$)");

            this.each(function(el) {
                if (pattern.test(el.className)) { return true; }
            });
            return false;
        },

        /**
         * Remove a class from the selected objects
         * @return this
         */
        removeClass : function( cssClass )
        {
            var pattern = new RegExp("(^| )" +cssClass+ "( |$)");
            this.each(function(el) {
                el.className = el.className.replace(pattern, "$1");
                el.className = el.className.replace(/ $/, "");
            });
            return this;
        },

        /**
         * Add a given class to selected elements
         * @return this
         */
        addClass : function( cssClass )
        {
            var self = this;
            this.each(function(el) {
                if ( ! self.hasClass(cssClass))
                {
                    if (el.className == "") { el.className = cssClass; }
                    else { el.className += " " + cssClass; }
                }
            });
            return this;
        },


        /**
         * Replace all elements from the this.elements array with the ones that match the regex pattern
         * @return this
         */
        getByClass : function( searchClass, parent, searchInTag )
        {
            // reset main array
            this.elements = [];

            if ( parent == null ) {
                parent = document;
            }
            if ( searchInTag == null ) {
                searchInTag = '*';
            }

            var els = parent.getElementsByTagName(searchInTag);
            var elsLen = els.length;
            var pattern = new RegExp('(^|\\\\s)'+searchClass+'(\\\\s|$)');

            for (i = 0, j = 0; i < elsLen; i++)
            {
                if ( pattern.test(els[i].className) )
                {
                    this.elements.push( els[i] );
                    j++;
                }
            }
            return this;
        },


        /**
         * Replace all elements from the this.elements array with the ones that match the regex pattern
         * @return this
         */
        getByTags : function( /*[ as Array ]*/searchTags, /*[ as Object ]*/parent )
        {
            if ( ! this.isArray(searchTags)) {
                throw new Error("The getByTags function expects the first argument to be an Array!");
            }

            if (searchTags.length == 0) { return this; }

            // temp array - holds the elements that match the regex
            var tempArr = [];

            // reset main array
            this.elements = [];

            if ( parent == null ) { parent = document; }


            for (var i= 0; i < searchTags.length; ++i)
            {
                var tag = searchTags[i];

                var els = parent.getElementsByTagName(tag);
            }



            var elsLen = els.length;
            var pattern = new RegExp('(^|\\\\s)'+searchClass+'(\\\\s|$)');

            for (i = 0, j = 0; i < elsLen; i++)
            {
                if ( pattern.test(els[i].className) )
                {
                    this.elements.push( els[i] );
                    j++;
                }
            }
            return this;
        },


        /**
         * Set the inner text to all of the elements from this.elements array
         * @return this
         */
        text : function( txt )
        {
            /*[ SET ]*/
            if (txt)
            {
                this.each(function(e) {
                    e.innerHTML = txt;
                });
                return this;
            }
            /*[ GET ]*/
            else { return this.elements[0].innerHTML; }
        },


        /**
         * Set/Get the value to all of the elements from this.elements array
         * @return this | mixed
         */
        value : function( txt )
        {
            /*[ SET ]*/
            if (txt)
            {
                this.each(function(e) {
                    e.value = txt;
                });
                return this;
            }
            /*[ GET ]*/
            else { return this.elements[0].value; }
        },

        /**
         * Set the css style property to all of the elements from this.elements array
		 *
		 * @param object properties	A key value pair object literal with the properties and values to apply to the selected object
         * @return this
         */
        css : function( /*[ as object ]*/properties )
        {
            this.each(function(el) {
				for (var p in properties)
                	el.style[ p ] = properties[ p ];
            });
            return this;
        },


        /**
         * Set the css style property to an element
         * @return this
         */
        setStyle : function( element, property, value )
        {
            element.style[ property ] = value;
            return this;
        },


        /**
         * Retrieve the computed style attribute of the element
         * @return string
         */
        getStyle : function( element, property )
        {
            var comp_style = null;

            if (window.getComputedStyle) {
                comp_style = window.getComputedStyle(element,null).getPropertyValue(property);
            }
            else {
                if (typeof(element) != "undefined") {
                    comp_style = element.currentStyle;
                    return comp_style[property];
                }
            }
            return comp_style;
        },






/*==============================
 * AJAX
==============================*/


        /**
         * Abort the active request
         * @return this
         */
        _abort : function( xhr )
        {
            xhr.abort();
			xhr = null;
            return this;
        },


        ajax : function( method, uri, /*[ as object ]*/options, onSuccess, onFailure )
        {
            method = method.toUpperCase();

			var self = this;

            /*[ Check and validate method ]*/
            var allow_methods = ["GET", "HEAD", "POST"];

            if ( ! allow_methods.inArray(method)) {
                throw new Error("The provided method: "+ method.toString() +" is not supported!");
            }


            xhr = _createRequest();

            if (xhr == null) { return this; }


            if ( ! options ) { options = {}; }
            /*[ Set options ]
            
                options = {
                    async       : false | true (default)
                    timeout     : null | 3000 (default)
                    postData    : string | null (default) // when making POST requests
                    label       : string | null (default) // when making HEAD requests
                    cache       : true | false (default)  // when making GET requests, whether or not to cache server's response
                    showLoader  : true | false (default)
                    imgSrc      : string | null (default) // the path to the image to be displayed
                    parentCtl   : DOMElement | null (default)  // the element that will append the image loader
                    loadingText : 'Loading...' (default) // the alternate text for the image loader
                }
            */
            if ( options.async == null )    { options.async = true; }
            if ( ! options.timeout )        { options.timeout  = 3000; }
            if ( ! options.postData )       { options.postData = null; }
            if ( ! options.label )          { options.label = null; }
            if ( ! options.cache )          { options.cache = false; }
            if ( ! options.showLoader )     { options.showLoader  = false; }
            if ( ! options.imgSrc )         { options.imgSrc  = null; }
            if ( ! options.parentCtl )      { options.parentCtl = null; }
            if ( ! options.loadingText )    { options.loadingText = "Loading..."; }


            /*[ Create the ajax loader ]*/
            var img_loader = null;
            if (options.showLoader)
            {
                /*[ Clear content first ]*/
                options.parentCtl.innerHTML = '';

                img_loader = _createImageLoader(options.imgSrc, options.parentCtl, options.loadingText);
            }


            /*[ Set timeout ]*/
            var _timer = setTimeout(function() { self._abort(xhr); }, options.timeout);


            /*[ Handle the state of the request ]*/
            xhr.onreadystatechange = function()
            {
                if (xhr.readyState == 4)
                {
                    /*[ Clear timeout ]*/
                    clearTimeout(_timer);

                    if (xhr.status == 200 || xhr.status == 304)
                    {
                        /*[ Clear the loading image ]*/
                        if (img_loader != null) { options.parentCtl.removeChild(img_loader); }

                        /*[ Retrieve response ]*/
                        if (method == "HEAD")
                        {
                            /*[ If a header label was provided ]*/
                             if (options.label) {
                                onSuccess( xhr.getResponseHeader(options.label) );
                             }
                             else {
                                onSuccess( xhr.getAllResponseHeaders() );
                             }
                        }
                        /*[ Common GET request ]*/
                        else { onSuccess( xhr.responseText, xhr.responseXML ); }
                    }
                    else {
                        /*[ Clear the loading image ]*/
                        if (img_loader != null)
                        {
                            try { options.parentCtl.removeChild(img_loader); }
                            catch(e){}
                        }

                        if (onFailure) { onFailure(xhr.statusText); self._abort(xhr); }
                        else {
                            /*[ Default error message ]*/
                            throw new Error("An error has occurred while executing the request.\r\nStatus: "+xhr.statusText);
                        }
                    }
                }
            };

            if ( ! options.cache)
            {
                var rand_no = Math.ceil(1000*Math.random());

                if (uri.indexOf('?') >= 0) {
                    uri += "&xyxz_rand="+rand_no;
                }
                else { uri += "?xyxz_rand="+rand_no; }
            }

            xhr.open(method, uri, options.async);

            if (method == "POST")
            {
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

                if (options.postData) {
                    if (options.postData.indexOf("?") < 0) {
                        options.postData = "?" + options.postData;
                    }
                }
            }
            xhr.send(options.postData);

            return this;
        }


    };
    /*[ end _$.prototype ]*/


    /**
     * Map the $ object to the library's main function
     * return object
     */
    window.Clib = window.$ = function() {
        return new _$(arguments);
    };


})();

Usage:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Clib - a basic javascript library</title>

	<script type="text/javascript" src="bin/c-lib.js"></script>
    <script type="text/javascript">
    
		// Clib == $
	
		Clib(window).on('load', function(event)
		{
			/*[ AJAX - GET ]*/
			Clib("call_server_button").on('click', function(ev)
			{
				// $().stopEvent(ev); /*[ if the default action should be prevented ]*/

				Clib().ajax("GET", "app_code/server.php?myname="+$('name_textbox').value(),
					/*[ OPTIONS ]*/
					{
						"cache"         : false,
						"showLoader"    : true,
						"imgSrc"        : 'bin/ajax-loader.gif',
						"parentCtl"     : document.getElementById('container')
					},
					/*[ ON SUCCESS ]*/
					function(txt, xml) {
						Clib("container").css({"background":"#f00", 'color':'#ff0'}).text(txt);
					}
				);
			});
			/*[ end ajax - get ]*/
		});
    </script>
</head>
<body>
	<h2>Ajax library</h2>


	<div>
    	<input type="text" id="name_textbox" />
    	<input type="button" id="call_server_button" value="Call server" />
    </div>
    <div id="container" style="margin: 25px; width: 400px;"></div>
</body>
</html>
Advertisements
Categories: JavaScript Tags: ,
%d bloggers like this: