﻿// jPixeliT - javascript library v1.2
// Written by Miron Abramson

var undefined, jPixeliT = {
    onError: function(errMessage) {
        alert("jPixeliT error:\n\r " + errMessage);
    }
    ,
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////// Selectors //////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    $: function(selector, rootElement) {
        ///	<summary>
        ///		Get element by id: jPixeliT.$("#id")
        ///     Get elements by tagName: jPixeliT.$("tagName","rootElementId") / jPixeliT.$("tagName",rootElement)
        ///     Get elements by tagName and claaName: jPixeliT.$("tagName.className","rootElementId") / jPixeliT.$("tagName.className",rootElement)
        ///         To get all elements by class, use jPixeliT.$("*.className")
        ///	</summary>
        /// <param name="selector" type="String" Mandatory="yes">The selector</param>
        /// <param name="selector" type="string/DOM element" Mandatory="No">DOM element id element Id that contain the selector</param>

        if (!selector || typeof (selector) != 'string') return selector;
        // Get by id
        if (selector.substr(0, 1) === "#") {
            return this.findById(selector.substr(1));
        }

        // Get by tag name and class name
        if (selector.indexOf(".") >= 0) {
            if (typeof (rootElement) === 'string') rootElement = this.$("#" + rootElement);
            rootElement = rootElement || document;
            var parts = selector.split(".");
            return this.getElementsByClassName(parts[1], rootElement, parts[0] === "*" ? null : parts[0]);
        }

        // Get by tag name
        return this.findByTagName(selector, rootElement);
    }
    ,
    findByTagName: function(tagName, rootElement) {
        if (typeof (rootElement) === 'string') rootElement = this.$("#" + rootElement);
        rootElement = rootElement || document;
        var lst = rootElement.getElementsByTagName(tagName);
        if (!lst || lst.length < 1) return null;
        return lst;
    }
    ,
    findById: function(id) {
        // Get by element id
        var parts = id.split(':');
        var all = false;
        if (parts.length > 0 && String.Equals(parts[1], 'all', true)) {
            all = true;
        }
        var elm = document.getElementById(parts[0]);
        if (elm) return elm;
        if (!all && this._elementsIdsCache[parts[0]]) {
            return document.getElementById(this._elementsIdsCache[parts[0]]);
        }
        var reg = new RegExp("_" + parts[0] + "$");
        var i = 0, pageElements = document.all ? document.all : document.getElementsByTagName("*");
        if (all) {
            var returnElements = [];
            while (elm = pageElements[i++]) {
                if (elm.id) {
                    if (reg.test(elm.id)) {
                        returnElements.push(elm);
                    }
                }
            }
            return returnElements.length > 0 ? returnElements : null;
        }
        else {
            while (elm = pageElements[i++]) {
                if (elm.id) {
                    if (reg.test(elm.id)) {
                        this._elementsIdsCache[id] = elm.id;
                        return elm;
                    }
                }
            }
        }
        return;
    }
    ,
    getElementsByClassName: function(className, rootElement, tagName) {
        ///	<summary>
        ///		Get all elements with the specified class name
        ///	</summary>
        /// <param name="className" type="String" Mandatory="yes">The class name to find</param>
        /// <param name="rootElement" type="DOM Element" Mandatory="No">the root element where to search from. To search all document, pass 'document'</param>
        /// <param name="tagName" type="String" Mandatory="No">The tag name to search ("div", "span"...)</param>
        if (document.getElementsByClassName) {
            getElementsByClassName = function(className, tagName, rootElement) {
                rootElement = rootElement || document;
                var elements = rootElement.getElementsByClassName(className),
				nodeName = (tagName) ? new RegExp("\\b" + tagName + "\\b", "i") : null,
				returnElements = [],
				current;
                var i = 0;
                while (current = elements[i++]) {
                    if (!nodeName || nodeName.test(current.nodeName)) {
                        returnElements.push(current);
                    }
                }
                return returnElements;
            };
        }
        else if (document.evaluate) {
            getElementsByClassName = function(className, tagName, rootElement) {
                tagName = tagName || "*";
                rootElement = rootElement || document;
                var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace) ? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
                for (var j = 0, jl = classes.length; j < jl; j += 1) {
                    classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
                }
                try {
                    elements = document.evaluate(".//" + tag + classesToCheck, rootElement, namespaceResolver, 0, null);
                }
                catch (e) {
                    elements = document.evaluate(".//" + tagName + classesToCheck, rootElement, null, 0, null);
                }
                while ((node = elements.iterateNext())) {
                    returnElements.push(node);
                }
                return returnElements;
            };
        }
        else {
            getElementsByClassName = function(className, tagName, rootElement) {
                tagName = tagName || "*";
                rootElement = rootElement || document;
                var classes = className.split(" "),
				classesToCheck = [],
				elements = (tagName === "*" && rootElement.all) ? rootElement.all : rootElement.getElementsByTagName(tagName),
				current,
				returnElements = [],
				match;
                for (var k = 0, kl = classes.length; k < kl; k += 1) {
                    classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
                }
                var elmNbr = elements.length;
                for (var l = 0, ll = elmNbr; l < ll; l += 1) {
                    current = elements[l];
                    match = false;
                    for (var m = 0, ml = classesToCheck.length; m < ml; m += 1) {
                        match = classesToCheck[m].test(current.className);
                        if (!match) {
                            break;
                        }
                    }
                    if (match) {
                        returnElements.push(current);
                    }
                }
                return returnElements;
            };
        }
        return getElementsByClassName(className, tagName, rootElement);
    }
    ,
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////// Utilities //////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    forEach: function(items, callback) {
        ///	<summary>
        ///		iterate over collection and excute the callback method for each item in the collection
        ///	</summary>
        /// <param name="items" type="Colection" Mandatory="yes">The collectin to iterate over</param>
        /// <param name="callback" type="function(item,index)" Mandatory="No">Callback method to excute over each item in the collection</param>
        if (!items || !callback) return;
        if (!items.length) callback(items, 0);
        var i = 0;
        var elm;
        while (elm = items[i++]) {
            callback(elm, i - 1);
        }
    }
    ,
    Cache: {}
    ,
    setInnerHTML: function(selector, text) {
        ///	<summary>
        ///		Set element innerHTML and excute scripts within the text
        ///	</summary>
        /// <param name="selector" type="String" Mandatory="yes">The selector of the element to set its innerHTML</param>
        /// <param name="text" type="text/html/script" Mandatory="Yes">The html/text to inject into the element</param>
        var elm = this.$(selector);
        if (elm) {
            if (!text) text = "";
            elm.innerHTML = text;
            var x = elm.getElementsByTagName("script");
            if (x) {
                for (var i = 0; i < x.length; i++) {
                    eval(x[i].text);
                }
            }
        }
    }
    ,
    isEmpty: function(value) {
        ///	<summary>
        ///		Check object for null or string to null or empty (length=0)
        ///	</summary>
        /// <param name="value" type="String/Object" Mandatory="yes">The value to check</param>
        if (typeof value === 'boolean') return false;
        if (typeof (value) === 'string') {
            if (value.length > 0)
                return false;
            return true;
        }
        return (value ? false : true);
    }
    ,
    isValidEmail: function(input) {
        ///	<summary>
        ///		Check string if it is a valid email address
        ///	</summary>
        /// <param name="input" type="String" Mandatory="yes">The string to check</param>
        if (!input) return false;
        var rx = new RegExp("\\w+([-+.\']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*");
        var matches = rx.exec(input);
        return (matches != null && input === matches[0]);
    }
    ,
    mouseLocation: function(e) {
        ///	<summary>
        ///		Get the current mouse pointer location on event
        ///	</summary>
        /// <param name="e" type="event" Mandatory="yes">Current mouse event</param>
        if (!e) var e = window.event;
        x = e.clientX;
        y = e.clientY + this.scrollOffset().top;
        return { left: x, top: y };
    },
    scrollOffset: function() {
        ///	<summary>
        ///		Get current scroll offset
        ///	</summary>
        var x, y;
        if (self.pageYOffset) {
            x = self.pageXOffset;
            y = self.pageYOffset;
        }
        else {
            if (document.documentElement && document.documentElement.scrollTop) {
                x = document.documentElement.scrollLeft;
                y = document.documentElement.scrollTop;
            }
            else {
                if (document.body) {
                    x = document.body.scrollLeft;
                    y = document.body.scrollTop;
                }
            }
        }
        return { left: parseInt(x), top: parseInt(y) };
    }
    ,
    removeSuffix: function(value, suffix, ignoreCase) {
        if (this.isEmpty(value) || this.isEmpty(suffix) || !(typeof (value) === 'string')) return value;
        return value.endsWith(suffix, ignoreCase) ? value.substring(0, value.length - suffix.length) : value;
    }
    ,
    querystringParam: function(name, url) {
        name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
        var regexS = "[\\?&]" + name + "=([^&#]*)";
        var regex = new RegExp(regexS);
        if (url === undefined) url = window.location.href;
        url = decodeURI(url);
        var results = regex.exec(url);
        if (!results)
            return "";
        else
            return unescape(results[1].replace(/\+/g, " "));
    }
    ,
    removeAttr: function(selector, name) {
        var elm = this.$(selector);
        this.attr(elm, name, "");
        if (elm.nodeType == 1)
            elm.removeAttribute(name);
    }
    ,
    attr: function(selector, attributeName, value) {
        ///	<summary>
        ///		Get or set element attribute
        ///	</summary>
        /// <param name="selector" type="selector" Mandatory="yes">selector of the element</param>
        /// <param name="attributeName" type="DOM Element" Mandatory="Yes">The attribute name</param>
        /// <param name="value" type="Object" Mandatory="No">The attribute value. If this attribute is not defined, the methos is 'get' else  it is 'set'</param>
        var elm = this.$(selector);
        if (!elm) return;

        var special = /href|src|style/.test(attributeName);

        if (value !== undefined) {
            this.forEach(elm, function(item, i) {
                if (attributeName == "class") item.className = value;
                else if (!jPixeliT.browser.capability.STYLE_ATTRIBUTE && attributeName == 'style') this.attr(item.style, "cssText", value);
                else {
                    if (attributeName in elm && !special) {
                        elm[attributeName] = value;
                    }
                    else item.setAttribute(attributeName, value);
                }
            });
            return;
        }
        if (!jPixeliT.browser.capability.STYLE_ATTRIBUTE && attributeName == 'style') return elm.style.getAttribute("cssText");
        if (attributeName in elm && !special) return elm[attributeName];
        return attributeName == "class" ? elm.className : elm.getAttribute(attributeName);
    }
    ,
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////// Css & style/////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    cssValue: function(selector, name, force) {
        var ret, elem = jPixeliT.$(selector);
        var style = elem.style;

        if (name == "width" || name == "height") {
            var val, props = { position: "absolute", visibility: "hidden", display: "block" }, which = name == "width" ? ["Left", "Right"] : ["Top", "Bottom"];

            function getWH() {
                val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
                jPixeliT.forEach(which, function(item) {
                    val -= parseFloat(jPixeliT.cssValue(elem, "padding" + item, true)) || 0;
                    val -= parseFloat(jPixeliT.cssValue(elem, "border" + this + "Width", true)) || 0;
                });
            }

            if (elem.offsetWidth !== 0)
                getWH();
            else {

                jPixeliT._swap(elem, props, getWH);
            }

            return Math.max(0, Math.round(val));
        }

        // We need to handle opacity special in IE
        if (name == "opacity") {
            ret = style.display === 'none' ? 0 : (style.filter && style.filter.indexOf("opacity=") >= 0 ? (parseFloat(style.filter.match(/opacity=([^)]*)/)[1]) / 100)
         : style["opacity"] ? parseFloat(style["opacity"]) : 1);
            return ret;
        }

        // Make sure we're using the right name for getting the float value
        if (name.match(/float/i))
            name = styleFloat;

        if (!force && style && style[name])
            ret = style[name];
        else if (defaultView.getComputedStyle) {
            // Only "float" is needed here
            if (name.match(/float/i))
                name = "float";

            name = name.replace(/([A-Z])/g, "-$1").toLowerCase();

            var computedStyle = defaultView.getComputedStyle(elem, null);

            if (computedStyle)
                ret = computedStyle.getPropertyValue(name);

        } else if (elem.currentStyle) {
            var camelCase = name.replace(/\-(\w)/g, function(all, letter) {
                return letter.toUpperCase();
            });

            ret = elem.currentStyle[name] || elem.currentStyle[camelCase];

            // From the awesome hack by Dean Edwards
            // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

            // If we're not dealing with a regular pixel number
            // but a number that has a weird ending, we need to convert it to pixels
            if (!/^\d+(px)?$/i.test(ret) && /^\d/.test(ret)) {
                // Remember the original values
                var left = style.left, rsLeft = elem.runtimeStyle.left;

                // Put in the new values to get a computed value out
                elem.runtimeStyle.left = elem.currentStyle.left;
                style.left = ret || 0;
                ret = style.pixelLeft + "px";

                // Revert the changed values
                style.left = left;
                elem.runtimeStyle.left = rsLeft;
            }
        }

        return ret;
    }
    ,
    setOpacity: function(selector, opacity) {
        if (opacity >= 1) opacity = 0.999;
        if (opacity < 0) opacity = 0;
        this.forEach(this.$(selector), function(item, index) {
            var s = item.style;
            s.zoom = 1; // Stupied hack for IE
            s.filter = "alpha(opacity=" + (opacity * 100) + ")";
            s.KHTMLOpacity = opacity;
            s.MozOpacity = opacity;
            s.opacity = opacity;
        });
    }
    ,
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////  Animation /////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    slide: function(selector, speed, callback) {
        var obj = this.$(selector);
        if (!obj) {
            this.onError("slide: Can't find element");
            return;
        }
        this.forEach(obj, function(item, index) {
            if (item.style.display === 'none')
                jPixeliT.slideDown(item, speed, callback);
            else jPixeliT.slideUp(item, speed, callback);
        });
    }
    ,
    slideDown: function(selector, speed, callback) {
        var obj = this.$(selector);
        if (!obj) {
            this.onError("slideDown: Can't find element");
            return;
        }
        var prop = this._getArguments(speed, callback);
        this.forEach(obj, function(item, index) {
            var func = function() {
                var p = new Parameter();
                p.duration = prop.duration;
                p.callback = prop.callback;
                jPixeliT._callbackQueue(p);
                p.element = item;
                p.from = 0;
                p.startTime = now();
                p.hide = false;
                var lastHeight = jPixeliT.attr(item, "lh");
                p.to = lastHeight ? lastHeight : jPixeliT.cssValue(item, "height");
                p.overflow = jPixeliT.cssValue(item, "overflow");
                if (p.to <= p.from || item.style.display !== 'none') {
                    p.completed();
                    return;
                }

                p.animationType = "slide";
                p.element.style.height = '0px';
                item.style.display = '';
                p.element.style.overflow = "hidden";
                p.timer = setInterval(function() { jPixeliT.animation.step(p); }, 13);
            }
            if (jPixeliT._isQueueForElementExists(item)) {
                var q = jPixeliT._getQueueForElement(item);
                q.push(func);
            }
            else { jPixeliT._getQueueForElement(item); func(); }
        });
    }
    ,
    slideUp: function(selector, speed, callback) {
        var obj = this.$(selector);
        if (!obj) {
            this.onError("slideUp: Can't find element");
            return;
        }
        var prop = this._getArguments(speed, callback);
        this.forEach(obj, function(item, index) {
            var func = function() {
                var p = new Parameter();
                p.duration = prop.duration;
                p.callback = prop.callback;
                jPixeliT._callbackQueue(p);
                p.element = item;
                p.from = jPixeliT.cssValue(item, "height");
                p.startTime = now();
                p.hide = true;
                p.to = 0;

                p.overflow = jPixeliT.cssValue(item, "overflow");
                if (p.to >= p.from || item.style.display === 'none') {
             //       p.element.style.height = '0px';
                    p.completed();
                    return;
                }
                p.element.style.overflow = "hidden";
                // Save the current height
                jPixeliT.attr(item, "lh", p.from);
                p.animationType = "slide";
                jPixeliT.animation.step(p);
                p.timer = setInterval(function() { jPixeliT.animation.step(p); }, 13);
            }
            if (jPixeliT._isQueueForElementExists(item)) {
                var q = jPixeliT._getQueueForElement(item);
                q.push(func);
            }
            else { jPixeliT._getQueueForElement(item); func(); }
        });
    }
    ,
    fadeIn: function(selector, speed, callback) {
        ///	<summary>
        ///		Fade in element until full visibility
        ///	</summary>
        /// <param name="selector" type="object" Mandatory="yes">selector of efected element</param>
        /// <param name="speed" type="int" Mandatory="yes">Fade in speed.  Values: 1-1000 (lower=faster) </param>
        /// <param name="callback" type="Function" Mandatory="No">Callback method to excute when completed</param>
        this.fadeTo(selector, 1, speed, callback);
    }
    ,
    fadeOut: function(selector, speed, callback) {
        ///	<summary>
        ///		Fade out element until it disapear
        ///	</summary>
        /// <param name="selector" type="object" Mandatory="yes">selector of efected element</param>
        /// <param name="speed" type="int" Mandatory="yes">Fade out speed.  Values: 1-1000 (lower=faster) </param>
        /// <param name="callback" type="Function" Mandatory="No">Callback method to excute when completed</param>
        this.fadeTo(selector, 0, speed, callback);
    }
    ,
    fadeTo: function(selector, toValue, speed, callback) {
        ///	<summary>
        ///		Fade in/out element to specified opacity
        ///	</summary>
        /// <param name="selector" type="object" Mandatory="yes">selector of effected element</param>
        /// <param name="speed" type="int" Mandatory="yes">Fade speed.  Values: 1-100 (lower=faster) </param>
        /// <param name="toValue" type="int" Mandatory="yes">desired opacity value  Values: 0.1-1 </param>
        /// <param name="callback" type="Function" Mandatory="No">Callback method to excute when completed</param>
        var obj = this.$(selector);
        if (!obj) {
            if (toValue == 0) this.onError("fadeOut: Can't find element");
            else if (toValue == 1) this.onError("fadeIn: Can't find element");
            else this.onError("fadeTo: Can't find element");
            return;
        }

        var prop = this._getArguments(speed, callback);
        this.forEach(obj, function(item, index) {
            var func = function() {
                var p = new Parameter();
                p.duration = prop.duration;
                p.callback = prop.callback;
                jPixeliT._callbackQueue(p);
                p.element = item;
                p.from = p.from = jPixeliT.cssValue(item, "opacity");
                p.startTime = now();
                if (p.from > 1) p.from = p.from / 100;
                p.to = (toValue > 1) ? toValue / 100 : toValue;

                p.overflow = jPixeliT.cssValue(item, "overflow");

                p.element.style.overflow = "hidden";
                p.animationType = "fade";

                p.to = (toValue > 1) ? toValue / 100 : toValue;
                if (p.from > 1) p.from = p.from / 100;
                if (p.from < p.to) {
                    item.style.display = '';
                    p.hide = false;
                }
                else {
                    p.hide = true;
                }
                jPixeliT.animation.step(p);
                p.timer = setInterval(function() { jPixeliT.animation.step(p); }, 13);
            }
            if (jPixeliT._isQueueForElementExists(item)) {
                var q = jPixeliT._getQueueForElement(item);
                q.push(func);
            }
            else { jPixeliT._getQueueForElement(item); func(); }
        });
    }
    ,
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////// Ajax ///////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    Ajax: {
        Timeout: 40000
        ,
        getXhr: function() {
            if (window.ActiveXObject) {
                var msTypes = ['Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
                for (var i = 0, l = msTypes.length; i < l; i++) {
                    try {
                        return new ActiveXObject(msTypes[i]);
                    }
                    catch (ex) { }
                }
            }
            return new window.XMLHttpRequest();
        }
        ,
        // Determines if an XMLHttpRequest was successful or not
        httpSuccess: function(xhr) {
            try {
                // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
                return !xhr.status && location.protocol == "file:" ||
				(xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || xhr.status == 1223;
            } catch (e) { }
            return false;
        },
        executeWebMethod: function ExecutePageMethod(url, webMethodName, async, postData, callBackMethod, objectState) {
            ///	<summary>
            ///		Call a static method with attribute '[System.Web.Services.WebMethod]' or a WebService.
            ///     To use this method, a ScriptManager control must be place in the aspx code
            ///	</summary>
            /// <param name="url" type="String" Mandatory="yes">The url to call</param>
            /// <param name="webMethodName" type="Boolen" Mandatory="yes">Name of the method to excute in the server code</param>
            /// <param name="async" type="Boolen" Mandatory="yes">Excute the call async or sync</param>
            /// <param name="postData" type="String" Mandatory="no">The post data. Must be JSON format !</param>
            /// <param name="callBackMethod" type="function(String,object)" Mandatory="no">The client side mathod to call after the call was completed</param>
            /// <param name="objectState" type="object" Mandatory="no">Object to identify the caller</param>
            var fixedUrl = url;
            var queryString = '';
            var qsStart = url.indexOf('?');
            if (qsStart !== -1) {
                fixedUrl = pageUrl.substr(0, qsStart);
                queryString = url.substr(qsStart);
            }
            fixedUrl += ("/" + encodeURIComponent(webMethodName) + queryString);
            return jPixeliT.Ajax.executeRequest(fixedUrl, async, postData, callBackMethod, objectState, true);
        }
        ,
        executePageMethod: function(pageUrl, pageMethodName, async, postData, callBackMethod, objectState) {
            ///	<summary>
            ///		Excute a method in the code behind in the current page
            ///
            /// Drop the following lines in the desired page On_Load event:
            ///
            ///  // Invoke method that been called from Ajax...
            ///  if (Request.PathInfo != null && Request.PathInfo.Length > 1)
            ///  {
            ///      string methodName = Request.PathInfo.Substring(1);
            ///      System.Reflection.MethodInfo theMethod = this.GetType().GetMethod(methodName);
            ///      object ret = theMethod.Invoke(this, null);
            ///      Response.Clear();
            ///      Response.ContentType = "text/plain";
            ///      Response.Write(ret);
            ///      Response.End();
            ///      return;
            ///  }
            ///
            ///	</summary>
            /// <param name="pageUrl" type="Boolen" Mandatory="yes">The page url</param>
            /// <param name="pageMethodName" type="Boolen" Mandatory="yes">Excute the call async or sync</param>
            /// <param name="async" type="Boolen" Mandatory="yes">Excute the call async or sync</param>
            /// <param name="postData" type="String" Mandatory="no">The post data ('name1=value1&name2=value2')</param>
            /// <param name="callBackMethod" type="function(String,object)" Mandatory="no">The client side mathod to call after the call was completed</param>
            /// <param name="objectState" type="object" Mandatory="no">Object to identify the caller</param>
            var url = pageUrl;
            var queryString = '';
            var qsStart = pageUrl.indexOf('?');
            if (qsStart !== -1) {
                url = pageUrl.substr(0, qsStart);
                queryString = pageUrl.substr(qsStart);
            }
            url += ("/" + encodeURIComponent(pageMethodName) + queryString);
            return jPixeliT.Ajax.executeRequest(url, async, postData, callBackMethod, objectState, false);
        }
        ,
        executeRequest: function(serverUrl, async, postData, callBackMethod, objectState, isJson) {
            ///	<summary>
            ///		Access a server url using 'ajax' technic
            ///	</summary>
            /// <param name="serverUrl" type="String" Mandatory="yes">The page url to call</param>
            /// <param name="async" type="Boolen" Mandatory="yes">Excute the call async or sync</param>
            /// <param name="postData" type="String" Mandatory="no">The post data ('name1=value1&name2=value2' or JSON format)</param>
            /// <param name="callBackMethod" type="function(String,object)" Mandatory="no">The client side mathod to call after the call was completed</param>
            /// <param name="objectState" type="object" Mandatory="no">Object to identify the caller</param>
            /// <param name="isJson" type="Boolean" Mandatory="no">flag if the request is json os not</param>
            var xhr = jPixeliT.Ajax.getXhr();
            var type = (!postData && !isJson) ? "GET" : "POST";
            var requestDone = false;
            var status;
            var returnData;
            xhr.open(type, serverUrl, async);
            try {
                xhr.setRequestHeader('jPixeliT-Ajax', 'true');
                if (type === "POST") {
                    xhr.setRequestHeader("Content-Type", isJson ? "application/json; charset=utf-8" : "application/x-www-form-urlencoded");
                }
                xhr.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT");
                xhr.setRequestHeader("Cache-Control", "no-cache");
            } catch (e) { }

            // Wait for a response to come back
            var onreadystatechange = function(isTimeout) {
                // The request was aborted, clear the interval 
                if (xhr.readyState == 0) {
                    if (intrval) {
                        clearInterval(intrval);
                        intrval = null;
                    }
                    // The transfer is complete and the data is available, or the request timed out
                } else if (!requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout")) {
                    requestDone = true;
                    if (intrval) {
                        clearInterval(intrval);
                        intrval = null;
                    }

                    status = (isTimeout == "timeout") ? "timeout" :
					(!jPixeliT.Ajax.httpSuccess(xhr)) ? "error" : "success";

                    if (status == "success") {
                        try {
                            returnData = xhr.responseText ? xhr.responseText : "";
                        } catch (e) {
                            status = "error";
                        }
                    }

                    if (isTimeout)
                        xhr.abort();

                    if (async) {
                        xhr = null;
                        if (status === "success" && typeof (callBackMethod) === 'function') {
                            callBackMethod(returnData, objectState);
                        }
                        else if (status === "error") {
                            jPixeliT.onError("Ajax unknows error");
                        }
                        else if (status === "timeout") {
                            jPixeliT.onError("Ajax request timeout");
                        }
                    }
                    else {
                        // Make sure that the request was successful
                        if (status === "success") {
                            return returnData;
                        }
                        else {
                            jPixeliT.onError("Ajax request failed");
                            return;
                        }
                    }
                }
            };

            if (async) {
                var intrval = setInterval(onreadystatechange, 13);

                // Timeout checker
                if (jPixeliT.Ajax.Timeout > 0)
                    setTimeout(function() {
                        // Check to see if the request is still happening
                        if (xhr && !requestDone)
                            onreadystatechange("timeout");
                    }, jPixeliT.Ajax.Timeout);
            }
            // Send the data
            try {
                xhr.send(postData);
            } catch (e) {
                jPixeliT.onError("Ajax request filed. Details: \n\r " + e);
            }

            // firefox 1.5 doesn't fire statechange for sync requests
            if (!async)
                return onreadystatechange();
        }
    }
    ,
    formPostData: function() {
        ///	<summary>
        ///		Get all form emlenets & values as string ready to be sent by the Execution methods
        ///	</summary>
        var sb = new StringBuilder();
        var inputElementsCollection = document.getElementsByTagName("input");
        if (inputElementsCollection) {
            jPixeliT._concatFormValues(inputElementsCollection, sb);
        }
        inputElementsCollection = document.getElementsByTagName("textarea");
        if (inputElementsCollection) {
            jPixeliT._concatFormValues(inputElementsCollection, sb);
        }
        inputElementsCollection = document.getElementsByTagName("select");
        if (inputElementsCollection) {
            jPixeliT._concatFormValues(inputElementsCollection, sb);
        }
        inputElementsCollection = document.getElementsByTagName("button");
        if (inputElementsCollection) {
            jPixeliT._concatFormValues(inputElementsCollection, sb);
        }
        if (sb.length > 0)
            return sb.toString().substring(1, sb.length);
        return '';
    }
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////// "Private" helper methods ///////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ,
    _concatFormValues: function(inputElementsCollection, sb) {
        var element, elmNbr;
        for (var index = 0; index < elmNbr; index++) {
            element = inputElementsCollection[index];
            if (element.id !== "__EVENTTARGET" && element.id !== "__EVENTARGUMENT" && element.id !== "__VIEWSTATE")
                sb.append("&" + element.id + "=" + escape(encodeURI(element.value)));
        }
    },
    _funcQueueCache: {}
    ,
    _isQueueForElementExists: function(element) {
        var id = element[queueCacheKey];
        if (!id) return false;
        return this._funcQueueCache[id] !== undefined;
    }
    ,
    _getQueueForElement: function(element) {
        var id = element[queueCacheKey];
        if (!id)
            id = element[queueCacheKey] = ++globalCounter;

        if (!this._funcQueueCache[id]) {
            this._funcQueueCache[id] = [];
        }
        return this._funcQueueCache[id];
    }
    ,
    _removeQueueForElement: function(element) {
        var id = element[queueCacheKey];

        delete this._funcQueueCache[id];
        try {
            delete element[queueCacheKey];
        } catch (e) {
            if (element.removeAttribute)
                element.removeAttribute(queueCacheKey);
        }
    }
    ,
    _elementsIdsCache: {}
    ,
    _getArguments: function(speed, func) {
        if (typeof (speed) === "number") {
            return { duration: speed, callback: func };
        }
        if (typeof (speed) == "string") {
            return { duration: (speed === "slow" ? 600 : 200), callback: func };
        }
        if (toString.call(speed) === "[object Function]") {
            return { duration: 400, callback: speed };
        }
        return { duration: 400, callback: null };
    }
    ,
    _callbackQueue: function(p) {
        p.completed = function() {
            if (p.callback)
                p.callback(p.element);
            var q = jPixeliT._getQueueForElement(p.element);
            if (q.length > 0) {
                var f = q.shift();
                f();
            }
            else {
                jPixeliT._removeQueueForElement(p.element);
            }
        };
    }
    ,
    // A method for quickly swapping in/out CSS properties to get correct calculations
    _swap: function(elem, options, callback) {
        var old = {};
        // Remember the old values, and insert the new ones
        for (var name in options) {

            old[name] = elem.style[name];
            elem.style[name] = options[name];
        }
        callback.call(elem);

        // Revert the old values
        for (var name in options)
            elem.style[name] = old[name];
    },
    String: window.String
    ,
    animation: {
        nextValue: function(p) {
            var t = now();
            if (t >= p.duration + p.startTime) {
                p.value = null;
                return;
            }
            p.state = (t - p.startTime) / p.duration;
            var pos = ((-Math.cos(p.state * Math.PI) / 2) + 0.5);
            return p.from + ((p.to - p.from) * pos);
        }
        ,
        step: function(p) {
            p.value = this.nextValue(p);

            if (typeof (p.value) === "number") {

                if (p.animationType === "slide")
                    p.element.style.height = p.value + 'px';
                else if (p.animationType === "fade")
                    jPixeliT.setOpacity(p.element, p.value);
            }
            else {
                clearInterval(p.timer);
                p.timer = null;

                if (p.animationType === "slide")
                    p.element.style.height = p.to + 'px';
                else if (p.animationType === "fade")
                    jPixeliT.setOpacity(p.element, p.to);

                if (p.toLocaleString > 0 && jPixeliT.attr(p.element, "lh"))
                    jPixeliT.removeAttr(p.element, "lh");
                if (p.hide)
                    p.element.style.display = 'none'
                p.completed();
            }
        }
    }
};

function now() {
    return +new Date;
}

var queueCacheKey = "queue_" + now(), globalCounter = 0;
var defaultView = document.defaultView || {};
var userAgent = navigator.userAgent.toLowerCase();

// Figure out what browser is being used
jPixeliT.browser = {
    version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [0, '0'])[1],
    safari: /webkit/.test(userAgent),
    opera: /opera/.test(userAgent),
    ie: /msie/.test(userAgent) && !/opera/.test(userAgent),
    mozilla: /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent),
    capability: {
        STYLE_ATTRIBUTE: (function() {
            // Check to see if the browser support getAttribute("style")
            var div = document.createElement("div");
            div.style.display = "none";
            div.innerHTML = '<a href="/a" style="color:red;float:left;opacity:.5;">a</a>';
            var a = div.getElementsByTagName("a")[0];
            return /red/.test(a.getAttribute("style"));
        })()
    }
};

jPixeliT.Cache.insert = function(key, value) {
    jPixeliT.Cache[key] = value;
}
jPixeliT.Cache.get = function(key) {
    return jPixeliT.Cache[key];
}
jPixeliT.Cache.contains = function(key) {
    return jPixeliT.isEmpty(jPixeliT.Cache[key]) ? false : true;
}

jPixeliT.String.isNullOrEmpty = String.IsNullOrEmpty = jPixeliT.isEmpty;

jPixeliT.String.format = String.Format = function(format, args) {
    var result = format;
    for (var i = 1; i < arguments.length; i++) {
        if (arguments[i] === undefined) arguments[i] = '';
        result = result.replace(new RegExp('\\{' + (i - 1) + '\\}', 'g'), arguments[i].toString());
    }
    return result;
}
jPixeliT.String.equals = String.Equals = function(a, b, ignoreCase) {
    if (typeof (a) === 'string' && typeof (b) === 'string') {
        if (ignoreCase) {
            if (ignoreCase === true) return (a.toUpperCase() === b.toUpperCase());
        }
    }
    return (a === b);
}


/////////////////////////////////
// String prototypes
/////////////////////////////////

// string.endsWith implementation
//
String.prototype.endsWith = function(suffix, ignoreCase) {
    if (!suffix) return false;
    if (suffix.length > this.length) return false;
    if (ignoreCase) {
        if (ignoreCase === true) {
            return (this.substr(this.length - suffix.length).toUpperCase() === suffix.toUpperCase());
        }
    }
    return (this.substr(this.length - suffix.length) === suffix);
}
//
// string.startWith implementation
//
String.prototype.startsWith = function(prefix, ignoreCase) {
    if (!prefix) return false;
    if (prefix.length > this.length) return false;
    if (ignoreCase) {
        if (ignoreCase === true) {
            return (this.substr(0, prefix.length).toUpperCase() === prefix.toUpperCase());
        }
    }
    return (this.substr(0, prefix.length) === prefix);
}
//
// string.Trim implementation
//
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g, '');
}
/////////////////////////////////////////
// Classes
/////////////////////////////////////////

function Parameter() {
    this.duration = null;
    this.element = null;
    this.callback = null;
    this.timer = null;
    this.value = null;
    this.from = null;
    this.to = null;
    this.startTime = null;
    this.state = null;
    this.overflow = null;
    this.completed = null;
    this.animationType = null;
    this.hide = false;
}

function StringBuilder(value) {
    this._buffer = [];
    this.length = 0;
    if ((value !== undefined && value !== null && value != '')) {
        var val = value.toString();
        this._buffer = [val];
        this.length = val.length;
    }
    this.append = function(value) {
        if ((value !== undefined && value !== null && value !== '')) {
            var val = value.toString();
            this._buffer[this._buffer.length] = val;
            this.length += val.length;
        }
        return this;
    }
    this.appendFormat = function(format, args) {
        var result = format;
        for (var i = 1; i < args.length; i++) {
            if (arguments[i] === undefined) arguments[i] = '';
            result = result.replace(new RegExp('\\{' + (i - 1) + '\\}', 'g'), args[i].toString());
        }
        return this.Append(result);
    }
    this.clear = function() {
        this._buffer = [];
        this.length = 0;
    }
    this.toString = function() {
        return this._buffer.join('');
    }
}