/Main_Page

::You must have ninja focus to complete your mission::NinjaFocus::

Javascript Utility Class

Views:


This javascript library contains two classes, one is a modified DomLoaded (by Dean Edwards) and the other is my utility class. It packs just enough punch for me and keeps me from bloating pages with jQuery or YUI. Also, it's a little more sane and stable.

The K class provides a small but relatively useful set of methods to help with general web pages. I also use it a bit for some applications where I only need basic client side functionality. The cookie code is more or less copied from Peter-Paul Koch at www.quirksmode.org, his code and documentation also played a large part in my browser detection code.

This library will also add the indexOf method to the array prototype - this is not something I normally do, but it's just so damn useful I always add this one method to all sites. Also, jQuery is put in to compatibility mode automatically.

I use this script "as is" and usually add any site specific stuff to this Javascript Boilerplate.

Source code is at the end

Nice things this class does:

Contents

Reference

addClass

Add a class name to an element, leaving any existing class names in place

K.addClass(someElement, "className");

analtytics

Load the Google Analytics script from Google.com and fire it.

K.analytics()

This method lets you delay loading analytics until after all of the important stuff has happend, like actually loading the web page and running all your superfly javascript code. Obviously reporting is important, but not if it's going to make your pages slow.

You must have a global variable, gaId, defined that contains the Google Analytics Id for your account.

Also, this method will limit the Google Analytics cookie to the exact domain your web page was loaded from. So, for example, if you use a sub domain to load static content, Google Analytics won't make your browser start sending it cookies and ruin your caching strategy.

createCookie

K.createCookie(name, value, days);

debugMessage

Helpful tool for debugging. Set the debugging level you want and this call this method to pass out debugging data.

Will cause either alerts, console logs (if available) or both.

When you are done with debugging, you can disable debugging and unleash your code on your users. When you find a bug or want to add a feature, just turn it back on again.

// Choose how you want to see debugging messages 
K.DEBUG_LEVEL = DEBUG_USE_CONSOLE | DEBUG_USE_ALERT | K.DEBUG_NONE;

eraseCookie

K.eraseCookie(name);

externalLinks

XHTML Strict does not like the target attribute on links. Use the rel attribute on your anchor tags and set it to "external". Call this method while initialising your page, and it will add a enhancement to make the links open in a new window.

<a href="http://www.google.co.uk" rel="external">Google</a>
K.externalLinks();

fileExtension

Returns the file extension from a given filename, filepath or URL.

var extension = K.fileExtension("someFile.name");

fileIcon

Returns the name to use for a file icon for a given file extension, file name, file path or url.

File names a simple and obvious - <file extension>.jpg. The fours letter versions are returned over the three letter (e.g. tiff instead of tif). I have a collection of file icons which I will try and remember to zip up and upload here. media:fileicons.zip

var iconFilename = K.fileIcon("someFile.name");

getElementsByClassName

Almost works like the dom method, but is cross browser and has a little something extra to help speed things up for Internet Explorer users.

var arrayOfElements = K.getElementsByClassName(element, "nodeType");

element is the container element, use document if you want to search through all elements in a page.

Specifying the node type is optional, but will help out Internet Explorer when you know exactly what type of element you are looking for.

The return type is an array - not a nodeList like you get with a native method. No matches returns an empty array.

getKeyCode

Returns the key code for an onkeypress event.

var code = K.getKeyCode(someEvent);

hasClass

Test to check if an element has a particular class name assigned to it.

var result = K.hasClass(element, "className");

isArray

Pretty obvious

isIE

isIE6

isIE7

isIE8

isMozilla15

isMozilla2:

isMozilla3

isMozilla

isOpera

isSafari

isSafari2

isSafari3

isSafari30

isSafari31

isWebKit

isWebsafeImage

Test to see if a filename points to a web safe image - no magic here, it just checks based on the file extension to see if the file is an image the browser will be able to display by itself.

var result = K.isWebsafeImage("someFile.name");

loadScript

Load an additional javascript file, then execute a call-back as soon as the script has loaded. Great for dealing with dependancies.

K.loadScript("http://www.example.com/script.js", function (){alert('Done!");});

ltrim

trim white space from the beginning of a string

var aString = K.ltrim("    aString");

readCookie

var value = K.readCookie("name");

rtrim

trim white space from the end of a string

var aString = K.trim("     aString   ");

setClass

Set the class name of an element - overwrite any existing class names

K.setClass(element, "className");

trim

trim white space from the the beginning and end of a string

var aString = K.ltrim("    aString");



Source

/************************
 * K javascript library *
 ************************/

// MIT License http://opensource.org/licenses/mit-license.php
 
///////////////////
// utility object
var K = {
    ELEMENT_NODE: 1,
    ATTRIBUTE_NODE: 2,
    TEXT_NODE: 3,
    CDATA_SECTION_NODE: 4,
    ENTITY_REFERENCE_NODE: 5,
    ENTITY_NODE: 6,
    PROCESSING_INSTRUCTION_NODE: 7,
    COMMENT_NODE: 8,
    DOCUMENT_NODE: 9,
    DOCUMENT_TYPE_NODE: 10,
    DOCUMENT_FRAGMENT_NODE: 11,
    NOTATION_NODE: 12,
    DEBUG_NONE: 0,
    DEBUG_USE_CONSOLE: 1,
    DEBUG_USE_ALERT: 2,
    DEBUG_ALWAYS_ALERT: 6,
    DEBUG_MESSAGES: 0,
    addClass: function (node, classname) {
        if (!K.hasClass(node, classname)) node.className += node.className ? " " + classname : classname;
    },
    addListener: function (obj, evt, handler, captures) {
        if (document.addEventListener)
        {
            obj.addEventListener(evt, handler, captures);
        }
        else
        {
            // IE
            obj.attachEvent('on' + evt, handler);
        }
    },
    analytics: function () {
        //Trigger loading of the Google Analytics Script
        if (!gaId) {
            return null;
        }
        gaJsHost = (("https:" == document.location.protocol) ? "https://ssl.": "http://www.");
        K.loadScript(gaJsHost + "google-analytics.com/ga.js", K.analyticsLoaded);
    },
    analyticsLoaded: function () {
        // Load Google Analytics, once the script has loaded
        if (!gaId)
        {
            return null;
        }
        try {
             var pageTracker = _gat._getTracker(gaId);
                // Limit Google Analytics to the full hostname domain only, rather than default of parent domain.
                pageTracker._setDomainName(BASE_URL.replace(/http:\/\//, '').replace(/\/.*$/, ''));
                pageTracker._trackPageview();
        }
        catch (err) {}
    },
    createCookie: function (name, value, days) {
        var date,
        expires;
        if (days) {
            date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            expires = "; expires=" + date.toGMTString();
        }
        else
        {
            expires = "";
        }
        document.cookie = name + "=" + value + expires + "; path=/";
    },
    debugMessage: function (message) {
        if (!K.DEBUG_MESSAGES) return null;
        var hasConsole = (typeof console != "undefined" && typeof console.log != "undefined")
        if (K.DEBUG_MESSAGES & K.DEBUG_USE_CONSOLE & hasConsole)
        {
            console.log(message);
        }
        if (K.DEBUG_MESSAGES & K.DEBUG_USE_ALERT & !hasConsole)
        {
            alert(message);
        }
        if (K.DEBUG_MESSAGES & K.DEBUG_ALWAYS_ALERT & hasConsole)
        {
            alert(message);
        }
    },
    enableImageSelector: function () {
        var imageselector,
        images,
        image,
        i;
        imageselector = document.getElementById('imageselector');
        if (imageselector)
        {
            images = imageselector.getElementsByTagName('img');
            image = new Image();
            for (i = 0; i < images.length; i++)
            {
                image.src = FILES_URL + '/' + images.item(i).src.match(/([^\\\/]+)$/)[1];
            }
        }
        jQuery('#imageselector img').click(
        function() {
            var largeimgsrc,
            imageviewer,
            largeimage;
            largeimgsrc = FILES_URL + '/' + this.src.match(/([^\\\/]+)$/)[1];
            jQuery('#imageviewer img').hide('slow',
            function() {
                imageviewer = document.getElementById('imageviewer');
                largeimage = imageviewer.getElementsByTagName('img').item(0);
                largeimage.src = largeimgsrc;
            });
            jQuery('#imageviewer img').show('slow');
        }
        );
    },
    eraseCookie: function (name) {
        K.createCookie(name, "", -1);
    },
    externalLinks: function ()
    {
        // for xhtml strict websites, set rel="external" on your links instead of target="_blank"
        // then call this function on domloaded
        var anchors,
        i;
        anchors = document.getElementsByTagName('a');
        for (i = 0; i < anchors.length; ++i)
        {
            anchor = anchors[i];
            if (anchor.getAttribute('href') && anchor.getAttribute('rel') == 'external')
            {
                anchor.target = '_blank';
            }
        }
    },
    fileExtension: function (path) {
        return path.substr(path.lastIndexOf(".") + 1, path.length);
    },
    fileIcon: function (path) {
        // a selection of file icons are avaible in the assets folder. This
        // function will determine the appropriate icon file name to load 
        // from any of the sets of icons. The choice is based on the fileextension 
        // of the path argument
        var ext, icon;
        ext = K.fileExtension(path);
        switch (ext.toLowerCase())
        {
            case 'jpg':
            case 'jpeg':         icon = 'jpeg.jpg';
                                 break;
            case 'gif':          icon = 'gif.jpg';
                                 break;
            case 'png':          icon = 'png.jpg';
                                 break;
            case 'doc':
            case 'dot':          icon = 'doc.jpg';
                                 break;
            case 'xls':
            case 'xlm':
            case 'xla':
            case 'xlc':
            case 'xlt':
            case 'xlw':          icon = 'xls.jpg';
                                 break;
            case 'ppt':
            case 'pps':
            case 'pos':          icon = 'ppt.jpg';
                                 break;
            case 'pdf':          icon = 'pdf.jpg';
                                 break;
            case 'tiff':
            case 'tif':          icon = 'tiff.jpg';
                                 break;
            case 'zip':          icon = 'zip.jpg';
                                 break;
            case 'gz':           icon = 'gz.jpg';
                                 break;
            case 'bz':           icon = 'bz.jpg';
                                 break;
            case 'bz2':          icon = 'bz2.jpg';
                                 break;
            case 'rtf':          icon = 'rtf.jpg';
                                 break;
            case 'swf':          icon = 'swf.jpg';
                                 break;
            case 'psd':          icon = 'psd.jpg';
                                 break;
            case 'html':
            case 'htm':          icon = 'html.jpg';
                                 break;
            default:             icon = 'unknown.jpg';
                                 break;
        }
        return icon;
    },
    formSubmissionCheck: function (form, message) {
        var existingWarnings, listItems, element, elements = [], i, value;
        ///////////
        // Clear up from any previous attempts to submit the form, where class names and 
        // warning messages may have been added to form elements.
        existingWarnings = K.getElementsByClassName(form, 'warning');
        if (existingWarnings.length)
        {
            for (i = 0; i < existingWarnings.length; ++i)
            {
                K.removeClass(existingWarnings[i], 'warning');
                existingWarnings[i].onfocus = null;
                if (    existingWarnings[i].tagName.toLowerCase() == 'input' 
                    ||  existingWarnings[i].tagName.toLowerCase() == 'textarea'
                    &&  existingWarnings[i].value == message)
                {
                    existingWarnings[i].value = '';
                }
            }
        }
        ////////////
        // Find all required elements
        listItems = K.getElementsByClassName(form, 'required');
        if (listItems)
        {
            for (i = 0; i < listItems.length; ++i)
            {
                // inputs are the most common aren't they?
                element = listItems[i].getElementsByTagName('input');
                if (!element.length) 
                {
                    element = listItems[i].getElementsByTagName('textarea');
                }
                // no inputs? then try textarea
                if (!element.length) 
                {
                    element = listItems[i].getElementsByTagName('select');
                }
                // still nothing? try select box
                if (element.length)
                {
                    element = element.item(0);
                    // filter out inputs that don't need to be validated
                    if (    element.getAttribute('type') == 'hidden'
                        ||  element.getAttribute('type') == 'submit'
                        ||  element.getAttribute('type') == 'reset' ) 
                    {
                        continue;
                    }
                    elements.push(element);
                }
            }
        }
        //////////////
        // Go over required elements and look for those which have not been filled in. 
        for (i = 0; i < elements.length; ++i)
        {
            if (elements[i].tagName.toLowerCase() == 'select')
            {
                value = elements[i].options[elements[i].selectedIndex].value;
            }
            else
            {
                value = elements[i].value;
            }
            if (!K.trim(value))
            {
                K.addClass(elements[i], 'warning');
                if (    elements[i].tagName.toLowerCase() != 'select'
                        && !(    elements[i].tagName.toLowerCase() == 'input'
                            &&  elements[i].getAttribute('type') == 'password') )
                {
                    elements[i].value = message;
                }
                elements[i].onfocus = function () {
                    K.debugMessage("focusing on "+this.tagName);
                    if (this.value == message)
                    {
                        this.value = '';
                    }
                    K.removeClass(this, 'warning');
                }
            }
        }
        return (K.getElementsByClassName(form, 'warning').length == 0);
    },
    getElementsByClassName: function (node, classname, tagName) {
        // Like node.getElementsByClassName(classname)
        // except you must pass the node (eg. document or document.getElementById('menu'))
        // as the first argument. Optionally specify the tagName to limit the search to 
        // only a specific type of tag (for performance).
    	var failedMatch, matchingElements = [], re, els, i, j, classname, elClassnames;
    	if (node && typeof node.getElementsByClassName != "undefined")
    	{
    	    // Need to be consistent and always return an Array, never a NodeList
    	    els = node.getElementsByClassName(classname);
    	    if (!els)
    	    {
    	        K.debugMessage("K.getElementsByClassName() nothing found, returning empty array");
    	        return matchingElements;
    	    }
    	    for(i = 0; i < els.length; ++i)
    	    {
    	        if (K.isSafari31())
    	        {
    	            // Safari does something very bloody weird. Class attribute is empty, 
    	            // WebInspector agrees, but safari still "finds" these elements. GGrrrrr.
    	            // Non at all rather than broken please.
    	            if (!K.hasClass(els.item(i), classname))
    	            {
    	                continue;
    	            }
    	        }
    	        matchingElements[i] = els.item(i);
    	    }
        	//delete els;
    	    return matchingElements;
    	}
    	classnames = classname.split(" ");
    	if (tagName)
    	{
    	    els = node.getElementsByTagName(tagName);
    	}
    	else
    	{
    	    els = node.all ? node.all : node.getElementsByTagName("*");
    	}
    	for(i=0; i < els.length; ++i)
    	{
    	    failedMatch = false;
    		if (!els.item(i).className)
    		{
    			continue;
    		}
    		for (j = 0; j < classnames.length; ++j)
    		{
    			if(els.item(i).className.indexOf(classnames[j]) < 0)
    			{
    			    failedMatch = true;
    			}
    		}
    		if (!failedMatch)
    		{
    		    matchingElements.push(els.item(i));
    		}
    	}
    	return matchingElements;
    },
    getKeyCode: function (e) {
        var key;
        if (e)
        {
            key = e.which;
        }
        else
        {
            key = window.event.keyCode;
        }
        return key;
    },
    hasClass: function (node, classes) {
        // can accept a single class name as a string or an array of classnames to search for.
        var i, currentClasses;
        if (!node || !node.className) 
        {
            return false;
        }
        if (typeof classes == 'string')
        {
            // single class name passed as a string, convert to array.
            classes = K.trim(classes.replace(/\s{2,}/g, ''));
            classes = classes.split(" ");
        }
        if (K.isArray(classes))
        {
            // now we have an array of class names to look for, build an
            // array of class names that the node has been assigned.
            currentClasses = node.className.split(" ");
            for (i = 0; i < classes.length; ++i)
            {
                // loop over the the array of class names we are trying to match
                if (currentClasses.indexOf(classes[i]) >= 0)
                {
                    // the node has been assigned one of the classes we are 
                    // looking for. Job done.
                    return true;
                }
            }
        }
        return false;
    },
    isArray: function (array) {
        return (array.constructor && array.constructor == Array);
    },
    isChrome: function () {
        return !!window.chrome && navigator && navigator.vendor && navigator.appVersion.toLowerCase().indexOf('chrome') != -1;
    },
    isIE8: function () {
        return K.isIE() && !!document.querySelector;
    },
    isIE7: function () {
        return K.isIE() && !!document.documentElement && typeof document.documentElement.style.maxHeight != 'undefined' && !K.isIE8();
    },
    isIE6: function () {
        return K.isIE() && !!document.compatMode && !K.isIE7() && !K.isIE8() && typeof document.createAttribute != "undefined";
    },
    isIE: function () {
        return !! (document.all && !window.opera);
    },
    isFirefox3: function () {
        return typeof document.getElementsByClassName != "undefined" && K.isFirefox();
    },
    isFirefox2: function () {
        return K.isFirefox() && !K.isFirefox3();
    },
    /*
    isMozilla15: function () {
            return typeof Array.every != "undefined" && !K.isMozilla3() && K.isMozilla();
        },*/
    isFirefox: function () {
        return typeof document.getElementsByTagName('script').item(0).contains == "undefined" && !document.all;
    },
    isOpera: function () {
        return !! window.opera;
    },
    isSafari31: function () {
        return K.isSafari3() && typeof document.getElementsByClassName != "undefined";
    },
    isSafari30: function () {
        return K.isSafari3() && !K.isSafari31();
    },
    isSafari3: function () {
        return K.isSafari() && window.devicePixelRatio;
    },
    isSafari2: function () {
        return K.isSafari() && !K.isSafari3();
    },
    isSafari: function () {
        return navigator && navigator.vendor && navigator.vendor.toLowerCase().indexOf('apple') != -1;
    },
    isWebkit: function () {
        return navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('applewebkit') != -1;
    },
    isWebsafeImage: function (path) {
        ext = K.fileExtension(path);
        switch (ext)
        {
            case 'jpg':
            case 'jpeg':
            case 'gif':
            case 'png': return true;
                        break;
            default:    return false;
                        break;
        }
    },
    loadScript: function (url, aFunction) {
        // Load an additional script after the domloaded event has already fired.
        // Safe for XHTML Strict web sites. 
        // url - the url to load, aFunction - function to call once script has loaded
        var e = document.createElement("script");
        e.onreadystatechange = function()
        {
            if ((this.readyState == 'completed' || this.readyState == 'loaded') && !this.loadScriptDone)
            {
                this.loadScriptDone = true;
                aFunction();
            }
        }
        e.onload = aFunction;
        e.type = "text/javascript";
        e.src = url;
        document.getElementsByTagName("head")[0].appendChild(e);
        return e;
    },
    ltrim: function (string) {
        // trim white space from the left of a string.
        if (typeof string == 'string') return string.replace(/^\s+/, '');
        return string;
    },
    readCookie: function (name) {
        var nameEQ = name + "=",
        ca,
        i,
        c;
        ca = document.cookie.split(';');
        for (i = 0; i < ca.length; i++) {
            c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1, c.length);
            }
            if (c.indexOf(nameEQ) == 0) {
                return c.substring(nameEQ.length, c.length);
            }
        }
        return null;
    },
    reCaptcha: function () {
        if (!reCaptchaKey || !document.getElementById('recaptchaplaceholder'))
        {
            return null;
        }
        loadScript((("https:" == document.location.protocol) ? "https://api-secure": "http://api") + '.recaptcha.net/js/recaptcha_ajax.js', reCaptchaLoaded);
    },
    reCaptchaLoaded: function () {
        if (!reCaptchaKey || !document.getElementById('recaptchaplaceholder'))
        {
            return null;
        }
        Recaptcha.create(reCaptchaKey, document.getElementById('recaptchaplaceholder'));
    },
    removeClass: function (node, classname) {
        if (K.hasClass(node, classname))
        {
    		node.className = node.className.replace(new RegExp('(\\s|^)' + classname + '(\\s|$)'),' ');
    	}
    },
    rtrim: function (string) {
        // trim white space from the right of a string.
        if (typeof string == 'string') return string.replace(/\s+$/, '');
        return string;
    },
    setClass: function (node, classname) {
        node.className = classname;
    },
    textToImage: function (menuId_or_links, tti_name, capitalise) {
        var primarymenu,
        sectionmenu,
        links = [],
        i,
        img,
        text,
        j;
        if (K.isArray(menuId_or_links))
        {
            links = menuId_or_links;
        }
        else
        {
            menu = document.getElementById(menuId_or_links);
            if (menu)
            {
                links = menu.getElementsByTagName('a');
            }
        }
        if (links.length)
        {
            
            for (i = 0; i < links.length; ++i)
            {
                text = '';
                for (j = 0; j < links[i].childNodes.length; ++j)
                {
                    text = text + links[i].childNodes[j].nodeValue;
                    links[i].childNodes[j].nodeValue = '';
                }
                if (capitalise && text.length) 
                {
                    text = text.toUpperCase();
                }
                url = STATIC_URL + '/tti/' + tti_name + '/' + escape(text);
                if (K.isIE6())
                {
                    links[i].style.cursor = 'pointer';
                    var textNode = document.createTextNode(text);
                    div = document.createElement('div');
                    div.appendChild(textNode);
                    img = document.createElement('img');
                    img.src = url;
                    img.wrapperDiv = div;
                    div.filterImage = img;
                    //div.appendChild(img);
                    //img.style['display'] = 'none';
                    if (img.width && img.height)
                    {
                        div.style.width = img.width + 'px';
                        div.style.height = img.height + 'px';
                    }
                    else
                    {
                        img.onreadystatechange = function () {
                            if (this.readyState == 'complete')
                            {
                                this.wrapperDiv.style.width = this.width +'px';
                                this.wrapperDiv.style.height = this.height +'px';
                            }
                        };
                    }
                    div.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src='" + url + "')";
                    div.style.cursor = "pointer";
                    div.style.display = "block";
                    div.style.textIndent = '-2000px';
                    links[i].appendChild(div);
                }
                else
                {
                    img = document.createElement('img');
                    img.src = url;
                    img.alt = text;
                    links[i].appendChild(img);
                }
            }
        }
    },
    trim: function (string) {
        // trim white space from the left and right of a string.
        if (typeof string == 'string') return string.replace(/^\s+|\s+$/g, '');
        return string;
    }
};
// K
//////

///////////////////////////////////
// DomLoaded - ondomdocumentready
/*! DomLoaded courtesy of Dean Edwards and contributors at http://dean.edwards.name
 * Released under an MIT License http://www.opensource.org/licenses/mit-license.php 
 * Modified by Kieran Whitbread */
var DomLoaded =
{
    onload: [],
    loaded: function()
    {
        var i;
        if (arguments.callee.done) return;
        arguments.callee.done = true;
        for (i = 0; i < DomLoaded.onload.length; i++) DomLoaded.onload[i]();
    },
    load: function(fireThis)
    {
        this.onload.push(fireThis);
        if (document.addEventListener)
        document.addEventListener("DOMContentLoaded", DomLoaded.loaded, null);
        if (/KHTML|WebKit/i.test(navigator.userAgent))
        {
            var _timer = setInterval(function()
            {
                if (/loaded|complete/.test(document.readyState))
                {
                    clearInterval(_timer);
                    delete _timer;
                    DomLoaded.loaded();
                }
            },
            10);
        }
/*@cc_on @*/
/*@if (@_win32)
var proto = "src='javascript:void(0)'";
if (location.protocol == "https:") proto = "src=//0";
document.write("<scr"+"ipt id=__ie_onload defer " + proto + "><\/scr"+"ipt>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
    if (this.readyState == "complete") {
        DomLoaded.loaded();
    }
};
/*@end @*/
        window.onload = DomLoaded.loaded;
    }
};
//DomLoaded
/////////////

///////////////////////////////////////////////
// Add the indexOf() method to Array Objects
if (!Array.indexOf)
 {
    Array.prototype.indexOf = function(obj, start)
    {
        for (var i = (start || 0); i < this.length; ++i)
        {
            if (this[i] == obj)
            {
                return i;
            }
        }
    }
}

/////////////////////////
// jQuery Compatibility
if (typeof jQuery != "undefined") {
    // Comment out the next line to keep the default jQuery "$" reference
    jQuery.noConflict(); // Might be using other JS libs such as prototype
}

/////////////////////////////////
// Configure Debugging Messages
//K.DEBUG_MESSAGES = K.DEBUG_USE_CONSOLE | K.DEBUG_USE_ALERT;
K.DEBUG_MESSAGES = K.DEBUG_NONE;

Main Menu

Personal tools

Toolbox