-
Notifications
You must be signed in to change notification settings - Fork 4
/
backbone.drupal.js
328 lines (277 loc) · 10.6 KB
/
backbone.drupal.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
// backbone.drupal 0.1.0
//
// (c) 2014 enzo - Eduardo Garcia enzo@enzolutions
// Licensed under the MIT license.
// * TODO Add .TaxonomyCollection with support for taxonomy listings.
// * TODO Add .SearchCollection with support for search results.
// * TODO Add configurable endpoint path, loaded via Drupal.settings.
// (will remove hard dependency on backbone_base feature)
// * TODO Add .FieldViewCollection for working with field views.
// Starts with the Backbone.Drupal. Constructor, currently a no-op
Backbone.Drupal = function() {};
// Backbone.Drupal.Auth Implement authentication against webservices
// ToDo: Validate if this method work for Drupal Restws module
Backbone.Drupal.Auth = (function(Backbone, $, _){
function Auth(options) {
// PUBLIC METHODS
function initialize(options) {
this.attributes = _.extend({}, defaults(), options);
}
// Set defaults. These are the only attributes allowed.
function defaults() {
return { crossDomain: false };
}
// Set attributes
initialize(options);
}
_.extend(Auth.prototype, {
// PUBLIC METHODS
// Set an attribute or a collection of attributes
set: function(attrs, newValue) {
if (_.isString(attrs) && !_.isUndefined(this.defaults()[attrs])) {
this._setAttribute(attrs, newValue);
} else {
this._setAttributes(attrs);
}
},
// Get the value of an attribute
get: function(attrName) {
return (this.attributes[attrName]);
}.bind(this),
login: function(username, password) {
// Enable attributes to be used in sucess call
var attributes = this.attributes;
var status = false;
var restEndpoint = Backbone.Drupal.restEndpoint.root + (Backbone.Drupal.restEndpoint.root.charAt(Backbone.Drupal.restEndpoint.root.length - 1) === '/' ? '' : '/');
if(Backbone.Drupal.restEndpoint.version == 8) {
// Prepare further calls to use Basic Auth againt drupal 8 and set a cookie
var settings = {
beforeSend: function (request) {
request.setRequestHeader ('Authorization', 'Basic ' + btoa(username + ':' + password));
//request.setRequestHeader ('Accept', 'application/json');
request.setRequestHeader ( "Content-type", "application/x-www-form-urlencoded" );
}
};
if(attributes.crossDomain) {
/*settings.xhrFields = {
withCredentials: true
};*/
//settings.crossDomain = true;
}
// Define specific parametres to be used in all future request.
$.ajaxSetup(settings);
status=true;
}
else if(Backbone.Drupal.restEndpoint.version != 8) {
// Call user/login end point to get CSR token an use in following calls
jQuery.ajax({
async: false,
url : restEndpoint + 'user/login' + Backbone.Drupal.restEndpoint.dataType,
type : 'post',
data : 'username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password),
//dataType : 'json',
error: function(XMLHttpRequest, textStatus, errorThrown) {
return false;
},
success : function(data) {
var settings = {
beforeSend: function (request) {
request.setRequestHeader("X-CSRF-Token", data.token);
}
};
if(attributes.crossDomain) {
settings.xhrFields = {
withCredentials: true
};
settings.crossDomain = true;
}
// Define specific parametres to be used in all future request.
$.ajaxSetup(settings);
status=true;
}
});
}
return status;
}.bind(this),
// PRIVATE METHODS
// Set a single attribute
_setAttribute: function(key, val) {
this.attributes[key] = val;
}.bind(this),
// Setting a collection of attributes
_setAttributes: function(attrs) {
_.each(attrs,
function(val, key) {
if (!_.isUndefined(this.defaults[key])) {
this.attributes[key] = val;
}
},
this);
}.bind(this),
});
return Auth;
})(Backbone, jQuery, _);
Backbone.Drupal.Models = {};
// Base objects for Backbone Drupal implementation.
// ---
// ### Backbone.Drupal.Model
//
// Extend the Model object with default Drupal Services settings and methods.
// These are defaults for interfacing with all Service module's providers.
Backbone.Drupal.Models.Base = Backbone.Model.extend({
// #### initialize()
//
// Set up defaults for attribute processing.
initialize: function() {
this.toJSONProcessors = this.JSONProcessors || {};
this.noSaveAttributes = this.noSaveAttributes || [];
_(this).bindAll('setNoSaveAttributes', 'getNoSaveAttributes', 'addNoSaveAttributes', 'toJSON');
},
// #### toJSON: Enhanced JSON processing function
// Allows us to specify and override processing functions
// for a single field. Most of this customization will actuallly
// be in the backend specific functions, as the preparation is
// needed to prepare for communication with the server.
toJSON: function() {
return _(this.attributes)
.chain()
// Filter out any attributes that should not be sent.
.objReject(function(value, name, list) {
return (_(this.noSaveAttributes).indexOf(name) >= 0);
}, this)
// Transform any attribute values that need processing.
.objMap(this.toJSONAttribute, this)
.value();
},
// #### setNoSaveAttributes: specify attributes we should not send on save
// Some backends reject our request when we send attributes we can't change.
// This function takes a single attribute name or an array of attribute
// names and will filter those attributes out on save.
setNoSaveAttributes: function(attributes) {
this.noSaveAttributes = attributes;
},
addNoSaveAttributes: function(attributes) {
this.noSaveAttributes = _(this.noSaveAttributes).union(attributes);
},
getNoSaveAttributes: function(attributes) {
return this.noSaveAttributes;
},
// ### setToJSONProcessor()
//
// Use this method to set a custom JSON processor for a given
// attribute. Currently all overrides are attribute name based,
// so provide the name of the attribute (e.g. "title") and
// a function to use (either anonymous func or a method on your
// model).
setToJSONProcessor: function(attributeName, processorFunction) {
this.toJSONProcessors[attributeName] = processorFunction;
},
// #### toJSONAttribute: process attribute into JSON if process funciton given.
toJSONAttribute: function(attributeValue, attributeName) {
if (typeof this.toJSONProcessors !== 'undefined') {
if (this.toJSONProcessors[attributeName]) {
attributeValue = this.toJSONProcessors[attributeName].call(this, attributeValue);
}
}
return attributeValue;
},
// Both Services and RESTWS use the format
// "{endpoint}/{resource-type}/{id}.json, only {endpoint} is empty for
// RESTWS.
// We don't include the collection stuff here, since Drupal collections are
// indpendent of their objects.
url: function() {
// Modified from Backbone.js to ignore collection and add ".format" extension.
var restEndpoint = Backbone.Drupal.restEndpoint.root + (Backbone.Drupal.restEndpoint.root.charAt(Backbone.Drupal.restEndpoint.root.length - 1) === '/' ? '' : '/');
var base = restEndpoint + this.urlSource;
if (this.isNew()) { return base; }
var url_endpoint = base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.get(this.idAttribute));
if(Backbone.Drupal.restEndpoint.version != 8) {
// Add .json for format here.
url_endpoint = url_endpoint + urlBackbone.Drupal.restEndpoint.dataType;
}
return url_endpoint;
},
// TODO: evaluate moving all of this to Views.Base
// In terms of proper architecture, model should not have views-specific functions.
// Prepare an object for default rendering
// arg1: whitelist, array of whitelisted properties (to render)
// TODO: add blacklist
renderAttributes: function(whitelist, blacklist) {
var properties = _.clone(this.attributes);
if (_.isArray(whitelist)) {
properties = _(properties).pick(whitelist);
}
return properties;
}
});
Backbone.Drupal.Collections = {};
// ### Backbone.Drupal.Collection
//
// Currently just sets the endpoint for all collections.
//
// TODO fix scoping issue that causes params to bleed between children of this object.
// e.g. if you have two NodeViewCollections, setting limit on one sets on both.
Backbone.Drupal.Collections.Base = Backbone.Collection.extend({
// #### initialize()
//
// We bind the param functions to this on initialize, to avoid chain
// inheritance issues.
//
// *NOTE* if you subclass this and have an initialize function in your
// subclass, you need to execute Drupal.Backbone.Collection.initialize
// explicitly.
initialize: function(opts) {
_.bindAll(this, 'setParam', 'setParams', 'getParams');
this.params = {};
},
// #### params
//
// Drupal collections are stateful, we store params in the collection.
params: {},
// #### setParam(string, string)
//
// Setter for individual params, called as setParam('name','value').
setParam: function(paramName, paramValue) {
this.params[paramName] = paramValue;
},
// #### setParams(object)
//
// Setter for multiple params, passed as object with key/value pairs.
setParams: function(params) {
if (typeof(this.params) !== 'object') {
this.params = object;
}
if (typeof(params) === 'object') {
_.extend(
this.params,
params
);
}
},
// #### getParams()
//
// Getter. Currently just returns param object property.
getParams: function() {
return this.params;
},
// #### fetch() implementation
//
// Fetch method passes params as data in AJAX call.
fetch: function(options) {
options = options ? options : {};
if (options.data) {
// Allow options.data to override any params.
_.defaults(options.data, this.getParams());
}
else if (this.getParams()) {
options.data = this.getParams();
}
// Call Super fetch function with options array including any collection params.
Backbone.Collection.prototype.fetch.call(this, options);
},
url: function() {
var url_endpoint = Backbone.Drupal.restEndpoint.root + '/' + this.urlSource;
return url_endpoint;
},
});