
    var ajaxAction = {
        inProcess: false,
        settings: {
            id: null,
            selector: 'table.content tr.data td input[type=checkbox].selector:checked',
            rowSelector:  "table.content tr.data#row-#id",          // item name selector
            nameSelector: "table.content tr.data#row-#id td:first", // item row selector

            onRun:      null,          // on run event
            onComplite: null,          // on complite event
            onSuccess:  null,          // on success event
            onFail:     null,          // on fail event
            showErrorAlert: true,      //
            processSelector: 'div#process', // default process informer selector
            processClass: 'process',
            post: null
        },
        msg : {
            confirm:     '',
            confirmOne:  '',
            process:     "Processing...",
            processOne:  "Processing '#name'...",
            noItems:     "No items selected.",
            inProcess:   "Action in process... wait and try again.",
            error:       "Error happend!"
        },
        premsg : {},
        preset : {},
        setMsg : function(m) {
            if(m) for(var i in m) {
                this.msg[i] = m[i];
            }
        },
        reset : function () {
            this.set(this.preset);
            this.setMsg(this.premsg);
        },
        fixSettings : function() {
            for(var i in this.settings)
                this.preset[i] = this.settings[i];
            for(var i in this.msg)
                this.premsg[i] = this.msg[i];
        },
        set : function(s, m) {
            if(s) for(var i in s) {
                this.settings[i] = s[i];
            }
            this.setMsg(m);
        },
        run : function(url, s, m) {
             // Если указаны параметры настройки - настраиваем
             this.set(s, m);
             // Проверяем или действия не выполняются
             if(this.inProcess) {
                 alert(this.msg.inProcess);
                 return 0;
             }
             // Если id не указан, но есть selector - используем его
             if(this.settings.id === null && this.settings.selector !== null) {
                 this.settings.id = [];
                 p = this;
                 $(this.settings.selector).each(function(i){
                     p.settings.id[i] = this.id.replace(/^select-([0-9]+)$/, function(all, id) { return id; });
                 });
             }
             if(this.settings.id !== null) {
                 if(!$.isArray(this.settings.id)) this.settings.id = [this.settings.id]; // make array
                 // Получаем объекты над которыми проводятся действия
                 if(!this.settings.id.length) { // Если массив пустой
                     alert(this.msg.noItems);
                     return 0;
                 }
                 // Получаем список ID объектов
                 idsList = "";
                 for(var i = 0, sl = this.settings.id.length; i < sl; i++) {
                    id = this.settings.id[i];
                    if(i == 0) { // Выделяем имя и ID для первого элемента
                        fstID = id;
                        fstName = $(this.settings.nameSelector.replace('#id', id)).text().replace(/^[\s\n\t\r]+/, '').replace(/[\s\n\t\r]+$/, '');
                        if(!fstName) fstName = "ID " + id;
                    }
                    idsList += "/" + id;
                    // Добавляем к класс выполнения к выделенным строкам
                    $(this.settings.rowSelector.replace('#id', id)).addClass(this.settings.processClass);
                 }
                 idCounter = this.settings.id.length;
             } else {
                 idCounter = 2;
                 fstName = "undefined";
                 fstID = null;
                 idsList = "";
             }
             // Если определено сообщение подтверждения, выполняем его
             if(idCounter == 1) cf = this.msg.confirmOne.replace('#name', fstName).replace('#id', fstID); else cf = this.msg.confirm;
             if(cf.length && !confirm(cf)) {
                 $("*." + this.settings.processClass).removeClass(this.settings.processClass);
                 return 0;
             }
             // Если определено событие запуска - запускаем его
             if(this.settings.onRun && !this.settings.onRun()) {
                $("*." + this.settings.processClass).removeClass(this.settings.processClass);
                return 0;
             }
             // Отображаем соощбение
             if(idCounter == 1) pm = this.msg.processOne.replace('#name', fstName).replace('#id', fstID); else pm = this.msg.process;
             this.setProccess(pm);
             this.inProcess = true;
             // Запускаем AJAX запрос
             if(url[url.length - 1] == "/") url = url.substr(0, url.length - 1);
             getReguest = url + idsList + "/ajax";
             if(this.settings.post === null) {
                 $.getJSON(getReguest, this.processData);
             } else {
                 $.post(getReguest, this.settings.post, this.processData, "json");
             }
             return 1;
        },
        processData : function(data) {
             if(ajaxAction.settings.onComplite) ajaxAction.settings.onComplite(data);
             // Скрываем сообщение
             ajaxAction.setProccess(null);
             ajaxAction.inProcess = false;
             if(parseInt(data.result) == 1) {
                 if(ajaxAction.settings.onSuccess) ajaxAction.settings.onSuccess(data);
                 $("*." + ajaxAction.settings.processClass).removeClass(ajaxAction.settings.processClass);
             } else {
                 if(ajaxAction.settings.onFail) ajaxAction.settings.onFail(data);
                 $("*." + ajaxAction.settings.processClass).removeClass(ajaxAction.settings.processClass);
                 if(ajaxAction.settings.showErrorAlert) {
                     if(!data.errors || data.errors.length > 64) {
                         alert(ajaxAction.msg.errors);
                     } else {
                         msg = "";
                         if(!$.isArray(data.errors)) data.errors = [data.errors];
                         for(var i in data.errors) {
                             msg += data.errors[i] + "\n";
                         }
                         alert(msg);
                     }
                 }
             }
        },
        setProccess : function(msg) {
            if(msg === null) {
                $(this.settings.processSelector).hide();
                $("*.proccessDisabled").attr('disabled', false).removeClass('proccessDisabled');
            } else {
                $(this.settings.processSelector).show().text(msg);
                $("input:enabled").addClass("proccessDisabled");
                $("*.proccessDisabled").attr('disabled', true);
            }
        }
    }

    ajaxAction.fixSettings();

