@converse/skeletor 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +38 -25
  2. package/dist/skeletor.js +10413 -6875
  3. package/dist/skeletor.js.map +1 -1
  4. package/dist/skeletor.min.js +74 -3
  5. package/dist/skeletor.min.js.map +1 -1
  6. package/package.json +23 -12
  7. package/src/collection.js +540 -395
  8. package/src/drivers/sessionStorage.js +226 -232
  9. package/src/element.js +132 -82
  10. package/src/eventemitter.js +187 -0
  11. package/src/helpers.js +148 -114
  12. package/src/{main.js → index.js} +21 -17
  13. package/src/listening.js +81 -0
  14. package/src/model.js +340 -240
  15. package/src/storage.js +223 -241
  16. package/src/types/collection.d.ts +366 -0
  17. package/src/types/collection.d.ts.map +1 -0
  18. package/src/types/drivers/sessionStorage.d.ts +37 -0
  19. package/src/types/drivers/sessionStorage.d.ts.map +1 -0
  20. package/src/types/element.d.ts +115 -0
  21. package/src/types/element.d.ts.map +1 -0
  22. package/src/types/eventemitter.d.ts +93 -0
  23. package/src/types/eventemitter.d.ts.map +1 -0
  24. package/src/types/helpers.d.ts +62 -0
  25. package/src/types/helpers.d.ts.map +1 -0
  26. package/src/types/index.d.ts +19 -0
  27. package/src/types/index.d.ts.map +1 -0
  28. package/src/types/listening.d.ts +40 -0
  29. package/src/types/listening.d.ts.map +1 -0
  30. package/src/types/model.d.ts +230 -0
  31. package/src/types/model.d.ts.map +1 -0
  32. package/src/types/storage.d.ts +35 -0
  33. package/src/types/storage.d.ts.map +1 -0
  34. package/src/types/utils/events.d.ts +28 -0
  35. package/src/types/utils/events.d.ts.map +1 -0
  36. package/src/utils/events.js +174 -0
  37. package/src/drivers/indexeddb-getitems.js~ +0 -1116
  38. package/src/drivers/indexeddb.js~ +0 -1115
  39. package/src/events.js +0 -328
  40. package/src/history.js +0 -301
  41. package/src/overview.js +0 -191
  42. package/src/router.js +0 -119
  43. package/src/storage.js~ +0 -269
  44. package/src/view.js +0 -267
package/src/model.js CHANGED
@@ -1,159 +1,217 @@
1
- // Backbone.js 1.4.0
2
- // (c) 2010-2019 Jeremy Ashkenas and DocumentCloud
3
- // Backbone may be freely distributed under the MIT license.
4
-
5
- // Model
6
- // -----
7
- // **Models** are the basic data object in the framework --
8
- // frequently representing a row in a table in a database on your server.
9
- // A discrete chunk of data and a bunch of useful, related methods for
10
- // performing computations and transformations on that data.
11
-
12
- // Create a new model with the specified attributes. A client id (`cid`)
13
- // is automatically generated and assigned for you.
14
-
15
- import {
16
- getResolveablePromise,
17
- getSyncMethod,
18
- inherits,
19
- urlError,
20
- wrapError
21
- } from './helpers.js';
22
- import { Events } from './events.js';
23
- import clone from "lodash-es/clone.js";
24
- import defaults from "lodash-es/defaults.js";
25
- import defer from "lodash-es/defer.js";
26
- import escape from "lodash-es/escape.js";
27
- import extend from "lodash-es/extend.js";
28
- import has from "lodash-es/has.js";
29
- import invert from "lodash-es/invert.js";
30
- import isElement from "lodash-es/isElement.js";
31
- import isEmpty from "lodash-es/isEmpty.js";
32
- import isEqual from "lodash-es/isEqual.js";
33
- import isFunction from "lodash-es/isFunction.js";
34
- import iteratee from "lodash-es/iteratee.js";
35
- import omit from "lodash-es/omit.js";
36
- import pick from "lodash-es/pick.js";
37
- import result from "lodash-es/result.js";
38
- import uniqueId from "lodash-es/uniqueId.js";
39
-
40
-
41
- export const Model = function(attributes, options) {
42
- let attrs = attributes || {};
43
- options || (options = {});
44
- this.preinitialize.apply(this, arguments);
45
- this.cid = uniqueId(this.cidPrefix);
46
- this.attributes = {};
47
- if (options.collection) this.collection = options.collection;
48
- if (options.parse) attrs = this.parse(attrs, options) || {};
49
- const default_attrs = result(this, 'defaults');
50
- attrs = defaults(extend({}, default_attrs, attrs), default_attrs);
51
- this.set(attrs, options);
52
- this.changed = {};
53
- this.initialize.apply(this, arguments);
54
- };
55
-
56
- Model.extend = inherits;
57
-
58
- // Attach all inheritable methods to the Model prototype.
59
- Object.assign(Model.prototype, Events, {
60
-
61
- // A hash of attributes whose current and previous value differ.
62
- changed: null,
63
-
64
- // The value returned during the last failed validation.
65
- validationError: null,
66
-
67
- // The default name for the JSON `id` attribute is `"id"`. MongoDB and
68
- // CouchDB users may want to set this to `"_id"`.
69
- idAttribute: 'id',
70
-
71
- // The prefix is used to create the client id which is used to identify models locally.
72
- // You may want to override this if you're experiencing name clashes with model ids.
73
- cidPrefix: 'c',
74
-
75
- // preinitialize is an empty function by default. You can override it with a function
76
- // or object. preinitialize will run before any instantiation logic is run in the Model.
77
- preinitialize: function(){},
78
-
79
- // Initialize is an empty function by default. Override it with your own
80
- // initialization logic.
81
- initialize: function(){},
82
-
83
- // Return a copy of the model's `attributes` object.
84
- toJSON: function(options) {
1
+ import { getResolveablePromise, getSyncMethod, urlError, wrapError } from './helpers.js';
2
+ import clone from 'lodash-es/clone.js';
3
+ import defaults from 'lodash-es/defaults.js';
4
+ import defer from 'lodash-es/defer.js';
5
+ import has from 'lodash-es/has.js';
6
+ import invert from 'lodash-es/invert.js';
7
+ import isEmpty from 'lodash-es/isEmpty.js';
8
+ import isEqual from 'lodash-es/isEqual.js';
9
+ import iteratee from 'lodash-es/iteratee.js';
10
+ import omit from 'lodash-es/omit.js';
11
+ import pick from 'lodash-es/pick.js';
12
+ import result from 'lodash-es/result.js';
13
+ import uniqueId from 'lodash-es/uniqueId.js';
14
+ import EventEmitter from './eventemitter.js';
15
+
16
+ /**
17
+ * @typedef {import('./collection.js').Collection} Collection
18
+ * @typedef {Record.<string, any>} Attributes
19
+ *
20
+ * @typedef {Record.<string, any>} Options
21
+ * @property {boolean} [validate]
22
+ *
23
+ * @typedef {Record.<string, any>} ModelOptions
24
+ * @property {Collection} [collection]
25
+ * @property {boolean} [parse]
26
+ * @property {boolean} [unset]
27
+ * @property {boolean} [silent]
28
+ */
29
+
30
+ /**
31
+ * **Models** are the basic data object in the framework --
32
+ * frequently representing a row in a table in a database on your server.
33
+ * A discrete chunk of data and a bunch of useful, related methods for
34
+ * performing computations and transformations on that data.
35
+ */
36
+ class Model extends EventEmitter(Object) {
37
+ /**
38
+ * Create a new model with the specified attributes. A client id (`cid`)
39
+ * is automatically generated and assigned for you.
40
+ * @param {Attributes} [attributes]
41
+ * @param {ModelOptions} [options]
42
+ */
43
+ constructor(attributes, options) {
44
+ super();
45
+ let attrs = attributes || {};
46
+ options || (options = {});
47
+ this.preinitialize.apply(this, arguments);
48
+ this.cid = uniqueId(this.cidPrefix);
49
+ this.attributes = {};
50
+
51
+ // The value returned during the last failed validation.
52
+ this.validationError = null;
53
+
54
+ if (options.collection) this.collection = options.collection;
55
+ if (options.parse) attrs = this.parse(attrs, options) || {};
56
+
57
+ const default_attrs = result(this, 'defaults');
58
+ attrs = defaults(Object.assign({}, default_attrs, attrs), default_attrs);
59
+
60
+ this.set(attrs, options);
61
+
62
+ this.initialize.apply(this, arguments);
63
+
64
+ // A hash of attributes whose current and previous value differ.
65
+ this.changed = {};
66
+ }
67
+
68
+ /**
69
+ * @param {Storage} storage
70
+ */
71
+ set browserStorage(storage) {
72
+ this._browserStorage = storage;
73
+ }
74
+
75
+ /**
76
+ * @returns {Storage} storage
77
+ */
78
+ get browserStorage() {
79
+ return this._browserStorage;
80
+ }
81
+
82
+ /**
83
+ * The default name for the JSON `id` attribute is `"id"`. MongoDB and
84
+ * CouchDB users may want to set this to `"_id"` (by overriding this getter
85
+ * in a subclass).
86
+ */
87
+ // eslint-disable-next-line class-methods-use-this
88
+ get idAttribute() {
89
+ return 'id';
90
+ }
91
+
92
+ /**
93
+ * The prefix is used to create the client id which is used to identify models locally.
94
+ * You may want to override this if you're experiencing name clashes with model ids.
95
+ */
96
+ // eslint-disable-next-line class-methods-use-this
97
+ get cidPrefix() {
98
+ return 'c';
99
+ }
100
+
101
+ /**
102
+ * preinitialize is an empty function by default. You can override it with a function
103
+ * or object. preinitialize will run before any instantiation logic is run in the Model.
104
+ */
105
+ // eslint-disable-next-line class-methods-use-this
106
+ preinitialize() {}
107
+
108
+ /**
109
+ * Initialize is an empty function by default. Override it with your own
110
+ * initialization logic.
111
+ * @param {Attributes} [attrs]
112
+ * @param {ModelOptions} [options]
113
+ */
114
+ initialize(attrs, options) {}
115
+
116
+ /**
117
+ * @param {object} attrs
118
+ * @param {object} [options]
119
+ * @returns {string} The validation error message
120
+ */
121
+ validate(attrs, options) {
122
+ return '';
123
+ }
124
+
125
+ /**
126
+ * Return a copy of the model's `attributes` object.
127
+ */
128
+ toJSON() {
85
129
  return clone(this.attributes);
86
- },
130
+ }
87
131
 
88
- // Proxy `Backbone.sync` by default -- but override this if you need
89
- // custom syncing semantics for *this* particular model.
90
- sync: function(method, model, options) {
91
- return getSyncMethod(this)(method, model, options);
92
- },
132
+ /**
133
+ * Override this if you need custom syncing semantics for *this* particular model.
134
+ * @param {'create'|'update'|'patch'|'delete'|'read'} method
135
+ * @param {Model} model
136
+ * @param {Options} options
137
+ */
138
+ // eslint-disable-next-line class-methods-use-this
139
+ sync(method, model, options) {
140
+ return getSyncMethod(model)(method, model, options);
141
+ }
93
142
 
94
- // Get the value of an attribute.
95
- get: function(attr) {
143
+ /**
144
+ * Get the value of an attribute.
145
+ * @param {string} attr
146
+ */
147
+ get(attr) {
96
148
  return this.attributes[attr];
97
- },
149
+ }
98
150
 
99
- keys: function() {
151
+ keys() {
100
152
  return Object.keys(this.attributes);
101
- },
153
+ }
102
154
 
103
- values: function() {
155
+ values() {
104
156
  return Object.values(this.attributes);
105
- },
157
+ }
106
158
 
107
- pairs: function() {
159
+ pairs() {
108
160
  return this.entries();
109
- },
161
+ }
110
162
 
111
- entries: function() {
163
+ entries() {
112
164
  return Object.entries(this.attributes);
113
- },
165
+ }
114
166
 
115
- invert: function() {
167
+ invert() {
116
168
  return invert(this.attributes);
117
- },
169
+ }
118
170
 
119
- pick: function(...args) {
171
+ pick(...args) {
120
172
  if (args.length === 1 && Array.isArray(args[0])) {
121
173
  args = args[0];
122
174
  }
123
175
  return pick(this.attributes, args);
124
- },
176
+ }
125
177
 
126
- omit: function(...args) {
178
+ omit(...args) {
127
179
  if (args.length === 1 && Array.isArray(args[0])) {
128
180
  args = args[0];
129
181
  }
130
182
  return omit(this.attributes, args);
131
- },
183
+ }
132
184
 
133
- isEmpty: function() {
185
+ isEmpty() {
134
186
  return isEmpty(this.attributes);
135
- },
136
-
137
- // Get the HTML-escaped value of an attribute.
138
- escape: function(attr) {
139
- return escape(this.get(attr));
140
- },
187
+ }
141
188
 
142
- // Returns `true` if the attribute contains a value that is not null
143
- // or undefined.
144
- has: function(attr) {
189
+ /**
190
+ * Returns `true` if the attribute contains a value that is not null
191
+ * or undefined.
192
+ * @param {string} attr
193
+ */
194
+ has(attr) {
145
195
  return this.get(attr) != null;
146
- },
196
+ }
147
197
 
148
- // Special-cased proxy to lodash's `matches` method.
149
- matches: function(attrs) {
198
+ /**
199
+ * Special-cased proxy to lodash's `matches` method.
200
+ * @param {Attributes} attrs
201
+ */
202
+ matches(attrs) {
150
203
  return !!iteratee(attrs, this)(this.attributes);
151
- },
204
+ }
152
205
 
153
- // Set a hash of model attributes on the object, firing `"change"`. This is
154
- // the core primitive operation of a model, updating the data and notifying
155
- // anyone who needs to know about the change in state. The heart of the beast.
156
- set: function(key, val, options) {
206
+ /**
207
+ * Set a hash of model attributes on the object, firing `"change"`. This is
208
+ * the core primitive operation of a model, updating the data and notifying
209
+ * anyone who needs to know about the change in state. The heart of the beast.
210
+ * @param {string|Object} key
211
+ * @param {string|Object} [val]
212
+ * @param {Options} [options]
213
+ */
214
+ set(key, val, options) {
157
215
  if (key == null) return this;
158
216
 
159
217
  // Handle both `"key", value` and `{key: value}` -style arguments.
@@ -171,10 +229,10 @@ Object.assign(Model.prototype, Events, {
171
229
  if (!this._validate(attrs, options)) return false;
172
230
 
173
231
  // Extract attributes and options.
174
- const unset = options.unset;
175
- const silent = options.silent;
176
- const changes = [];
177
- const changing = this._changing;
232
+ const unset = options.unset;
233
+ const silent = options.silent;
234
+ const changes = [];
235
+ const changing = this._changing;
178
236
  this._changing = true;
179
237
 
180
238
  if (!changing) {
@@ -184,7 +242,7 @@ Object.assign(Model.prototype, Events, {
184
242
 
185
243
  const current = this.attributes;
186
244
  const changed = this.changed;
187
- const prev = this._previousAttributes;
245
+ const prev = this._previousAttributes;
188
246
 
189
247
  // For each `set` attribute, update or delete the current value.
190
248
  for (const attr in attrs) {
@@ -195,7 +253,7 @@ Object.assign(Model.prototype, Events, {
195
253
  } else {
196
254
  delete changed[attr];
197
255
  }
198
- unset ? delete current[attr] : current[attr] = val;
256
+ unset ? delete current[attr] : (current[attr] = val);
199
257
  }
200
258
 
201
259
  // Update the `id`.
@@ -214,7 +272,7 @@ Object.assign(Model.prototype, Events, {
214
272
  if (changing) return this;
215
273
  if (!silent) {
216
274
  while (this._pending) {
217
- options = this._pending;
275
+ options = /** @type {Options} */ (this._pending);
218
276
  this._pending = false;
219
277
  this.trigger('change', this, options);
220
278
  }
@@ -222,36 +280,52 @@ Object.assign(Model.prototype, Events, {
222
280
  this._pending = false;
223
281
  this._changing = false;
224
282
  return this;
225
- },
283
+ }
226
284
 
227
- // Remove an attribute from the model, firing `"change"`. `unset` is a noop
228
- // if the attribute doesn't exist.
229
- unset: function(attr, options) {
230
- return this.set(attr, undefined, extend({}, options, {unset: true}));
231
- },
285
+ /**
286
+ * Remove an attribute from the model, firing `"change"`. `unset` is a noop
287
+ * if the attribute doesn't exist.
288
+ * @param {string} attr
289
+ * @param {Options} [options]
290
+ */
291
+ unset(attr, options) {
292
+ return this.set(attr, undefined, Object.assign({}, options, { unset: true }));
293
+ }
232
294
 
233
- // Clear all attributes on the model, firing `"change"`.
234
- clear: function(options) {
295
+ /**
296
+ * Clear all attributes on the model, firing `"change"`.
297
+ * @param {Options} options
298
+ */
299
+ clear(options) {
235
300
  const attrs = {};
236
301
  for (const key in this.attributes) attrs[key] = undefined;
237
- return this.set(attrs, extend({}, options, {unset: true}));
238
- },
302
+ return this.set(attrs, Object.assign({}, options, { unset: true }));
303
+ }
239
304
 
240
- // Determine if the model has changed since the last `"change"` event.
241
- // If you specify an attribute name, determine if that attribute has changed.
242
- hasChanged: function(attr) {
305
+ /**
306
+ * Determine if the model has changed since the last `"change"` event.
307
+ * If you specify an attribute name, determine if that attribute has changed.
308
+ * @param {string} [attr]
309
+ */
310
+ hasChanged(attr) {
243
311
  if (attr == null) return !isEmpty(this.changed);
244
312
  return has(this.changed, attr);
245
- },
246
-
247
- // Return an object containing all the attributes that have changed, or
248
- // false if there are no changed attributes. Useful for determining what
249
- // parts of a view need to be updated and/or what attributes need to be
250
- // persisted to the server. Unset attributes will be set to undefined.
251
- // You can also pass an attributes object to diff against the model,
252
- // determining if there *would be* a change.
253
- changedAttributes: function(diff) {
254
- if (!diff) return this.hasChanged() ? clone(this.changed) : false;
313
+ }
314
+
315
+ /**
316
+ * Return an object containing all the attributes that have changed, or
317
+ * false if there are no changed attributes. Useful for determining what
318
+ * parts of a view need to be updated and/or what attributes need to be
319
+ * persisted to the server. Unset attributes will be set to undefined.
320
+ * You can also pass an attributes object to diff against the model,
321
+ * determining if there *would be* a change.
322
+ * @param {Object} diff
323
+ */
324
+ changedAttributes(diff) {
325
+ if (!diff) {
326
+ return this.hasChanged() ? clone(this.changed) : false;
327
+ }
328
+
255
329
  const old = this._changing ? this._previousAttributes : this.attributes;
256
330
  const changed = {};
257
331
  let hasChanged;
@@ -262,51 +336,66 @@ Object.assign(Model.prototype, Events, {
262
336
  hasChanged = true;
263
337
  }
264
338
  return hasChanged ? changed : false;
265
- },
339
+ }
266
340
 
267
- // Get the previous value of an attribute, recorded at the time the last
268
- // `"change"` event was fired.
269
- previous: function(attr) {
341
+ /**
342
+ * Get the previous value of an attribute, recorded at the time the last
343
+ * `"change"` event was fired.
344
+ * @param {string} [attr]
345
+ */
346
+ previous(attr) {
270
347
  if (attr == null || !this._previousAttributes) return null;
271
348
  return this._previousAttributes[attr];
272
- },
349
+ }
273
350
 
274
- // Get all of the attributes of the model at the time of the previous
275
- // `"change"` event.
276
- previousAttributes: function() {
351
+ /**
352
+ * Get all of the attributes of the model at the time of the previous
353
+ * `"change"` event.
354
+ */
355
+ previousAttributes() {
277
356
  return clone(this._previousAttributes);
278
- },
357
+ }
358
+
359
+ /**
360
+ * Fetch the model from the server, merging the response with the model's
361
+ * local attributes. Any changed attributes will trigger a "change" event.
362
+ * @param {Options} [options={}]
363
+ */
364
+ fetch(options={}) {
365
+ options = Object.assign({ parse: true }, options);
279
366
 
280
- // Fetch the model from the server, merging the response with the model's
281
- // local attributes. Any changed attributes will trigger a "change" event.
282
- fetch: function(options) {
283
- options = extend({parse: true}, options);
284
- const model = this;
285
367
  const success = options.success;
286
- options.success = function(resp) {
287
- const serverAttrs = options.parse ? model.parse(resp, options) : resp;
288
- if (!model.set(serverAttrs, options)) return false;
289
- if (success) success.call(options.context, model, resp, options);
290
- model.trigger('sync', model, resp, options);
368
+
369
+ options.success = (resp) => {
370
+ const serverAttrs = options.parse ? this.parse(resp, options) : resp;
371
+ if (!this.set(serverAttrs, options)) return false;
372
+ if (success) success.call(options.context, this, resp, options);
373
+ this.trigger('sync', this, resp, options);
291
374
  };
375
+
292
376
  wrapError(this, options);
293
377
  return this.sync('read', this, options);
294
- },
378
+ }
295
379
 
296
- // Set a hash of model attributes, and sync the model to the server.
297
- // If the server returns an attributes hash that differs, the model's
298
- // state will be `set` again.
299
- save: function(key, val, options) {
380
+ /**
381
+ * Set a hash of model attributes, and sync the model to the server.
382
+ * If the server returns an attributes hash that differs, the model's
383
+ * state will be `set` again.
384
+ * @param {string|Attributes} [key]
385
+ * @param {boolean|number|string|Options} [val]
386
+ * @param {Options} [options]
387
+ */
388
+ save(key, val, options) {
300
389
  // Handle both `"key", value` and `{key: value}` -style arguments.
301
390
  let attrs;
302
391
  if (key == null || typeof key === 'object') {
303
392
  attrs = key;
304
- options = val;
393
+ options = /** @type {Options} */ (val);
305
394
  } else {
306
395
  (attrs = {})[key] = val;
307
396
  }
308
397
 
309
- options = extend({validate: true, parse: true}, options);
398
+ options = Object.assign({ validate: true, parse: true }, options);
310
399
  const wait = options.wait;
311
400
  const return_promise = options.promise;
312
401
  const promise = return_promise && getResolveablePromise();
@@ -316,35 +405,36 @@ Object.assign(Model.prototype, Events, {
316
405
  // the model will be valid when the attributes, if any, are set.
317
406
  if (attrs && !wait) {
318
407
  if (!this.set(attrs, options)) return false;
319
- } else if (!this._validate(attrs, options)) {
408
+ } else if (!this._validate(/** @type {Object} */ (attrs), options)) {
320
409
  return false;
321
410
  }
322
411
 
323
412
  // After a successful server-side save, the client is (optionally)
324
413
  // updated with the server-side state.
325
- const model = this;
326
414
  const success = options.success;
327
415
  const error = options.error;
328
416
  const attributes = this.attributes;
329
- options.success = function(resp) {
417
+
418
+ options.success = (resp) => {
330
419
  // Ensure attributes are restored during synchronous saves.
331
- model.attributes = attributes;
332
- let serverAttrs = options.parse ? model.parse(resp, options) : resp;
333
- if (wait) serverAttrs = extend({}, attrs, serverAttrs);
334
- if (serverAttrs && !model.set(serverAttrs, options)) return false;
335
- if (success) success.call(options.context, model, resp, options);
336
- model.trigger('sync', model, resp, options);
420
+ this.attributes = attributes;
421
+ let serverAttrs = options.parse ? this.parse(resp, options) : resp;
422
+ if (wait) serverAttrs = Object.assign({}, attrs, serverAttrs);
423
+ if (serverAttrs && !this.set(serverAttrs, options)) return false;
424
+ if (success) success.call(options.context, this, resp, options);
425
+ this.trigger('sync', this, resp, options);
337
426
  return_promise && promise.resolve();
338
427
  };
339
- options.error = function(model, e, options) {
428
+
429
+ options.error = (model, e, options) => {
340
430
  error && error.call(options.context, model, e, options);
341
431
  return_promise && promise.reject(e);
342
- }
432
+ };
343
433
 
344
434
  wrapError(this, options);
345
435
 
346
436
  // Set temporary attributes if `{wait: true}` to properly find new ids.
347
- if (attrs && wait) this.attributes = extend({}, attributes, attrs);
437
+ if (attrs && wait) this.attributes = Object.assign({}, attributes, attrs);
348
438
 
349
439
  const method = this.isNew() ? 'create' : options.patch ? 'patch' : 'update';
350
440
  if (method === 'patch' && !options.attrs) options.attrs = attrs;
@@ -358,27 +448,28 @@ Object.assign(Model.prototype, Events, {
358
448
  } else {
359
449
  return xhr;
360
450
  }
451
+ }
361
452
 
362
- },
363
-
364
- // Destroy this model on the server if it was already persisted.
365
- // Optimistically removes the model from its collection, if it has one.
366
- // If `wait: true` is passed, waits for the server to respond before removal.
367
- destroy: function(options) {
453
+ /**
454
+ * Destroy this model on the server if it was already persisted.
455
+ * Optimistically removes the model from its collection, if it has one.
456
+ * If `wait: true` is passed, waits for the server to respond before removal.
457
+ * @param {Options} [options]
458
+ */
459
+ destroy(options) {
368
460
  options = options ? clone(options) : {};
369
- const model = this;
370
461
  const success = options.success;
371
462
  const wait = options.wait;
372
463
 
373
- const destroy = function() {
374
- model.stopListening();
375
- model.trigger('destroy', model, model.collection, options);
464
+ const destroy = () => {
465
+ this.stopListening();
466
+ this.trigger('destroy', this, this.collection, options);
376
467
  };
377
468
 
378
- options.success = function(resp) {
469
+ options.success = (resp) => {
379
470
  if (wait) destroy();
380
- if (success) success.call(options.context, model, resp, options);
381
- if (!model.isNew()) model.trigger('sync', model, resp, options);
471
+ if (success) success.call(options.context, this, resp, options);
472
+ if (!this.isNew()) this.trigger('sync', this, resp, options);
382
473
  };
383
474
 
384
475
  let xhr = false;
@@ -390,50 +481,59 @@ Object.assign(Model.prototype, Events, {
390
481
  }
391
482
  if (!wait) destroy();
392
483
  return xhr;
393
- },
394
-
395
- // Default URL for the model's representation on the server -- if you're
396
- // using Backbone's restful methods, override this to change the endpoint
397
- // that will be called.
398
- url: function() {
399
- const base =
400
- result(this, 'urlRoot') ||
401
- result(this.collection, 'url') ||
402
- urlError();
484
+ }
485
+
486
+ /**
487
+ * Default URL for the model's representation on the server -- if you're
488
+ * using Backbone's restful methods, override this to change the endpoint
489
+ * that will be called.
490
+ */
491
+ url() {
492
+ const base = result(this, 'urlRoot') || result(this.collection, 'url') || urlError();
403
493
  if (this.isNew()) return base;
404
494
  const id = this.get(this.idAttribute);
405
495
  return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
406
- },
496
+ }
407
497
 
408
- // **parse** converts a response into the hash of attributes to be `set` on
409
- // the model. The default implementation is just to pass the response along.
410
- parse: function(resp, options) {
498
+ /**
499
+ * **parse** converts a response into the hash of attributes to be `set` on
500
+ * the model. The default implementation is just to pass the response along.
501
+ * @param {Options} resp
502
+ * @param {Options} [options]
503
+ */
504
+ parse(resp, options) {
411
505
  return resp;
412
- },
413
-
414
- // Create a new model with identical attributes to this one.
415
- clone: function() {
416
- return new this.constructor(this.attributes);
417
- },
506
+ }
418
507
 
419
- // A model is new if it has never been saved to the server, and lacks an id.
420
- isNew: function() {
508
+ /**
509
+ * A model is new if it has never been saved to the server, and lacks an id.
510
+ */
511
+ isNew() {
421
512
  return !this.has(this.idAttribute);
422
- },
513
+ }
423
514
 
424
- // Check if the model is currently in a valid state.
425
- isValid: function(options) {
426
- return this._validate({}, extend({}, options, {validate: true}));
427
- },
515
+ /**
516
+ * Check if the model is currently in a valid state.
517
+ * @param {Options} [options]
518
+ */
519
+ isValid(options) {
520
+ return this._validate({}, Object.assign({}, options, { validate: true }));
521
+ }
428
522
 
429
- // Run validation against the next complete set of model attributes,
430
- // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
431
- _validate: function(attrs, options) {
523
+ /**
524
+ * Run validation against the next complete set of model attributes,
525
+ * returning `true` if all is well. Otherwise, fire an `"invalid"` event.
526
+ * @param {Attributes} attrs
527
+ * @param {Options} [options]
528
+ */
529
+ _validate(attrs, options) {
432
530
  if (!options.validate || !this.validate) return true;
433
- attrs = extend({}, this.attributes, attrs);
434
- const error = this.validationError = this.validate(attrs, options) || null;
531
+ attrs = Object.assign({}, this.attributes, attrs);
532
+ const error = (this.validationError = this.validate(attrs, options) || null);
435
533
  if (!error) return true;
436
- this.trigger('invalid', this, error, extend(options, {validationError: error}));
534
+ this.trigger('invalid', this, error, Object.assign(options, { validationError: error }));
437
535
  return false;
438
536
  }
439
- });
537
+ }
538
+
539
+ export { Model };