﻿Type.registerNamespace("Controls");


$(document).ready(function() {
    if (MasterLoad) {
        $.log("AjaxLink runs MasterLoad!");
        MasterLoad(false, $(document));
    }
});



/// <summary>
/// V1.3 Ajax enables a and form tags, default all tags with the class AjaxBehavior and the attribute ajaxTarget. ajaxTarget is the
/// id of the div tag which should receive the result.
/// The plugin should be used on the form or a link
/// if you want to rebind events or other stuff after a ajax update on a specific div please create a function called divid+Load (or use plugin option loadedFunction)
///  i.e. the ajaxTarget is #mydiv the function should be named mydivLoad(isAjaxRequest,ajaxTargetElement,ajaxLinkElement)
/// This method is also called the first time the AjaxLink plugin is called but the argument isAjaxRequest is false then.
/// If the function MasterLoad exist it will be runned on document ready and after each AjaxLink ajaxrequest with the same arguments.
/// This plugin can be used instead of the html helper Ajax.BeginForm and Ajax.Link
/// Depends:
/// jquery-1.4.js
///	ui.core.js
/// ExtendJquery.js
/// jquery.hashchange.js
/// MicrosoftAjax.js
/// URI.js
/// </summary>
Controls.AjaxLink = function() {
    //the constructor runs directly when the js file is loaded
    //run _ready on document ready
    $(document).ready(Function.createDelegate(this, this._ready));
}

Controls.AjaxLink.prototype =
{
    /// <summary>
    /// every ajax links onclick will be stored in a hash table so we can run the correct function if window.location change
    /// </summary>
    _hashArray: new Array(),
    _ready: function() {
        //we want to check the window history after document ready is finished 
        window.setTimeout(Function.createDelegate(this, this._readyLast), 0);
    },
    _readyLast: function() {
        //hook up on the event hashchange
        $(window).hashchange(Function.createDelegate(this, this._hashchange));
        if (location.hash != "") {
            this._hashchange();
        }
    },
    /// <summary>
    /// this metod runs every time the window has location change
    /// And tries to restore the page status.
    /// </summary>    
    _hashchange: function() {
        //   if ($(".Loading").length == 0) //is this neccesary?
        {
            $.log("AjaxLink.found hashchange:" + location.hash);

            if (this._hashArray[location.hash]) {
                $.log("AjaxLink.found saved function!");
                this._hashArray[location.hash]();
            }
        }

    },

    /// <summary>
    /// This metod will be called for each intsnace of the jquery plugin and here we change the behavior of the link or form to use ajax
    /// </summary>    
    _init: function() {
        if (this.options.ajaxTarget == null) {
            this.options.ajaxTarget = this.element.attr("ajaxTarget");
        }
        $.log("AjaxLink._init:ID/class:" + this.element.attr("id") + "/" + this.element.attr("class") + ", ajaxTarget:" + this.options.ajaxTarget);

        if (this.options.ajaxTarget && $(this.options.ajaxTarget).length > 0) //do the attribute exist and points on a available div 
        {
            if (this.element.attr("href")) {
                this.element.click($.createEventDelegate(this, this._startLoadLink));
                $.log("AjaxLink._init:href:" + this.element.attr('href') + ", " + this.element.href());
                if (this.element.attr("ajaxHref")) {
                    this.element.attr('href', '#' + this.element.attr("ajaxHref"));
                }
                else {
                    this.element.attr('href', '#' + this.element.href());
                }
                if (this.options.url == null) {
                    this.options.url = $(this.element).attr("href").substr(1);
                }
                if (this.options.enableHistory) {
                    this._hashArray[this.element.href()] = Function.createDelegate(this, function() {
                        this._startLoadLinkParams(this.options.ajaxTarget, this.options.url);
                    })
                }
            }
            if (this.element.attr("action")) {
                $.log("AjaxLink._init:action:" + this.element.attr("action"));

                if (this.options.url == null) {
                    if (this.element.attr("ajaxAction")) {
                        this.element.attr('action', this.element.attr("ajaxAction"));
                    }
                    this.options.url = $(this.element).attr("action");
                }
                this.element.submit($.createEventDelegate(this, this._startLoadForm));
                //the submit buttons on the ajaxified form have to change form action with the submit button clicked
                //live needed if the target is inside the ajaxified form
                $(":submit", this.element).live("click", $.createEventDelegate(this, this._addSubmitButtonData));
            }


            if (this.options.loadedFunction == null) {
                var loadedFunction = (this.options.ajaxTarget.replace(/[#\.\s]/gi, "")) + "Load";
                if (eval("typeof(" + loadedFunction + ")") != "undefined") {
                    $.log("AjaxLink._init:found function:" + loadedFunction);
                    this.options.loadedFunction = eval(loadedFunction);
                }

            }
            if (this.options.loadedFunction != null) {
                $.log("AjaxLink._init:runs loadedFunction!");
                this.options.loadedFunction(false, $(this.options.ajaxTarget), this.element);
            }
        }
        else {
            $.log("AjaxLink_init.no target, ajaxTarget:" + this.options.ajaxTarget + ",no hits: " + $(this.options.ajaxTarget).length);
        }

    },
    load: function(loadedFunction) {
        if (typeof (loadedFunction) != "undefined") {
            this.options.loadedFunction = loadedFunction;
        }
        if (this.element.attr("action")) {
            this._startLoadForm(this.element, null);
        }
        else {
            this._startLoadLink(this.element, null);

        }
    },
    /// <summary>
    /// After a click this method will be run and load ajax
    /// </summary>    
    _startLoadLink: function(element, event) {
        if (event != null) {
            event.stopPropagation();
            event.preventDefault();
        }
        this.waitFx(this.options.ajaxTarget);
        if (this.options.enableHistory) {
            $.locationHash(this.element.href());
        }
        this._startLoadLinkParams(this.options.ajaxTarget, this.options.url);
        return false;
    },
    /// <summary>
    /// This metod is runned after a click and the function is stored in the hashtable to restore window status
    /// </summary>
    _startLoadLinkParams: function(ajaxTarget, url) {
        var uri = new URI(this.options.url);
        uri.variables["rand"] = (new Date().getTime()).toString();
        url = uri.toString();

        $.log("AjaxLink.loads url:" + url);
        $(ajaxTarget).load(url, null, Function.createDelegate(this, this._endLoad));

    },
    /// <summary>
    /// Runs after a form submit
    /// </summary>
    _startLoadForm: function(element, event) {
        if (event != null) {
            event.stopPropagation();
            event.preventDefault();
        }
        if (Sys.Mvc.FormContext.getValidationForForm) { //is Micorosft validation included?
            var validator = Sys.Mvc.FormContext.getValidationForForm(this.element[0]); //has the form a validator?
            if (typeof (validator) != "undefined") {
                var errorMessages = validator.validate('submit'); //is there any error messages?
                if (Sys.Mvc._validationUtil.arrayIsNullOrEmpty(errorMessages)) {
                    this.SubmitForm();
                }
                else {
                    return false;
                }
            }
        }

        if ($(this.element).data("validator")) { //has the form a jquery validator on it?
            if ($(this.element).valid()) { //is the form valid?
                this.SubmitForm();
            }
        }
        else {
            this.SubmitForm();
        }
    },
    SubmitForm: function() {
        this.waitFx(this.options.ajaxTarget);
        var data = this.element.attr("method").toUpperCase() == "GET" ? this.element.serialize() : this.element.serializeArray();
        var url = this.options.url;
        if (this.element.attr("method").toUpperCase() == "GET") { //fixes i.e. problem
            var uri = new URI(this.options.url);
            uri.variables["rand"] = (new Date().getTime()).toString();
            url = uri.toString();
        }
        $.log("AjaxLink.loads url:" + url + ", with data:" + this.element.serialize());
        $(this.options.ajaxTarget).load(url, data, Function.createDelegate(this, this._endLoad));
    },
    /// <summary>
    /// Runs after a ajax request is done!
    /// </summary>    
    _endLoad: function(responseText, textStatus, XMLHttpRequest) {
        if (textStatus == "error") {
            this.options.onError(responseText);
            return
        } //show the error! or just in debug??
        $.log("AjaxLink._endLoad:responseText:" + responseText.substr(0, 100) + "...");

        this.endWaitFx(this.options.ajaxTarget);
        var context = $(this.options.ajaxTarget);
        if (this.options.runMasterLoadAutomaticly && MasterLoad) {
            MasterLoad(true, context)
        }
        if (this.options.loadedFunction != null) {
            $.log("AjaxLink._endLoad:runs loadedFunction!");
            this.options.loadedFunction(true, context, this.element);
        }
        if (this.options.onSuccess != null) {
            this.options.onSuccess(this.element);
        }
    },
    /// <summary>
    /// marks the target div with an effect
    /// </summary>
    waitFx: function(ajaxTarget) {
        $.log("AjaxLink.waitFx");
        if (this.options.waitFx == null) {
            $(ajaxTarget).addClass(this.options.loadingClass);
        }
        else {
            this.options.waitFx(ajaxTarget);
        }
    },
    endWaitFx: function(ajaxTarget) {
        $.log("AjaxLink.endWaitFx");
        if (this.options.waitFx == null) {
            $(ajaxTarget).removeClass(this.options.loadingClass);
        }
        else {
            this.options.waitFx(ajaxTarget);
        }
    },
    _addSubmitButtonData: function(element, event) {
        $.log("AjaxLink._addSubmitButtonData");
        var uri = new URI(this.options.url);
        //first delete from action if a other submit button has been clicked
        $(":submit", this.element).each(function(i) {
            uri.variables[$(this).attr("name")] = null;
        });
        //add clicked button value to action
        uri.variables[$(element).attr("name")] = $(element).attr("value");
        this.options.url = uri.toString();

    },
    /*    changeOptions: function(options)
    {
    jQuery.extend(this.options, options);
    },*/
    defaults:
    {
        loadingClass: "Loading", //this class will be added on ajaxtarget div when loading if option waityFx is not sett.
        waitFx: null, //A function for loading effect,default will class Loading be added on target div
        waitEndFx: null, //A function for end loading effect
        loadedFunction: null, //A function to run after loading, default will it check if a function with name targetId+Load exists and runs it
        ajaxTarget: null, //string default will the attribute ajaxTarget on the a or form tag be used
        onSuccess: null, //function that is run after successful post
        url: null, //string default will the attribute href or action on the a or form tag be used
        runMasterLoadAutomaticly: true, //if true the function MasterLoad will be evaluated on the updated div after every load
        enableHistory: true, //true if the link action should be saved in the history. i.e. a buy should not be done multiple if the user hits the back button.
        onError: function(responseText) { alert(responseText); }
    }
}

Controls.AjaxLink.registerClass('Controls.AjaxLink', null, Sys.IDisposable);

$.registerAsWidget(Controls.AjaxLink);


