@converse/skeletor 0.0.8 → 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.
- package/README.md +38 -25
- package/dist/skeletor.js +9232 -5096
- package/dist/skeletor.js.map +1 -1
- package/dist/skeletor.min.js +74 -3
- package/dist/skeletor.min.js.map +1 -1
- package/package.json +21 -11
- package/src/collection.js +540 -395
- package/src/drivers/sessionStorage.js +222 -219
- package/src/element.js +132 -82
- package/src/eventemitter.js +187 -0
- package/src/helpers.js +143 -118
- package/src/{main.js → index.js} +21 -17
- package/src/listening.js +81 -0
- package/src/model.js +340 -238
- package/src/storage.js +222 -230
- package/src/types/collection.d.ts +366 -0
- package/src/types/collection.d.ts.map +1 -0
- package/src/types/drivers/sessionStorage.d.ts +37 -0
- package/src/types/drivers/sessionStorage.d.ts.map +1 -0
- package/src/types/element.d.ts +115 -0
- package/src/types/element.d.ts.map +1 -0
- package/src/types/eventemitter.d.ts +93 -0
- package/src/types/eventemitter.d.ts.map +1 -0
- package/src/types/helpers.d.ts +62 -0
- package/src/types/helpers.d.ts.map +1 -0
- package/src/types/index.d.ts +19 -0
- package/src/types/index.d.ts.map +1 -0
- package/src/types/listening.d.ts +40 -0
- package/src/types/listening.d.ts.map +1 -0
- package/src/types/model.d.ts +230 -0
- package/src/types/model.d.ts.map +1 -0
- package/src/types/storage.d.ts +35 -0
- package/src/types/storage.d.ts.map +1 -0
- package/src/types/utils/events.d.ts +28 -0
- package/src/types/utils/events.d.ts.map +1 -0
- package/src/utils/events.js +174 -0
- package/src/drivers/sessionStorage.js~ +0 -307
- package/src/events.js +0 -328
- package/src/history.js +0 -301
- package/src/overview.js +0 -191
- package/src/router.js +0 -119
- package/src/view.js +0 -267
package/src/helpers.js
CHANGED
|
@@ -12,13 +12,13 @@ import result from 'lodash-es/result.js';
|
|
|
12
12
|
export class NotImplementedError extends Error {}
|
|
13
13
|
|
|
14
14
|
function S4() {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
// Generate four random hex digits.
|
|
16
|
+
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function guid() {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
// Generate a pseudo-GUID by concatenating random hexadecimal.
|
|
21
|
+
return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4();
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// Helpers
|
|
@@ -29,139 +29,164 @@ export function guid() {
|
|
|
29
29
|
// class properties to be extended.
|
|
30
30
|
//
|
|
31
31
|
export function inherits(protoProps, staticProps) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// Set the prototype chain to inherit from `parent`, without calling
|
|
48
|
-
// `parent`'s constructor function and add the prototype properties.
|
|
49
|
-
child.prototype = create(parent.prototype, protoProps);
|
|
50
|
-
child.prototype.constructor = child;
|
|
51
|
-
|
|
52
|
-
// Set a convenience property in case the parent's prototype is needed
|
|
53
|
-
// later.
|
|
54
|
-
child.__super__ = parent.prototype;
|
|
55
|
-
|
|
56
|
-
return child;
|
|
57
|
-
}
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
33
|
+
const parent = this;
|
|
34
|
+
let child;
|
|
35
|
+
|
|
36
|
+
// The constructor function for the new subclass is either defined by you
|
|
37
|
+
// (the "constructor" property in your `extend` definition), or defaulted
|
|
38
|
+
// by us to simply call the parent constructor.
|
|
39
|
+
if (protoProps && has(protoProps, 'constructor')) {
|
|
40
|
+
child = protoProps.constructor;
|
|
41
|
+
} else {
|
|
42
|
+
child = function () {
|
|
43
|
+
return parent.apply(this, arguments);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
58
46
|
|
|
47
|
+
// Add static properties to the constructor function, if supplied.
|
|
48
|
+
extend(child, parent, staticProps);
|
|
59
49
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Object.assign(promise, wrapper);
|
|
71
|
-
promise.then(
|
|
72
|
-
function (v) {
|
|
73
|
-
promise.isResolved = true;
|
|
74
|
-
promise.isPending = false;
|
|
75
|
-
promise.isRejected = false;
|
|
76
|
-
return v;
|
|
77
|
-
},
|
|
78
|
-
function (e) {
|
|
79
|
-
promise.isResolved = false;
|
|
80
|
-
promise.isPending = false;
|
|
81
|
-
promise.isRejected = true;
|
|
82
|
-
throw (e);
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
return promise;
|
|
50
|
+
// Set the prototype chain to inherit from `parent`, without calling
|
|
51
|
+
// `parent`'s constructor function and add the prototype properties.
|
|
52
|
+
child.prototype = create(parent.prototype, protoProps);
|
|
53
|
+
child.prototype.constructor = child;
|
|
54
|
+
|
|
55
|
+
// Set a convenience property in case the parent's prototype is needed
|
|
56
|
+
// later.
|
|
57
|
+
child.__super__ = parent.prototype;
|
|
58
|
+
|
|
59
|
+
return child;
|
|
86
60
|
}
|
|
87
61
|
|
|
62
|
+
export function getResolveablePromise() {
|
|
63
|
+
/**
|
|
64
|
+
* @typedef {Object} PromiseWrapper
|
|
65
|
+
* @property {boolean} isResolved
|
|
66
|
+
* @property {boolean} isPending
|
|
67
|
+
* @property {boolean} isRejected
|
|
68
|
+
* @property {Function} resolve
|
|
69
|
+
* @property {Function} reject
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/** @type {PromiseWrapper} */
|
|
73
|
+
const wrapper = {
|
|
74
|
+
isResolved: false,
|
|
75
|
+
isPending: true,
|
|
76
|
+
isRejected: false,
|
|
77
|
+
resolve: null,
|
|
78
|
+
reject: null,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @typedef {Promise & PromiseWrapper} ResolveablePromise
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
const promise = /** @type {ResolveablePromise} */ (
|
|
86
|
+
new Promise((resolve, reject) => {
|
|
87
|
+
wrapper.resolve = resolve;
|
|
88
|
+
wrapper.reject = reject;
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
Object.assign(promise, wrapper);
|
|
92
|
+
promise.then(
|
|
93
|
+
function (v) {
|
|
94
|
+
promise.isResolved = true;
|
|
95
|
+
promise.isPending = false;
|
|
96
|
+
promise.isRejected = false;
|
|
97
|
+
return v;
|
|
98
|
+
},
|
|
99
|
+
function (e) {
|
|
100
|
+
promise.isResolved = false;
|
|
101
|
+
promise.isPending = false;
|
|
102
|
+
promise.isRejected = true;
|
|
103
|
+
throw e;
|
|
104
|
+
},
|
|
105
|
+
);
|
|
106
|
+
return promise;
|
|
107
|
+
}
|
|
88
108
|
|
|
89
109
|
// Throw an error when a URL is needed, and none is supplied.
|
|
90
110
|
export function urlError() {
|
|
91
|
-
|
|
111
|
+
throw new Error('A "url" property or function must be specified');
|
|
92
112
|
}
|
|
93
113
|
|
|
94
114
|
// Wrap an optional error callback with a fallback error event.
|
|
95
115
|
export function wrapError(model, options) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
const error = options.error;
|
|
117
|
+
options.error = function (resp) {
|
|
118
|
+
if (error) error.call(options.context, model, resp, options);
|
|
119
|
+
model.trigger('error', model, resp, options);
|
|
120
|
+
};
|
|
101
121
|
}
|
|
102
122
|
|
|
103
123
|
// Map from CRUD to HTTP for our default `sync` implementation.
|
|
104
124
|
const methodMap = {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
125
|
+
create: 'POST',
|
|
126
|
+
update: 'PUT',
|
|
127
|
+
patch: 'PATCH',
|
|
128
|
+
delete: 'DELETE',
|
|
129
|
+
read: 'GET',
|
|
110
130
|
};
|
|
111
131
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// sync
|
|
118
|
-
// ----
|
|
132
|
+
/**
|
|
133
|
+
* @typedef {import('./model.js').Model} Model
|
|
134
|
+
* @typedef {import('./collection.js').Collection} Collection
|
|
135
|
+
*/
|
|
119
136
|
|
|
120
|
-
// Override this function to change the manner in which Backbone persists
|
|
121
|
-
// models to the server. You will be passed the type of request, and the
|
|
122
|
-
// model in question. By default, makes a RESTful Ajax request
|
|
123
|
-
// to the model's `url()`. Some possible customizations could be:
|
|
124
|
-
//
|
|
125
|
-
// * Use `setTimeout` to batch rapid-fire updates into a single request.
|
|
126
|
-
// * Send up the models as XML instead of JSON.
|
|
127
|
-
// * Persist models via WebSockets instead of Ajax.
|
|
128
|
-
//
|
|
129
|
-
export function sync(method, model, options={}) {
|
|
130
|
-
const type = methodMap[method];
|
|
131
|
-
|
|
132
|
-
// Default JSON-request options.
|
|
133
|
-
const params = {type: type, dataType: 'json'};
|
|
134
|
-
|
|
135
|
-
// Ensure that we have a URL.
|
|
136
|
-
if (!options.url) {
|
|
137
|
-
params.url = result(model, 'url') || urlError();
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Ensure that we have the appropriate request data.
|
|
141
|
-
if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
|
|
142
|
-
params.contentType = 'application/json';
|
|
143
|
-
params.data = JSON.stringify(options.attrs || model.toJSON(options));
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Don't process data on a non-GET request.
|
|
147
|
-
if (params.type !== 'GET') {
|
|
148
|
-
params.processData = false;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Pass along `textStatus` and `errorThrown` from jQuery.
|
|
152
|
-
const error = options.error;
|
|
153
|
-
options.error = function(xhr, textStatus, errorThrown) {
|
|
154
|
-
options.textStatus = textStatus;
|
|
155
|
-
options.errorThrown = errorThrown;
|
|
156
|
-
if (error) error.call(options.context, xhr, textStatus, errorThrown);
|
|
157
|
-
};
|
|
158
137
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
138
|
+
/**
|
|
139
|
+
* @param {Model | Collection} model
|
|
140
|
+
*/
|
|
141
|
+
export function getSyncMethod(model) {
|
|
142
|
+
const store = result(model, 'browserStorage') || result(/** @type {Model} */(model).collection, 'browserStorage');
|
|
143
|
+
return store ? store.sync() : sync;
|
|
163
144
|
}
|
|
164
145
|
|
|
165
|
-
|
|
166
|
-
|
|
146
|
+
/**
|
|
147
|
+
* @typedef {Object} SyncOptions
|
|
148
|
+
* @property {string} [url]
|
|
149
|
+
* @property {any} [data]
|
|
150
|
+
* @property {any} [attrs]
|
|
151
|
+
* @property {Function} [success]
|
|
152
|
+
* @property {Function} [error]
|
|
153
|
+
* @property {any} [xhr]
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Override this function to change the manner in which Backbone persists
|
|
158
|
+
* models to the server. You will be passed the type of request, and the
|
|
159
|
+
* model in question. By default makes a `fetch()` API call
|
|
160
|
+
* to the model's `url()`.
|
|
161
|
+
*
|
|
162
|
+
* Some possible customizations could be:
|
|
163
|
+
*
|
|
164
|
+
* - Use `setTimeout` to batch rapid-fire updates into a single request.
|
|
165
|
+
* - Persist models via WebSockets instead of Ajax.
|
|
166
|
+
* - Persist models to browser storage
|
|
167
|
+
*
|
|
168
|
+
* @param {'create'|'update'|'patch'} method
|
|
169
|
+
* @param {import('./model.js').Model} model
|
|
170
|
+
* @param {SyncOptions} [options]
|
|
171
|
+
*/
|
|
172
|
+
export function sync(method, model, options = {}) {
|
|
173
|
+
let data = options.data;
|
|
174
|
+
|
|
175
|
+
// Ensure that we have the appropriate request data.
|
|
176
|
+
if (data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
|
|
177
|
+
data = options.attrs || model.toJSON();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const type = methodMap[method];
|
|
181
|
+
const params = {
|
|
182
|
+
method: type,
|
|
183
|
+
body: data ? JSON.stringify(data) : '',
|
|
184
|
+
success: options.success,
|
|
185
|
+
error: options.error,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const url = options.url || result(model, 'url') || urlError();
|
|
189
|
+
const xhr = (options.xhr = fetch(url, params));
|
|
190
|
+
model.trigger('request', model, xhr, { ...params, xhr });
|
|
191
|
+
return xhr;
|
|
167
192
|
}
|
package/src/{main.js → index.js}
RENAMED
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
/* global global */
|
|
2
|
-
import
|
|
2
|
+
import ElementView from './element.js';
|
|
3
|
+
import EventEmitter from './eventemitter.js';
|
|
4
|
+
import Storage from './storage.js';
|
|
3
5
|
import { Collection } from './collection.js';
|
|
4
|
-
import { Events } from './events.js';
|
|
5
|
-
import History from './history.js';
|
|
6
6
|
import { Model } from './model.js';
|
|
7
|
-
import {
|
|
8
|
-
import { View } from './view.js';
|
|
7
|
+
import { sync } from './helpers.js';
|
|
9
8
|
|
|
10
9
|
const skeletor = {
|
|
11
10
|
Collection,
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
ElementView,
|
|
12
|
+
EventEmitter,
|
|
14
13
|
Model,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
ajax,
|
|
18
|
-
sync
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
Object.assign(skeletor, Events);
|
|
14
|
+
sync,
|
|
15
|
+
};
|
|
22
16
|
|
|
23
17
|
// Establish the root object, `window` (`self`) in the browser, or `global` on the server.
|
|
24
18
|
// We use `self` instead of `window` for `WebWorker` support.
|
|
25
|
-
const root =
|
|
26
|
-
|
|
19
|
+
const root =
|
|
20
|
+
(typeof self == 'object' && self.self === self && self) ||
|
|
21
|
+
(typeof global == 'object' && global.global === global && global);
|
|
27
22
|
|
|
28
23
|
// Current version of the library. Keep in sync with `package.json`.
|
|
29
24
|
skeletor.VERSION = '0.0.1';
|
|
@@ -34,10 +29,19 @@ const previousSkeletor = root.Skeletor;
|
|
|
34
29
|
|
|
35
30
|
// Runs Skeletor.js in *noConflict* mode, returning the `Skeletor` variable
|
|
36
31
|
// to its previous owner. Returns a reference to this Skeletor object.
|
|
37
|
-
skeletor.noConflict = function() {
|
|
32
|
+
skeletor.noConflict = function () {
|
|
38
33
|
root.Skeletor = previousSkeletor;
|
|
39
34
|
return this;
|
|
40
35
|
};
|
|
41
36
|
|
|
42
37
|
root.Skeletor = skeletor;
|
|
43
38
|
export default skeletor;
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
Collection,
|
|
42
|
+
ElementView,
|
|
43
|
+
EventEmitter,
|
|
44
|
+
Model,
|
|
45
|
+
Storage,
|
|
46
|
+
sync,
|
|
47
|
+
}
|
package/src/listening.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { eventsApi, onApi, offApi } from './utils/events.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A listening class that tracks and cleans up memory bindings
|
|
5
|
+
* when all callbacks have been offed.
|
|
6
|
+
*/
|
|
7
|
+
class Listening {
|
|
8
|
+
|
|
9
|
+
/** @typedef {import('./eventemitter.js').default} EventEmitter */
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {any} listener
|
|
13
|
+
* @param {any} obj
|
|
14
|
+
*/
|
|
15
|
+
constructor(listener, obj) {
|
|
16
|
+
this.id = listener._listenId;
|
|
17
|
+
this.listener = listener;
|
|
18
|
+
this.obj = obj;
|
|
19
|
+
this.interop = true;
|
|
20
|
+
this.count = 0;
|
|
21
|
+
this._events = undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} name
|
|
26
|
+
* @param {Function} callback
|
|
27
|
+
* @param {any} context
|
|
28
|
+
* @param {Listening} _listening
|
|
29
|
+
*/
|
|
30
|
+
start(name, callback, context, _listening) {
|
|
31
|
+
this._events = eventsApi(onApi, this._events || {}, name, callback, {
|
|
32
|
+
context: this.obj,
|
|
33
|
+
ctx: context,
|
|
34
|
+
listening: _listening,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (_listening) {
|
|
38
|
+
const listeners = this.obj._listeners || (this.obj._listeners = {});
|
|
39
|
+
listeners[this.id] = this;
|
|
40
|
+
|
|
41
|
+
// Allow the listening to use a counter, instead of tracking
|
|
42
|
+
// callbacks for library interop
|
|
43
|
+
this.interop = false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Stop's listening to a callback (or several).
|
|
51
|
+
* Uses an optimized counter if the listenee uses Backbone.Events.
|
|
52
|
+
* Otherwise, falls back to manual tracking to support events
|
|
53
|
+
* library interop.
|
|
54
|
+
* @param {string} name
|
|
55
|
+
* @param {Function} callback
|
|
56
|
+
*/
|
|
57
|
+
stop(name, callback) {
|
|
58
|
+
let cleanup;
|
|
59
|
+
if (this.interop) {
|
|
60
|
+
this._events = eventsApi(offApi, this._events, name, callback, {
|
|
61
|
+
context: undefined,
|
|
62
|
+
listeners: undefined,
|
|
63
|
+
});
|
|
64
|
+
cleanup = !this._events;
|
|
65
|
+
} else {
|
|
66
|
+
this.count--;
|
|
67
|
+
cleanup = this.count === 0;
|
|
68
|
+
}
|
|
69
|
+
if (cleanup) this.cleanup();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Cleans up memory bindings between the listener and the listenee.
|
|
74
|
+
*/
|
|
75
|
+
cleanup() {
|
|
76
|
+
delete this.listener._listeningTo[this.obj._listenId];
|
|
77
|
+
if (!this.interop) delete this.obj._listeners[this.id];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default Listening;
|