覆盖Request / Request.JSON中的send()方法来追加定义的数据?

时间:2011-11-10 16:24:49

标签: mootools

我的网站大量使用ajax来编辑用户详细信息。我想创建一个管理员模式,以便管理员可以编辑用户的详细信息,而无需以他们身份登录(因此必须知道他们的密码。)

我计划让我网站上的所有用户详情页面都使用参数id。如果页面访问者以管理员身份登录,我希望将此id附加到发送的所有ajax请求的数据中。因此,如果用户以管理员身份登录,我将在mootools库加载后向页面中注入一些javascript,强制Request方法在发出请求时始终携带此id。

我该如何实现?

这是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()函数有任何更改,我的代码将变得不同步(我喜欢使用最新的库版本。)< / p>

有没有更好的方法来做到这一点(我的方法在这里工作)?如何在不更改~20 .js文件的情况下为Request类发送的所有请求添加内容,并在我的网站上的其他位置更改此类的约100次使用?

1 个答案:

答案 0 :(得分:1)

嗯,我会质疑这种做法值得信赖,但无论如何,你可以为你的管理员使用一个特殊的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方法。

另一种解决方案是通过重构来更改Request原型本身,而不是直接编辑它 - 您可以使用mootools-more或Class.refactor中的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 dev会被抓住,数据会在他们不知情的情况下发出,验证器可能会失败等等)。调试可能很困难。将它作为隐式扩展类从维护的角度来看也是有意义的,也是最小的抽象。

不要过于担心未来的兼容性 - mootools 2.0(又名MILK)将采用AMD的方式,旧的mootools代码将从兼容性的角度来看已经过时,尽管API仍然存在)。 1.4分支中可能不会有更多版本。