forked from AmpersandJS/ampersand-sync
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathampersand-sync.js
130 lines (111 loc) · 4.35 KB
/
ampersand-sync.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*$AMPERSAND_VERSION*/
var result = require('lodash.result');
var defaults = require('lodash.defaults');
var includes = require('lodash.includes');
var assign = require('lodash.assign');
var xhr = require('xhr');
var qs = require('qs');
// Throw an error when a URL is needed, and none is supplied.
var urlError = function () {
throw new Error('A "url" property or function must be specified');
};
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
var methodMap = {
'create': 'POST',
'update': 'PUT',
'patch': 'PATCH',
'delete': 'DELETE',
'read': 'GET'
};
module.exports = function (method, model, options) {
var type = methodMap[method];
var headers = {};
// Default options, unless specified.
defaults(options || (options = {}), {
emulateHTTP: false,
emulateJSON: false,
// overrideable primarily to enable testing
xhrImplementation: xhr
});
// Default request options.
var params = {type: type};
// Ensure that we have a URL.
if (!options.url) {
options.url = result(model, 'url') || urlError();
}
// Ensure that we have the appropriate request data.
if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
params.json = options.attrs || model.toJSON(options);
}
// If passed a data param, we add it to the URL or body depending on request type
if (options.data && type === 'GET') {
// make sure we've got a '?'
options.url += includes(options.url, '?') ? '&' : '?';
options.url += qs.stringify(options.data);
}
// For older servers, emulate JSON by encoding the request into an HTML-form.
if (options.emulateJSON) {
headers['Content-Type'] = 'application/x-www-form-urlencoded';
params.body = params.json ? {model: params.json} : {};
delete params.json;
}
// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
// And an `X-HTTP-Method-Override` header.
if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
params.type = 'POST';
if (options.emulateJSON) params.body._method = type;
headers['X-HTTP-Method-Override'] = type;
}
// When emulating JSON, we turn the body into a querystring.
// We do this later to let the emulateHTTP run its course.
if (options.emulateJSON) {
params.body = qs.stringify(params.body);
}
// Start setting ajaxConfig options (headers, xhrFields).
var ajaxConfig = (result(model, 'ajaxConfig') || {});
// Combine generated headers with user's headers.
if (ajaxConfig.headers) {
assign(headers, ajaxConfig.headers);
}
params.headers = headers;
//Set XDR for cross domain in IE8/9
if (ajaxConfig.useXDR) {
params.useXDR = true;
}
// Set raw xhr options.
if (ajaxConfig.xhrFields) {
var beforeSend = ajaxConfig.beforeSend;
params.beforeSend = function (req) {
for (var key in ajaxConfig.xhrFields) {
req[key] = ajaxConfig.xhrFields[key];
}
if (beforeSend) return beforeSend.apply(this, arguments);
};
params.xhrFields = ajaxConfig.xhrFields;
} else {
params.beforeSend = ajaxConfig.beforeSend;
}
// Turn a jQuery.ajax formatted request into xhr compatible
params.method = params.type;
var ajaxSettings = assign(params, options);
// Make the request. The callback executes functions that are compatible
// With jQuery.ajax's syntax.
var request = options.xhr = options.xhrImplementation(ajaxSettings, function (err, resp, body) {
if (err || resp.statusCode >= 400) {
if (options.error) return options.error(resp, 'error', err.message || body);
} else {
// Parse body as JSON if a string.
if (body && typeof body === 'string') {
try {
body = JSON.parse(body);
} catch (err) {
if (options.error) return options.error(resp, 'error', err.message);
}
}
if (options.success) return options.success(body, 'success', resp);
}
});
model.trigger('request', model, request, options, ajaxSettings);
request.ajaxSettings = ajaxSettings;
return request;
};