Переопределить метод send () в Request / Request.JSON для добавления определенных данных? - PullRequest
0 голосов
/ 10 ноября 2011

Мой сайт активно использует ajax для таких вещей, как редактирование пользовательских данных. Я хочу создать режим администратора, чтобы администратор мог редактировать данные пользователя, не входя под ним (и, следовательно, не узнавая их пароль).

Я планирую, чтобы все страницы сведений о пользователе на моем сайте принимали параметр id. Если посетитель страницы вошел в систему как администратор, я хочу, чтобы этот идентификатор был добавлен к данным всех отправленных запросов ajax. Поэтому, если пользователь вошел в систему как администратор, после загрузки библиотеки mootools я добавлю некоторый JavaScript на страницу, что заставит метод Request всегда переносить этот идентификатор при выполнении запросов.

Как мне это реализовать?

Это метод отправки для класса запроса:

send: function(options){
    if (!this.check(options)) return this;

    this.options.isSuccess = this.options.isSuccess || this.isSuccess;
    this.running = true;

    var type = typeOf(options);
    if (type == 'string' || type == 'element') options = {data: options};

    var old = this.options;
    options = Object.append({data: old.data, url: old.url, method: old.method}, options);
    var data = options.data, url = String(options.url), method = options.method.toLowerCase();

    switch (typeOf(data)){
        case 'element': data = document.id(data).toQueryString(); break;
        case 'object': case 'hash': data = Object.toQueryString(data);
    }

    //---------
    //LOOK HERE
    //---------
    if (this.options.format){
        var format = 'format=' + this.options.format;
        data = (data) ? format + '&' + data : format;
    }

    if (this.options.emulation && !['get', 'post'].contains(method)){
        var _method = '_method=' + method;
        data = (data) ? _method + '&' + data : _method;
        method = 'post';
    }

    if (this.options.urlEncoded && ['post', 'put'].contains(method)){
        var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
        this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding;
    }

    if (!url) url = document.location.pathname;

    var trimPosition = url.lastIndexOf('/');
    if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);

    if (this.options.noCache)
        url += (url.contains('?') ? '&' : '?') + String.uniqueID();

    if (data && method == 'get'){
        url += (url.contains('?') ? '&' : '?') + data;
        data = null;
    }

    var xhr = this.xhr;
    if (progressSupport){
        xhr.onloadstart = this.loadstart.bind(this);
        xhr.onprogress = this.progress.bind(this);
    }

    xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
    if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;

    xhr.onreadystatechange = this.onStateChange.bind(this);

    Object.each(this.headers, function(value, key){
        try {
            xhr.setRequestHeader(key, value);
        } catch (e){
            this.fireEvent('exception', [key, value]);
        }
    }, this);

    this.fireEvent('request');
    xhr.send(data);
    if (!this.options.async) this.onStateChange();
    if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this);
    return this;
}

В отмеченном мною месте метод добавляет дополнительные данные к запросам. Я думал, что это будет хорошим местом для добавления моего кода. Я мог бы переписать метод, чтобы включить что-то вроде этого:

if (_USER_ID_TO_EDIT){
    var id= 'userIdToEdit=' + _USER_ID_TO_EDIT;
data = (data) ? id+ '&' + data : id;
}

Однако это не очень удачное решение, потому что это означает, что если в библиотеке есть какие-либо изменения в функции send (), мой код станет не синхронизированным (мне нравится использовать последнюю версию библиотеки.)

Есть ли лучший способ сделать это (и сработает ли мой метод здесь)? Как добавить содержимое ко всем запросам, отправленным классом Request, не изменяя ~ 20 файлов .js и ~ 100 вариантов использования этого класса в других местах на моем сайте?

1 Ответ

1 голос
/ 10 ноября 2011

эмм, я бы сомневался в надежности этой практики, но в любом случае вы можете просто использовать специальный экземпляр Request для вашего администратора:

Request.admin = new Class({

    Extends: Request,

    initialize: function(options) {
       this.parent(options);
    },

    send: function(options) {
        // example, add to the data being sent admin id and a delay 
        options = Object.merge({
            data: {
                adminid: "foo",
                delay: 5 // testing with 5 sec delay
            }
        }, options || this.options);
        this.parent(options);
    }

});

new Request.admin({
    url: '/echo/html/',
    data: {
        html: "<p>original data here. foobar</p>"        
    },
    method: 'post',
    onComplete: function() {
        document.id('target').set("html", this.response.text);
    }
}).send();

http://jsfiddle.net/dimitar/x2pBu/

Я бы посчитал это лучшей практикой.Вам также необходимо переопределить метод .get.

Другое решение состоит в том, чтобы изменить сам прототип запроса путем его рефакторинга, а не редактирования напрямую - вы можете использовать Class.refactor из mootools-more или Request.implement({send: ... }); так что все подклассы Request извлекают из этого выгоду (Request.HTML и Request.JSON, Request.Queue и т. д.).

Вы даже можете сделать var orig = Request.prototype.send; Request.prototype.send = function() {... something to options; orig.call(this, options); } и т. д. и т. д.

Недостаток такого родаИзменения в том, что вы получаете неожиданное поведение в своем классе Request (т.е. разработчик mootools, который ожидает, что определенные вещи будут обнаружены, данные выйдут без их ведома, валидаторы могут потерпеть неудачу и т. д. и т. д.).Это может быть трудно для отладки.Наличие в качестве неявного расширенного класса также имеет смысл с точки зрения обслуживания, минимальной абстракции.

не стоит слишком беспокоиться о будущей совместимости - mootools 2.0 (также известный как MILK) пойдет по пути AMD, а старый код mootools будетустарел с точки зрения совместимости, хотя API останется).Вероятно, в ветке 1.4 не будет больше выпусков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...