simplyview 1.0.0 → 2.0.2
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 +9 -6
- package/dist/simply.everything.js +1596 -1139
- package/docs/examples.md +82 -0
- package/docs/readme.md +33 -0
- package/docs/simply.action.md +42 -0
- package/docs/simply.activate.md +27 -0
- package/docs/simply.api.md +188 -0
- package/docs/simply.app.md +27 -0
- package/docs/simply.collect.md +64 -0
- package/docs/simply.command.md +110 -0
- package/docs/simply.include.md +61 -0
- package/docs/simply.keyboard.md +60 -0
- package/docs/simply.path.md +3 -0
- package/docs/simply.route.md +133 -0
- package/docs/simply.view.md +53 -0
- package/docs/simply.viewmodel.md +3 -0
- package/examples/counter.html +1 -0
- package/examples/github.html +39 -0
- package/examples/githubv4.html +107 -0
- package/examples/graphql.html +51 -0
- package/examples/graphql.html~ +35 -0
- package/examples/keyboard.html +41 -0
- package/examples/viewmodel.html +359 -0
- package/js/simply.action.js +14 -5
- package/js/simply.activate.js +12 -4
- package/js/simply.api.js +229 -0
- package/js/simply.app.js +27 -9
- package/js/simply.collect.js +13 -5
- package/js/simply.command.js +36 -6
- package/js/simply.include.js +38 -17
- package/js/simply.keyboard.js +45 -0
- package/js/simply.modules.js +22 -0
- package/js/simply.observe.js +13 -4
- package/js/simply.path.js +12 -4
- package/js/simply.render.js +12 -6
- package/js/simply.resize.js +28 -20
- package/js/simply.route.js +149 -19
- package/js/simply.view.js +16 -9
- package/js/simply.viewmodel.js +174 -0
- package/make +16 -2
- package/make~ +17 -0
- package/package.json +6 -3
- package/package.json~ +8 -5
- package/test/simply.route.test.js +102 -0
- package/examples/todo.html~ +0 -50
- package/js/simply.app.js~ +0 -44
- package/js/simply.bind.js +0 -253
- package/js/simply.command.js~ +0 -166
- package/js/simply.resize.js~ +0 -69
|
@@ -1,178 +1,355 @@
|
|
|
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
|
-
|
|
1
|
+
/**
|
|
2
|
+
* simply.observe
|
|
3
|
+
* This component lets you observe changes in a json compatible data structure
|
|
4
|
+
* It doesn't support linking the same object multiple times
|
|
5
|
+
* It doesn't register deletion of properties using the delete keyword, assign
|
|
6
|
+
* null to the property instead.
|
|
7
|
+
* It doesn't register addition of new properties.
|
|
8
|
+
* It doesn't register directly assigning new entries in an array on a previously
|
|
9
|
+
* non-existant index.
|
|
10
|
+
*
|
|
11
|
+
* usage:
|
|
12
|
+
*
|
|
13
|
+
* (function) simply.observe( (object) model, (string) path, (function) callback)
|
|
14
|
+
*
|
|
15
|
+
* var model = { foo: { bar: 'baz' } };
|
|
16
|
+
* var removeObserver = simply.observe(model, 'foo.bar', function(value, sourcePath) {
|
|
17
|
+
* console.log(sourcePath+': '+value);
|
|
18
|
+
* };
|
|
19
|
+
*
|
|
20
|
+
* The function returns a function that removes the observer when called.
|
|
21
|
+
*
|
|
22
|
+
* The component can observe in place changes in arrays, either by changing
|
|
23
|
+
* an item in a specific index, by calling methods on the array that change
|
|
24
|
+
* the array in place or by reassigning the array with a new value.
|
|
25
|
+
*
|
|
26
|
+
* The sourcePath contains the exact entry that was changed, the value is the
|
|
27
|
+
* value for the path passed to simply.observe.
|
|
28
|
+
* If an array method was called that changes the array in place, the sourcePath
|
|
29
|
+
* also contains that method and its arguments JSON serialized.
|
|
30
|
+
*
|
|
31
|
+
* sourcePath parts are always seperated with '.', even for array indexes.
|
|
32
|
+
* so if foo = [ 'bar' ], the path to 'bar' would be 'foo.0'
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
FIXME: child properties added after initial observe() call aren't added to the
|
|
37
|
+
childListeners. onMissingChildren can't then find them.
|
|
38
|
+
TODO: onMissingChildren must loop through all fields to get only the direct child
|
|
39
|
+
properties for a given parent, keep seperate index for this?
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
(function (global) {
|
|
43
|
+
'use strict';
|
|
44
|
+
|
|
45
|
+
var changeListeners = new WeakMap();
|
|
46
|
+
var parentListeners = new WeakMap();
|
|
47
|
+
var childListeners = new WeakMap();
|
|
48
|
+
var changesSignalled = {};
|
|
49
|
+
var observersPaused = 0;
|
|
50
|
+
|
|
51
|
+
function signalChange(model, path, value, sourcePath) {
|
|
52
|
+
if (observersPaused) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
sourcePath = sourcePath ? sourcePath : path;
|
|
57
|
+
changesSignalled = {};
|
|
58
|
+
|
|
59
|
+
var signalRecursion = function(model, path, value, sourcePath) {
|
|
60
|
+
if (changeListeners.has(model) && changeListeners.get(model)[path]) {
|
|
61
|
+
// changeListeners[model][path] contains callback methods
|
|
62
|
+
changeListeners.get(model)[path].forEach(function(callback) {
|
|
63
|
+
changesSignalled[path] = true;
|
|
64
|
+
callback(value, sourcePath);
|
|
65
|
+
});
|
|
38
66
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
//TODO: check if this is correct
|
|
70
|
+
//previous version only triggered parentListeners when no changeListeners were
|
|
71
|
+
//triggered. that created problems with arrays. make an exhaustive unit test.
|
|
72
|
+
signalRecursion(model, path, value, sourcePath);
|
|
73
|
+
|
|
74
|
+
if (parentListeners.has(model) && parentListeners.get(model)[path]) {
|
|
75
|
+
// parentListeners[model][path] contains child paths to signal change on
|
|
76
|
+
// if a parent object is changed, this signals the change to the child objects
|
|
77
|
+
parentListeners.get(model)[path].forEach(function(childPath) {
|
|
78
|
+
if (!changesSignalled[childPath]) {
|
|
79
|
+
var value = getByPath(model, childPath);
|
|
80
|
+
if (value) {
|
|
81
|
+
attach(model, childPath);
|
|
82
|
+
}
|
|
83
|
+
signalRecursion(model, childPath, value, sourcePath);
|
|
84
|
+
changesSignalled[childPath] = true;
|
|
43
85
|
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (childListeners.has(model) && childListeners.get(model)[path]) {
|
|
90
|
+
// childListeners[model][path] contains parent paths to signal change on
|
|
91
|
+
// if a child object is changed, this signals the change to the parent objects
|
|
92
|
+
childListeners.get(model)[path].forEach(function(parentPath) {
|
|
93
|
+
if (!changesSignalled[parentPath]) {
|
|
94
|
+
var value = getByPath(model, parentPath);
|
|
95
|
+
signalRecursion(model, parentPath, value, sourcePath);
|
|
96
|
+
changesSignalled[parentPath] = true;
|
|
97
|
+
// check if the parent object still has this child property
|
|
98
|
+
//FIXME: add a setter trigger here to restore observers once the child property get set again
|
|
99
|
+
|
|
48
100
|
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getByPath(model, path) {
|
|
107
|
+
var parts = path.split('.');
|
|
108
|
+
var curr = model;
|
|
109
|
+
do {
|
|
110
|
+
curr = curr[parts.shift()];
|
|
111
|
+
} while (parts.length && curr);
|
|
112
|
+
return curr;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function parent(path) {
|
|
116
|
+
var parts = path.split('.');
|
|
117
|
+
parts.pop();
|
|
118
|
+
return parts.join('.');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function head(path) {
|
|
122
|
+
return path.split('.').shift();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function onParents(model, path, callback) {
|
|
126
|
+
var parent = '';
|
|
127
|
+
var parentOb = model;
|
|
128
|
+
var parents = path.split('.');
|
|
129
|
+
do {
|
|
130
|
+
var head = parents.shift();
|
|
131
|
+
if (parentOb && typeof parentOb[head] != 'undefined') {
|
|
132
|
+
callback(parentOb, head, (parent ? parent + '.' + head : head));
|
|
133
|
+
parentOb = parentOb[head];
|
|
49
134
|
}
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
};
|
|
59
|
-
for ( var i in methods ) {
|
|
60
|
-
if ( typeof document.documentElement[i] != 'undefined' ) {
|
|
61
|
-
var requestMethod = i;
|
|
62
|
-
var cancelMethod = methods[i].exit;
|
|
63
|
-
var event = methods[i].event;
|
|
64
|
-
var element = methods[i].el;
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
135
|
+
parent = (parent ? parent + '.' + head : head );
|
|
136
|
+
} while (parents.length);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function onChildren(model, path, callback) {
|
|
140
|
+
var onChildObjects = function(object, path, callback) {
|
|
141
|
+
if (typeof object != 'object' || object == null) {
|
|
142
|
+
return;
|
|
67
143
|
}
|
|
68
|
-
if (
|
|
144
|
+
if (Array.isArray(object)) {
|
|
69
145
|
return;
|
|
70
146
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
147
|
+
// register the current keys
|
|
148
|
+
Object.keys(object).forEach(function(key) {
|
|
149
|
+
callback(object, key, path+'.'+key);
|
|
150
|
+
onChildObjects(object[key], path+'.'+key, callback);
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
var parent = getByPath(model, path);
|
|
154
|
+
onChildObjects(parent, path, callback);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function onMissingChildren(model, path, callback) {
|
|
158
|
+
var allChildren = Object.keys(childListeners.get(model) || []).filter(function(childPath) {
|
|
159
|
+
return childPath.substr(0, path.length)==path && childPath.length>path.length;
|
|
160
|
+
});
|
|
161
|
+
if (!allChildren.length) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
var object = getByPath(model, path);
|
|
165
|
+
var keysSeen = {};
|
|
166
|
+
allChildren.forEach(function(childPath) {
|
|
167
|
+
var key = head(childPath.substr(path.length+1));
|
|
168
|
+
if (typeof object[key] == 'undefined') {
|
|
169
|
+
if (!keysSeen[key]) {
|
|
170
|
+
callback(object, key, path+'.'+key);
|
|
171
|
+
keysSeen[key] = true;
|
|
172
|
+
}
|
|
81
173
|
} else {
|
|
82
|
-
|
|
83
|
-
document[cancelMethod]();
|
|
174
|
+
onMissingChildren(model, path+'.'+key, callback);
|
|
84
175
|
}
|
|
85
|
-
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function addChangeListener(model, path, callback) {
|
|
180
|
+
if (!changeListeners.has(model)) {
|
|
181
|
+
changeListeners.set(model, {});
|
|
86
182
|
}
|
|
87
|
-
|
|
183
|
+
if (!changeListeners.get(model)[path]) {
|
|
184
|
+
changeListeners.get(model)[path] = [];
|
|
185
|
+
}
|
|
186
|
+
changeListeners.get(model)[path].push(callback);
|
|
88
187
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
for ( var i in inActions ) {
|
|
92
|
-
actions[i] = inActions[i];
|
|
188
|
+
if (!parentListeners.has(model)) {
|
|
189
|
+
parentListeners.set(model, {});
|
|
93
190
|
}
|
|
191
|
+
var parentPath = parent(path);
|
|
192
|
+
onParents(model, parentPath, function(parentOb, key, currPath) {
|
|
193
|
+
if (!parentListeners.get(model)[currPath]) {
|
|
194
|
+
parentListeners.get(model)[currPath] = [];
|
|
195
|
+
}
|
|
196
|
+
parentListeners.get(model)[currPath].push(path);
|
|
197
|
+
});
|
|
94
198
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
199
|
+
if (!childListeners.has(model)) {
|
|
200
|
+
childListeners.set(model, {});
|
|
201
|
+
}
|
|
202
|
+
onChildren(model, path, function(childOb, key, currPath) {
|
|
203
|
+
if (!childListeners.get(model)[currPath]) {
|
|
204
|
+
childListeners.get(model)[currPath] = [];
|
|
205
|
+
}
|
|
206
|
+
childListeners.get(model)[currPath].push(path);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
103
209
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
210
|
+
function removeChangeListener(model, path, callback) {
|
|
211
|
+
if (!changeListeners.has(model)) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (changeListeners.get(model)[path]) {
|
|
215
|
+
changeListeners.get(model)[path] = changeListeners.get(model)[path].filter(function(f) {
|
|
216
|
+
return f != callback;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
108
220
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (
|
|
122
|
-
var
|
|
123
|
-
|
|
124
|
-
|
|
221
|
+
function pauseObservers() {
|
|
222
|
+
observersPaused++;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function resumeObservers() {
|
|
226
|
+
observersPaused--;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function attach(model, path, options) {
|
|
230
|
+
|
|
231
|
+
var attachArray = function(object, path) {
|
|
232
|
+
var desc = Object.getOwnPropertyDescriptor(object, 'push');
|
|
233
|
+
if (!desc || desc.configurable) {
|
|
234
|
+
for (var f of ['push','pop','reverse','shift','sort','splice','unshift','copyWithin']) {
|
|
235
|
+
(function(f) {
|
|
236
|
+
try {
|
|
237
|
+
Object.defineProperty(object, f, {
|
|
238
|
+
value: function() {
|
|
239
|
+
pauseObservers();
|
|
240
|
+
var result = Array.prototype[f].apply(this, arguments);
|
|
241
|
+
attach(model, path);
|
|
242
|
+
var args = [].slice.call(arguments).map(function(arg) {
|
|
243
|
+
return JSON.stringify(arg);
|
|
244
|
+
});
|
|
245
|
+
resumeObservers();
|
|
246
|
+
signalChange(model, path, this, path+'.'+f+'('+args.join(',')+')');
|
|
247
|
+
return result;
|
|
248
|
+
},
|
|
249
|
+
readable: false,
|
|
250
|
+
enumerable: false,
|
|
251
|
+
configurable: false
|
|
252
|
+
});
|
|
253
|
+
} catch(e) {
|
|
254
|
+
console.error('simply.observer: Error: Couldn\'t redefine array method '+f+' on '+path, e);
|
|
255
|
+
}
|
|
256
|
+
}(f));
|
|
257
|
+
}
|
|
258
|
+
for (var i=0, l=object.length; i<l; i++) {
|
|
259
|
+
//FIXME: options becomes undefined here somewhere
|
|
260
|
+
// if (options.skipArray) {
|
|
261
|
+
addSetter(object, i, path+'.'+i);
|
|
262
|
+
// } else {
|
|
263
|
+
// attach(model, path+'.'+i, options);
|
|
264
|
+
// }
|
|
125
265
|
}
|
|
126
266
|
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
var addSetTrigger = function(object, key, currPath) {
|
|
270
|
+
Object.defineProperty(object, key, {
|
|
271
|
+
set: function(value) {
|
|
272
|
+
addSetter(object, key, currPath);
|
|
273
|
+
object[key] = value;
|
|
274
|
+
},
|
|
275
|
+
configurable: true,
|
|
276
|
+
readable: false,
|
|
277
|
+
enumerable: false
|
|
278
|
+
});
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
var addSetter = function(object, key, currPath) {
|
|
282
|
+
if (Object.getOwnPropertyDescriptor(object, key).configurable) {
|
|
283
|
+
// assume object keys are only unconfigurable if the
|
|
284
|
+
// following code has already been run on this property
|
|
285
|
+
var _value = object[key];
|
|
286
|
+
Object.defineProperty(object, key, {
|
|
287
|
+
set: function(value) {
|
|
288
|
+
_value = value;
|
|
289
|
+
signalChange(model, currPath, value);
|
|
290
|
+
if (value!=null) {
|
|
291
|
+
onChildren(model, currPath, addSetter);
|
|
292
|
+
onMissingChildren(model, currPath, addSetTrigger);
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
get: function() {
|
|
296
|
+
return _value;
|
|
297
|
+
},
|
|
298
|
+
configurable: false,
|
|
299
|
+
readable: true,
|
|
300
|
+
enumerable: true
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if (Array.isArray(object[key])) {
|
|
304
|
+
attachArray(object[key], currPath, options);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
136
307
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
el = el.parentElement;
|
|
140
|
-
}
|
|
141
|
-
return el;
|
|
308
|
+
onParents(model, path, addSetter);
|
|
309
|
+
onChildren(model, path, addSetter);
|
|
142
310
|
}
|
|
143
|
-
|
|
144
|
-
document.addEventListener('change', function(evt) {
|
|
145
|
-
var root = null;
|
|
146
|
-
var name = '';
|
|
147
|
-
if (evt.target.dataset.simplyElement) {
|
|
148
|
-
root = findCollection(evt.target);
|
|
149
|
-
if (root && root.dataset) {
|
|
150
|
-
name = root.dataset.simplyCollection;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (name && knownCollections[name]) {
|
|
154
|
-
var inputs = root.querySelectorAll('[data-simply-element]');
|
|
155
|
-
var elements = [].reduce.call(inputs, function(elements, input) {
|
|
156
|
-
elements[input.dataset.simplyElement] = input;
|
|
157
|
-
return elements;
|
|
158
|
-
}, {});
|
|
159
|
-
for (var i=knownCollections[name].length-1; i>=0; i--) {
|
|
160
|
-
var result = knownCollections[name][i].call(evt.target.form, elements);
|
|
161
|
-
if (result === false) {
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}, true);
|
|
167
311
|
|
|
168
|
-
|
|
312
|
+
// FIXME: if you remove a key by reassigning the parent object
|
|
313
|
+
// and then assign that missing key a new value
|
|
314
|
+
// the observer doesn't get triggered
|
|
315
|
+
// var model = { foo: { bar: 'baz' } };
|
|
316
|
+
// simply.observer(model, 'foo.bar', ...)
|
|
317
|
+
// model.foo = { }
|
|
318
|
+
// model.foo.bar = 'zab'; // this should trigger the observer but doesn't
|
|
169
319
|
|
|
170
|
-
|
|
171
|
-
|
|
320
|
+
var observe = function(model, path, callback, options) {
|
|
321
|
+
if (!path) {
|
|
322
|
+
var keys = Object.keys(model);
|
|
323
|
+
keys.forEach(function(key) {
|
|
324
|
+
attach(model, key, options);
|
|
325
|
+
addChangeListener(model, key, callback);
|
|
326
|
+
});
|
|
327
|
+
return function() {
|
|
328
|
+
keys.forEach(function(key) {
|
|
329
|
+
removeChangeListener(model, key, callback);
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
} else {
|
|
333
|
+
attach(model, path, options);
|
|
334
|
+
addChangeListener(model, path, callback);
|
|
335
|
+
return function() {
|
|
336
|
+
removeChangeListener(model, path, callback);
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
};
|
|
172
340
|
|
|
173
|
-
|
|
341
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
342
|
+
module.exports = observe;
|
|
343
|
+
} else {
|
|
344
|
+
if (!global.simply) {
|
|
345
|
+
global.simply = {};
|
|
346
|
+
}
|
|
347
|
+
global.simply.observe = observe;
|
|
348
|
+
}
|
|
349
|
+
})(this);(function(global) {
|
|
350
|
+
'use strict';
|
|
174
351
|
|
|
175
|
-
|
|
352
|
+
var render = function(options) {
|
|
176
353
|
if (!options) {
|
|
177
354
|
options = {};
|
|
178
355
|
}
|
|
@@ -282,540 +459,451 @@ this.simply = (function(simply, global) {
|
|
|
282
459
|
// },
|
|
283
460
|
}, options.fieldTypes);
|
|
284
461
|
|
|
285
|
-
return options;
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
return simply;
|
|
289
|
-
})(this.simply || {}, this);
|
|
290
|
-
this.simply = (function (simply, global) {
|
|
291
|
-
|
|
292
|
-
var throttle = function( callbackFunction, intervalTime ) {
|
|
293
|
-
var eventId = 0;
|
|
294
|
-
return function() {
|
|
295
|
-
var myArguments = arguments;
|
|
296
|
-
var me = this;
|
|
297
|
-
if ( eventId ) {
|
|
298
|
-
return;
|
|
299
|
-
} else {
|
|
300
|
-
eventId = global.setTimeout( function() {
|
|
301
|
-
callbackFunction.apply(me, myArguments);
|
|
302
|
-
eventId = 0;
|
|
303
|
-
}, intervalTime );
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
var runWhenIdle = (function() {
|
|
309
|
-
if (global.requestIdleCallback) {
|
|
310
|
-
return function(callback) {
|
|
311
|
-
global.requestIdleCallback(callback, {timeout: 500});
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
return global.requestAnimationFrame;
|
|
315
|
-
})();
|
|
316
|
-
|
|
317
|
-
var rebaseHref = function(relative, base) {
|
|
318
|
-
if (/^[a-z-]*:?\//.test(relative)) {
|
|
319
|
-
return relative; // absolute href, no need to rebase
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
var stack = base.split('/'),
|
|
323
|
-
parts = relative.split('/');
|
|
324
|
-
stack.pop(); // remove current file name (or empty string)
|
|
325
|
-
for (var i=0; i<parts.length; i++) {
|
|
326
|
-
if (parts[i] == '.')
|
|
327
|
-
continue;
|
|
328
|
-
if (parts[i] == '..')
|
|
329
|
-
stack.pop();
|
|
330
|
-
else
|
|
331
|
-
stack.push(parts[i]);
|
|
332
|
-
}
|
|
333
|
-
return stack.join('/');
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
var observer, loaded = {};
|
|
337
|
-
var head = document.documentElement.querySelector('head');
|
|
338
|
-
var currentScript = document.currentScript;
|
|
339
|
-
|
|
340
|
-
var waitForPreviousScripts = function() {
|
|
341
|
-
// because of the async=false attribute, this script will run after
|
|
342
|
-
// the previous scripts have been loaded and run
|
|
343
|
-
// simply.include.next.js only fires the simply-next-script event
|
|
344
|
-
// that triggers the Promise.resolve method
|
|
345
|
-
return new Promise(function(resolve) {
|
|
346
|
-
var next = document.createElement('script');
|
|
347
|
-
next.src = rebaseHref('simply.include.next.js', currentScript.src);
|
|
348
|
-
next.async = false;
|
|
349
|
-
document.addEventListener('simply-include-next', function() {
|
|
350
|
-
head.removeChild(next);
|
|
351
|
-
resolve();
|
|
352
|
-
}, { once: true, passive: true});
|
|
353
|
-
head.appendChild(next);
|
|
354
|
-
});
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
var scriptLocations = [];
|
|
358
|
-
|
|
359
|
-
simply.include = {
|
|
360
|
-
scripts: function(scripts, base) {
|
|
361
|
-
var arr = [];
|
|
362
|
-
for(var i = scripts.length; i--; arr.unshift(scripts[i]));
|
|
363
|
-
var importScript = function() {
|
|
364
|
-
var script = arr.shift();
|
|
365
|
-
if (!script) {
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
var attrs = [].map.call(script.attributes, function(attr) {
|
|
369
|
-
return attr.name;
|
|
370
|
-
});
|
|
371
|
-
var clone = document.createElement('script');
|
|
372
|
-
attrs.forEach(function(attr) {
|
|
373
|
-
clone.setAttribute(attr, script[attr]);
|
|
374
|
-
});
|
|
375
|
-
clone.removeAttribute('data-simply-location');
|
|
376
|
-
if (!clone.src) {
|
|
377
|
-
// this is an inline script, so copy the content and wait for previous scripts to run
|
|
378
|
-
clone.innerHTML = script.innerHTML;
|
|
379
|
-
waitForPreviousScripts()
|
|
380
|
-
.then(function() {
|
|
381
|
-
var node = scriptLocations[script.dataset.simplyLocation];
|
|
382
|
-
node.parentNode.insertBefore(clone, node);
|
|
383
|
-
node.parentNode.removeChild(node);
|
|
384
|
-
importScript();
|
|
385
|
-
});
|
|
386
|
-
} else {
|
|
387
|
-
clone.src = rebaseHref(clone.src, base);
|
|
388
|
-
if (!clone.hasAttribute('async') && !clone.hasAttribute('defer')) {
|
|
389
|
-
clone.async = false; //important! do not use clone.setAttribute('async', false) - it has no effect
|
|
390
|
-
}
|
|
391
|
-
var node = scriptLocations[script.dataset.simplyLocation];
|
|
392
|
-
node.parentNode.insertBefore(clone, node);
|
|
393
|
-
node.parentNode.removeChild(node);
|
|
394
|
-
loaded[clone.src]=true;
|
|
395
|
-
importScript();
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
if (arr.length) {
|
|
399
|
-
importScript();
|
|
400
|
-
}
|
|
401
|
-
},
|
|
402
|
-
html: function(html, link) {
|
|
403
|
-
var fragment = document.createRange().createContextualFragment(html);
|
|
404
|
-
var stylesheets = fragment.querySelectorAll('link[rel="stylesheet"],style');
|
|
405
|
-
// add all stylesheets to head
|
|
406
|
-
[].forEach.call(stylesheets, function(stylesheet) {
|
|
407
|
-
if (stylesheet.href) {
|
|
408
|
-
stylesheet.href = rebaseHref(stylesheet.href, link.href);
|
|
409
|
-
}
|
|
410
|
-
head.appendChild(stylesheet);
|
|
411
|
-
});
|
|
412
|
-
// remove the scripts from the fragment, as they will not run in the
|
|
413
|
-
// order in which they are defined
|
|
414
|
-
var scriptsFragment = document.createDocumentFragment();
|
|
415
|
-
// FIXME: this loses the original position of the script
|
|
416
|
-
// should add a placeholder so we can reinsert the clone
|
|
417
|
-
var scripts = fragment.querySelectorAll('script');
|
|
418
|
-
[].forEach.call(scripts, function(script) {
|
|
419
|
-
var placeholder = document.createComment(script.src || 'inline script');
|
|
420
|
-
script.parentNode.insertBefore(placeholder, script);
|
|
421
|
-
script.dataset.simplyLocation = scriptLocations.length;
|
|
422
|
-
scriptLocations.push(placeholder);
|
|
423
|
-
scriptsFragment.appendChild(script);
|
|
424
|
-
});
|
|
425
|
-
// add the remainder before the include link
|
|
426
|
-
link.parentNode.insertBefore(fragment, link ? link : null);
|
|
427
|
-
global.setTimeout(function() {
|
|
428
|
-
if (global.editor && global.editor.data && fragment.querySelector('[data-simply-field],[data-simply-list]')) {
|
|
429
|
-
//TODO: remove this dependency and let simply.bind listen for dom node insertions (and simply-edit.js use simply.bind)
|
|
430
|
-
global.editor.data.apply(editor.currentData, document);
|
|
431
|
-
}
|
|
432
|
-
simply.include.scripts(scriptsFragment.childNodes, link ? link.href : global.location.href );
|
|
433
|
-
}, 10);
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
var included = {};
|
|
438
|
-
var includeLinks = function(links) {
|
|
439
|
-
// mark them as in progress, so handleChanges doesn't find them again
|
|
440
|
-
var remainingLinks = [].reduce.call(links, function(remainder, link) {
|
|
441
|
-
if (link.rel=='simply-include-once' && included[link.href]) {
|
|
442
|
-
link.parentNode.removeChild(link);
|
|
443
|
-
} else {
|
|
444
|
-
included[link.href]=true;
|
|
445
|
-
link.rel = 'simply-include-loading';
|
|
446
|
-
remainder.push(link);
|
|
447
|
-
}
|
|
448
|
-
return remainder;
|
|
449
|
-
}, []);
|
|
450
|
-
[].forEach.call(remainingLinks, function(link) {
|
|
451
|
-
if (!link.href) {
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
// fetch the html
|
|
455
|
-
fetch(link.href)
|
|
456
|
-
.then(function(response) {
|
|
457
|
-
if (response.ok) {
|
|
458
|
-
console.log('simply-include: loaded '+link.href);
|
|
459
|
-
return response.text();
|
|
460
|
-
} else {
|
|
461
|
-
console.log('simply-include: failed to load '+link.href);
|
|
462
|
-
}
|
|
463
|
-
})
|
|
464
|
-
.then(function(html) {
|
|
465
|
-
// if succesfull import the html
|
|
466
|
-
simply.include.html(html, link);
|
|
467
|
-
// remove the include link
|
|
468
|
-
link.parentNode.removeChild(link);
|
|
469
|
-
});
|
|
470
|
-
});
|
|
471
|
-
};
|
|
472
|
-
|
|
473
|
-
var handleChanges = throttle(function() {
|
|
474
|
-
runWhenIdle(function() {
|
|
475
|
-
var links = document.querySelectorAll('link[rel="simply-include"],link[rel="simply-include-once"]');
|
|
476
|
-
if (links.length) {
|
|
477
|
-
includeLinks(links);
|
|
478
|
-
}
|
|
479
|
-
});
|
|
480
|
-
});
|
|
462
|
+
return options;
|
|
463
|
+
};
|
|
481
464
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
}
|
|
465
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
466
|
+
module.exports = render;
|
|
467
|
+
} else {
|
|
468
|
+
if (!global.simply) {
|
|
469
|
+
global.simply = {};
|
|
470
|
+
}
|
|
471
|
+
global.simply.render = render;
|
|
472
|
+
}
|
|
473
|
+
})(this);
|
|
474
|
+
(function(global) {
|
|
475
|
+
'us strict';
|
|
476
|
+
|
|
477
|
+
var path = {
|
|
478
|
+
get: function(model, path) {
|
|
479
|
+
if (!path) {
|
|
480
|
+
return model;
|
|
481
|
+
}
|
|
482
|
+
return path.split('.').reduce(function(acc, name) {
|
|
483
|
+
return (acc && acc[name] ? acc[name] : null);
|
|
484
|
+
}, model);
|
|
485
|
+
},
|
|
486
|
+
set: function(model, path, value) {
|
|
487
|
+
var lastName = simply.path.pop(path);
|
|
488
|
+
var parentPath = simply.path.parent(path);
|
|
489
|
+
var parentOb = simply.path.get(model, parentPath);
|
|
490
|
+
parentOb[lastName] = value;
|
|
491
|
+
},
|
|
492
|
+
pop: function(path) {
|
|
493
|
+
return path.split('.').pop();
|
|
494
|
+
},
|
|
495
|
+
push: function(path, name) {
|
|
496
|
+
return (path ? path + '.' : '') + name;
|
|
497
|
+
},
|
|
498
|
+
parent: function(path) {
|
|
499
|
+
var p = path.split('.');
|
|
500
|
+
p.pop();
|
|
501
|
+
return p.join('.');
|
|
502
|
+
},
|
|
503
|
+
parents: function(path) {
|
|
504
|
+
var result = [];
|
|
505
|
+
path.split('.').reduce(function(acc, name) {
|
|
506
|
+
acc.push( (acc.length ? acc[acc.length-1] + '.' : '') + name );
|
|
507
|
+
return acc;
|
|
508
|
+
},result);
|
|
509
|
+
return result;
|
|
510
|
+
}
|
|
488
511
|
};
|
|
489
512
|
|
|
490
|
-
|
|
513
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
514
|
+
module.exports = path;
|
|
515
|
+
} else {
|
|
516
|
+
if (!global.simply) {
|
|
517
|
+
global.simply = {};
|
|
518
|
+
}
|
|
519
|
+
global.simply.path = path;
|
|
520
|
+
}
|
|
521
|
+
})(this);
|
|
522
|
+
(function(global) {
|
|
523
|
+
'use strict';
|
|
491
524
|
|
|
492
|
-
|
|
525
|
+
var routeInfo = [];
|
|
526
|
+
var listeners = {
|
|
527
|
+
goto: {},
|
|
528
|
+
match: {},
|
|
529
|
+
call: {},
|
|
530
|
+
finish: {}
|
|
531
|
+
};
|
|
493
532
|
|
|
494
|
-
|
|
495
|
-
|
|
533
|
+
function getRegexpFromRoute(route) {
|
|
534
|
+
return new RegExp('^'+route.replace(/:\w+/g, '([^/]+)').replace(/:\*/, '(.*)'));
|
|
535
|
+
}
|
|
496
536
|
|
|
497
|
-
|
|
537
|
+
function parseRoutes(routes) {
|
|
538
|
+
var paths = Object.keys(routes);
|
|
539
|
+
var matchParams = /:(\w+|\*)/g;
|
|
540
|
+
var matches, params, path;
|
|
541
|
+
for (var i=0; i<paths.length; i++) {
|
|
542
|
+
path = paths[i];
|
|
543
|
+
matches = [];
|
|
544
|
+
params = [];
|
|
545
|
+
do {
|
|
546
|
+
matches = matchParams.exec(path);
|
|
547
|
+
if (matches) {
|
|
548
|
+
params.push(matches[1]);
|
|
549
|
+
}
|
|
550
|
+
} while(matches);
|
|
551
|
+
routeInfo.push({
|
|
552
|
+
match: getRegexpFromRoute(path),
|
|
553
|
+
params: params,
|
|
554
|
+
action: routes[path]
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}
|
|
498
558
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
559
|
+
var linkHandler = function(evt) {
|
|
560
|
+
if (evt.ctrlKey) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (evt.which != 1) {
|
|
564
|
+
return; // not a 'left' mouse click
|
|
565
|
+
}
|
|
566
|
+
var link = evt.target;
|
|
567
|
+
while (link && link.tagName!='A') {
|
|
568
|
+
link = link.parentElement;
|
|
569
|
+
}
|
|
570
|
+
if (link
|
|
571
|
+
&& link.pathname
|
|
572
|
+
&& link.hostname==global.location.hostname
|
|
573
|
+
&& !link.link
|
|
574
|
+
&& !link.dataset.simplyCommand
|
|
575
|
+
) {
|
|
576
|
+
let path = getPath(link.pathname+link.hash);
|
|
577
|
+
if ( !route.has(path) ) {
|
|
578
|
+
path = getPath(link.pathname);
|
|
503
579
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
580
|
+
if ( route.has(path) ) {
|
|
581
|
+
let params = runListeners('goto', { path: path});
|
|
582
|
+
if (params.path) {
|
|
583
|
+
route.goto(params.path);
|
|
584
|
+
}
|
|
585
|
+
evt.preventDefault();
|
|
509
586
|
return false;
|
|
510
587
|
}
|
|
511
|
-
listeners[name] = listeners[name].filter(function(listener) {
|
|
512
|
-
return listener!=callback;
|
|
513
|
-
});
|
|
514
588
|
}
|
|
515
589
|
};
|
|
516
590
|
|
|
517
|
-
var
|
|
518
|
-
|
|
519
|
-
if (nodes) {
|
|
520
|
-
[].forEach.call(nodes, function(node) {
|
|
521
|
-
callListeners(node);
|
|
522
|
-
});
|
|
523
|
-
}
|
|
591
|
+
var options = {
|
|
592
|
+
root: '/'
|
|
524
593
|
};
|
|
525
594
|
|
|
526
|
-
var
|
|
527
|
-
if (
|
|
528
|
-
|
|
595
|
+
var getPath = function(path) {
|
|
596
|
+
if (path.substring(0,options.root.length)==options.root
|
|
597
|
+
||
|
|
598
|
+
( options.root[options.root.length-1]=='/'
|
|
599
|
+
&& path.length==(options.root.length-1)
|
|
600
|
+
&& path == options.root.substring(0,path.length)
|
|
601
|
+
)
|
|
529
602
|
) {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
603
|
+
path = path.substring(options.root.length);
|
|
604
|
+
}
|
|
605
|
+
if (path[0]!='/' && path[0]!='#') {
|
|
606
|
+
path = '/'+path;
|
|
533
607
|
}
|
|
608
|
+
return path;
|
|
534
609
|
};
|
|
535
610
|
|
|
536
|
-
var
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
[].forEach.call(change.addedNodes, function(node) {
|
|
541
|
-
if (node.querySelectorAll) {
|
|
542
|
-
var toActivate = [].slice.call(node.querySelectorAll('[data-simply-activate]'));
|
|
543
|
-
if (node.matches('[data-simply-activate]')) {
|
|
544
|
-
toActivate.push(node);
|
|
545
|
-
}
|
|
546
|
-
activateNodes = activateNodes.concat(toActivate);
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
if (activateNodes.length) {
|
|
552
|
-
activateNodes.forEach(function(node) {
|
|
553
|
-
callListeners(node);
|
|
554
|
-
});
|
|
611
|
+
var getUrl = function(path) {
|
|
612
|
+
path = getPath(path);
|
|
613
|
+
if (options.root[options.root.length-1]==='/' && path[0]==='/') {
|
|
614
|
+
path = path.substring(1);
|
|
555
615
|
}
|
|
616
|
+
return options.root + path;
|
|
556
617
|
};
|
|
557
618
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
619
|
+
function runListeners(action, params) {
|
|
620
|
+
if (!Object.keys(listeners[action])) {
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
Object.keys(listeners[action]).forEach(function(route) {
|
|
624
|
+
var routeRe = getRegexpFromRoute(route);
|
|
625
|
+
if (routeRe.exec(params.path)) {
|
|
626
|
+
var result;
|
|
627
|
+
listeners[action][route].forEach(function(callback) {
|
|
628
|
+
result = callback.call(global, params);
|
|
629
|
+
if (result) {
|
|
630
|
+
params = result;
|
|
631
|
+
}
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
return params;
|
|
570
636
|
}
|
|
571
637
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
638
|
+
var route = {
|
|
639
|
+
handleEvents: function() {
|
|
640
|
+
global.addEventListener('popstate', function() {
|
|
641
|
+
if (route.match(getPath(document.location.pathname + document.location.hash)) === false) {
|
|
642
|
+
route.match(getPath(document.location.pathname));
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
global.document.addEventListener('click', linkHandler);
|
|
646
|
+
},
|
|
647
|
+
load: function(routes) {
|
|
648
|
+
parseRoutes(routes);
|
|
649
|
+
},
|
|
650
|
+
clear: function() {
|
|
651
|
+
routeInfo = [];
|
|
652
|
+
listeners = {
|
|
653
|
+
match: {},
|
|
654
|
+
call: {},
|
|
655
|
+
finish: {}
|
|
656
|
+
};
|
|
657
|
+
},
|
|
658
|
+
match: function(path, options) {
|
|
659
|
+
var args = {
|
|
660
|
+
path: path,
|
|
661
|
+
options: options
|
|
662
|
+
};
|
|
663
|
+
args = runListeners('match',args);
|
|
664
|
+
path = args.path ? args.path : path;
|
|
580
665
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
666
|
+
var matches;
|
|
667
|
+
if (!path) {
|
|
668
|
+
if (route.match(document.location.pathname+document.location.hash)) {
|
|
669
|
+
return true;
|
|
670
|
+
} else {
|
|
671
|
+
return route.match(document.location.pathname);
|
|
672
|
+
}
|
|
588
673
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
674
|
+
path = getPath(path);
|
|
675
|
+
for ( var i=0; i<routeInfo.length; i++) {
|
|
676
|
+
if (path && path[path.length-1]!='/') {
|
|
677
|
+
matches = routeInfo[i].match.exec(path+'/');
|
|
678
|
+
if (matches) {
|
|
679
|
+
path+='/';
|
|
680
|
+
history.replaceState({}, '', getUrl(path));
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
matches = routeInfo[i].match.exec(path);
|
|
684
|
+
if (matches && matches.length) {
|
|
685
|
+
var params = {};
|
|
686
|
+
routeInfo[i].params.forEach(function(key, i) {
|
|
687
|
+
if (key=='*') {
|
|
688
|
+
key = 'remainder';
|
|
689
|
+
}
|
|
690
|
+
params[key] = matches[i+1];
|
|
691
|
+
});
|
|
692
|
+
Object.assign(params, options);
|
|
693
|
+
args.route = route;
|
|
694
|
+
args.params = params;
|
|
695
|
+
args = runListeners('call', args);
|
|
696
|
+
params = args.params ? args.params : params;
|
|
697
|
+
args.result = routeInfo[i].action.call(route, params);
|
|
698
|
+
runListeners('finish', args);
|
|
699
|
+
return args.result;
|
|
700
|
+
}
|
|
603
701
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
702
|
+
return false;
|
|
703
|
+
},
|
|
704
|
+
goto: function(path) {
|
|
705
|
+
history.pushState({},'',getUrl(path));
|
|
706
|
+
return route.match(path);
|
|
707
|
+
},
|
|
708
|
+
has: function(path) {
|
|
709
|
+
path = getPath(path);
|
|
710
|
+
for ( var i=0; i<routeInfo.length; i++) {
|
|
711
|
+
var matches = routeInfo[i].match.exec(path);
|
|
712
|
+
if (matches && matches.length) {
|
|
713
|
+
return true;
|
|
714
|
+
}
|
|
612
715
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
for(var i=setters.length-1;i>=0;i--) {
|
|
619
|
-
if (el.matches(setters[i])) {
|
|
620
|
-
return fieldTypes[setters[i]];
|
|
716
|
+
return false;
|
|
717
|
+
},
|
|
718
|
+
addListener: function(action, route, callback) {
|
|
719
|
+
if (['goto','match','call','finish'].indexOf(action)==-1) {
|
|
720
|
+
throw new Error('Unknown action '+action);
|
|
621
721
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
function getPath(el, attribute) {
|
|
627
|
-
var attributes = attribute.split(',');
|
|
628
|
-
for (var attr of attributes) {
|
|
629
|
-
if (el.hasAttribute(attr)) {
|
|
630
|
-
return el.getAttribute(attr);
|
|
722
|
+
if (!listeners[action][route]) {
|
|
723
|
+
listeners[action][route] = [];
|
|
631
724
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
var myArguments = arguments;
|
|
640
|
-
var me = this;
|
|
641
|
-
if ( eventId ) {
|
|
725
|
+
listeners[action][route].push(callback);
|
|
726
|
+
},
|
|
727
|
+
removeListener: function(action, route, callback) {
|
|
728
|
+
if (['match','call','finish'].indexOf(action)==-1) {
|
|
729
|
+
throw new Error('Unknown action '+action);
|
|
730
|
+
}
|
|
731
|
+
if (!listeners[action][route]) {
|
|
642
732
|
return;
|
|
643
|
-
} else {
|
|
644
|
-
eventId = global.setTimeout( function() {
|
|
645
|
-
callbackFunction.apply(me, myArguments);
|
|
646
|
-
eventId = 0;
|
|
647
|
-
}, intervalTime );
|
|
648
733
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
}
|
|
734
|
+
listeners[action][route] = listeners[action][route].filter(function(listener) {
|
|
735
|
+
return listener != callback;
|
|
736
|
+
});
|
|
737
|
+
},
|
|
738
|
+
init: function(params) {
|
|
739
|
+
if (params.root) {
|
|
740
|
+
options.root = params.root;
|
|
741
|
+
}
|
|
657
742
|
}
|
|
658
|
-
|
|
659
|
-
})();
|
|
743
|
+
};
|
|
660
744
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
if (!this.config.model) {
|
|
667
|
-
this.config.model = {};
|
|
668
|
-
}
|
|
669
|
-
if (!this.config.attribute) {
|
|
670
|
-
this.config.attribute = 'data-simply-bind';
|
|
671
|
-
}
|
|
672
|
-
if (!this.config.selector) {
|
|
673
|
-
this.config.selector = '[data-simply-bind]';
|
|
674
|
-
}
|
|
675
|
-
if (!this.config.container) {
|
|
676
|
-
this.config.container = document;
|
|
677
|
-
}
|
|
678
|
-
if (typeof this.config.twoway == 'undefined') {
|
|
679
|
-
this.config.twoway = true;
|
|
745
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
746
|
+
module.exports = route;
|
|
747
|
+
} else {
|
|
748
|
+
if (!global.simply) {
|
|
749
|
+
global.simply = {};
|
|
680
750
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
751
|
+
global.simply.route = route;
|
|
752
|
+
}
|
|
753
|
+
})(this);
|
|
754
|
+
(function(global) {
|
|
755
|
+
'use strict';
|
|
756
|
+
|
|
757
|
+
var listeners = {};
|
|
758
|
+
|
|
759
|
+
var activate = {
|
|
760
|
+
addListener: function(name, callback) {
|
|
761
|
+
if (!listeners[name]) {
|
|
762
|
+
listeners[name] = [];
|
|
763
|
+
}
|
|
764
|
+
listeners[name].push(callback);
|
|
765
|
+
initialCall(name);
|
|
766
|
+
},
|
|
767
|
+
removeListener: function(name, callback) {
|
|
768
|
+
if (!listeners[name]) {
|
|
769
|
+
return false;
|
|
689
770
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
Object.assign(this.fieldTypes, this.config.fieldTypes);
|
|
693
|
-
}
|
|
694
|
-
this.attach(this.config.container.querySelectorAll(this.config.selector), this.config.model, force);
|
|
695
|
-
if (this.config.twoway) {
|
|
696
|
-
var self = this;
|
|
697
|
-
var observer = new MutationObserver(
|
|
698
|
-
throttle(function() {
|
|
699
|
-
runWhenIdle(function() {
|
|
700
|
-
self.attach(self.config.container.querySelectorAll(self.config.selector), self.config.model);
|
|
701
|
-
});
|
|
702
|
-
})
|
|
703
|
-
);
|
|
704
|
-
observer.observe(this.config.container, {
|
|
705
|
-
subtree: true,
|
|
706
|
-
childList: true
|
|
771
|
+
listeners[name] = listeners[name].filter(function(listener) {
|
|
772
|
+
return listener!=callback;
|
|
707
773
|
});
|
|
708
774
|
}
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
var focusedElement = null;
|
|
712
|
-
var initialized = new WeakMap();
|
|
713
|
-
var observers = new WeakMap();
|
|
714
|
-
var observersPaused = 0;
|
|
775
|
+
};
|
|
715
776
|
|
|
716
|
-
|
|
717
|
-
var
|
|
718
|
-
|
|
719
|
-
|
|
777
|
+
var initialCall = function(name) {
|
|
778
|
+
var nodes = document.querySelectorAll('[data-simply-activate="'+name+'"]');
|
|
779
|
+
if (nodes) {
|
|
780
|
+
[].forEach.call(nodes, function(node) {
|
|
781
|
+
callListeners(node);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
};
|
|
720
785
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
setValue(el, value, self);
|
|
728
|
-
}
|
|
786
|
+
var callListeners = function(node) {
|
|
787
|
+
if (node && node.dataset.simplyActivate
|
|
788
|
+
&& listeners[node.dataset.simplyActivate]
|
|
789
|
+
) {
|
|
790
|
+
listeners[node.dataset.simplyActivate].forEach(function(callback) {
|
|
791
|
+
callback.call(node);
|
|
729
792
|
});
|
|
730
|
-
}
|
|
793
|
+
}
|
|
794
|
+
};
|
|
731
795
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
focusedElement = null;
|
|
796
|
+
var handleChanges = function(changes) {
|
|
797
|
+
var activateNodes = [];
|
|
798
|
+
for (var change of changes) {
|
|
799
|
+
if (change.type=='childList') {
|
|
800
|
+
[].forEach.call(change.addedNodes, function(node) {
|
|
801
|
+
if (node.querySelectorAll) {
|
|
802
|
+
var toActivate = [].slice.call(node.querySelectorAll('[data-simply-activate]'));
|
|
803
|
+
if (node.matches('[data-simply-activate]')) {
|
|
804
|
+
toActivate.push(node);
|
|
805
|
+
}
|
|
806
|
+
activateNodes = activateNodes.concat(toActivate);
|
|
744
807
|
}
|
|
745
808
|
});
|
|
746
|
-
}, 250);
|
|
747
|
-
var observer = new MutationObserver(function() {
|
|
748
|
-
if (observersPaused) {
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
update();
|
|
752
|
-
});
|
|
753
|
-
observer.observe(el, {
|
|
754
|
-
characterData: true,
|
|
755
|
-
subtree: true,
|
|
756
|
-
childList: true,
|
|
757
|
-
attributes: true
|
|
758
|
-
});
|
|
759
|
-
if (!observers.has(el)) {
|
|
760
|
-
observers.set(el, []);
|
|
761
809
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
810
|
+
}
|
|
811
|
+
if (activateNodes.length) {
|
|
812
|
+
activateNodes.forEach(function(node) {
|
|
813
|
+
callListeners(node);
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
};
|
|
765
817
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
return;
|
|
772
|
-
}
|
|
773
|
-
initialized.set(el, true);
|
|
774
|
-
var selectors = Object.keys(self.fieldTypes);
|
|
775
|
-
for (var i=selectors.length-1; i>=0; i--) {
|
|
776
|
-
if (self.fieldTypes[selectors[i]].init && el.matches(selectors[i])) {
|
|
777
|
-
self.fieldTypes[selectors[i]].init.call(el, self);
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
};
|
|
818
|
+
var observer = new MutationObserver(handleChanges);
|
|
819
|
+
observer.observe(document, {
|
|
820
|
+
subtree: true,
|
|
821
|
+
childList: true
|
|
822
|
+
});
|
|
782
823
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
824
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
825
|
+
module.exports = activate;
|
|
826
|
+
} else {
|
|
827
|
+
if (!global.simply) {
|
|
828
|
+
global.simply = {};
|
|
829
|
+
}
|
|
830
|
+
global.simply.activate = activate;
|
|
831
|
+
}
|
|
832
|
+
})(this);
|
|
833
|
+
(function(global) {
|
|
834
|
+
'use strict';
|
|
835
|
+
|
|
836
|
+
var knownCollections = {};
|
|
837
|
+
|
|
838
|
+
var collect = {
|
|
839
|
+
addListener: function(name, callback) {
|
|
840
|
+
if (!knownCollections[name]) {
|
|
841
|
+
knownCollections[name] = [];
|
|
787
842
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
el.dataset.simplyBound = 'Error: nested binding';
|
|
791
|
-
console.error('Error: found nested data-binding element:',el);
|
|
792
|
-
return;
|
|
843
|
+
if (knownCollections[name].indexOf(callback) == -1) {
|
|
844
|
+
knownCollections[name].push(callback);
|
|
793
845
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
846
|
+
},
|
|
847
|
+
removeListener: function(name, callback) {
|
|
848
|
+
if (knownCollections[name]) {
|
|
849
|
+
var index = knownCollections[name].indexOf(callback);
|
|
850
|
+
if (index>=0) {
|
|
851
|
+
knownCollections[name].splice(index, 1);
|
|
852
|
+
}
|
|
797
853
|
}
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
854
|
+
},
|
|
855
|
+
update: function(element, value) {
|
|
856
|
+
element.value = value;
|
|
857
|
+
element.dispatchEvent(new Event('change', {
|
|
858
|
+
bubbles: true,
|
|
859
|
+
cancelable: true
|
|
860
|
+
}));
|
|
802
861
|
}
|
|
803
862
|
};
|
|
804
863
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
864
|
+
function findCollection(el) {
|
|
865
|
+
while (el && !el.dataset.simplyCollection) {
|
|
866
|
+
el = el.parentElement;
|
|
867
|
+
}
|
|
868
|
+
return el;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
global.addEventListener('change', function(evt) {
|
|
872
|
+
var root = null;
|
|
873
|
+
var name = '';
|
|
874
|
+
if (evt.target.dataset.simplyElement) {
|
|
875
|
+
root = findCollection(evt.target);
|
|
876
|
+
if (root && root.dataset) {
|
|
877
|
+
name = root.dataset.simplyCollection;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (name && knownCollections[name]) {
|
|
881
|
+
var inputs = root.querySelectorAll('[data-simply-element]');
|
|
882
|
+
var elements = [].reduce.call(inputs, function(elements, input) {
|
|
883
|
+
elements[input.dataset.simplyElement] = input;
|
|
884
|
+
return elements;
|
|
885
|
+
}, {});
|
|
886
|
+
for (var i=knownCollections[name].length-1; i>=0; i--) {
|
|
887
|
+
var result = knownCollections[name][i].call(evt.target.form, elements);
|
|
888
|
+
if (result === false) {
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}, true);
|
|
812
894
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
}
|
|
895
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
896
|
+
module.exports = collect;
|
|
897
|
+
} else {
|
|
898
|
+
if (!global.simply) {
|
|
899
|
+
global.simply = {};
|
|
900
|
+
}
|
|
901
|
+
global.simply.collect = collect;
|
|
902
|
+
}
|
|
816
903
|
|
|
817
|
-
|
|
818
|
-
|
|
904
|
+
})(this);
|
|
905
|
+
(function(global) {
|
|
906
|
+
'use strict';
|
|
819
907
|
|
|
820
908
|
var defaultCommands = {
|
|
821
909
|
'simply-hide': function(el, value) {
|
|
@@ -830,7 +918,7 @@ this.simply = (function(simply, global) {
|
|
|
830
918
|
this.action('simply-show',target);
|
|
831
919
|
}
|
|
832
920
|
},
|
|
833
|
-
'simply-select': function(value
|
|
921
|
+
'simply-select': function(el, value) {
|
|
834
922
|
var group = el.dataset.simplyGroup;
|
|
835
923
|
var target = this.app.get(value);
|
|
836
924
|
var targetGroup = (target ? target.dataset.simplyGroup : null);
|
|
@@ -861,6 +949,16 @@ this.simply = (function(simply, global) {
|
|
|
861
949
|
{
|
|
862
950
|
match: 'input,select,textarea',
|
|
863
951
|
get: function(el) {
|
|
952
|
+
if (el.tagName==='SELECT' && el.multiple) {
|
|
953
|
+
var values = [], opt;
|
|
954
|
+
for (var i=0,l=el.options.length;i<l;i++) {
|
|
955
|
+
var opt = el.options[i];
|
|
956
|
+
if (opt.selected) {
|
|
957
|
+
values.push(opt.value);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return values;
|
|
961
|
+
}
|
|
864
962
|
return el.dataset.simplyValue || el.value;
|
|
865
963
|
},
|
|
866
964
|
check: function(el, evt) {
|
|
@@ -881,7 +979,19 @@ this.simply = (function(simply, global) {
|
|
|
881
979
|
get: function(el) {
|
|
882
980
|
var data = {};
|
|
883
981
|
[].forEach.call(el.elements, function(el) {
|
|
884
|
-
|
|
982
|
+
if (el.tagName=='INPUT' && (el.type=='checkbox' || el.type=='radio')) {
|
|
983
|
+
if (!el.checked) {
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
if (data[el.name] && !Array.isArray(data[el.name])) {
|
|
988
|
+
data[el.name] = [data[el.name]];
|
|
989
|
+
}
|
|
990
|
+
if (Array.isArray(data[el.name])) {
|
|
991
|
+
data[el.name].push(el.value);
|
|
992
|
+
} else {
|
|
993
|
+
data[el.name] = el.value;
|
|
994
|
+
}
|
|
885
995
|
});
|
|
886
996
|
return data;//new FormData(el);
|
|
887
997
|
},
|
|
@@ -927,7 +1037,7 @@ this.simply = (function(simply, global) {
|
|
|
927
1037
|
return null;
|
|
928
1038
|
}
|
|
929
1039
|
|
|
930
|
-
|
|
1040
|
+
var command = function(app, inCommands) {
|
|
931
1041
|
|
|
932
1042
|
var commands = Object.create(defaultCommands);
|
|
933
1043
|
for (var i in inCommands) {
|
|
@@ -968,62 +1078,202 @@ this.simply = (function(simply, global) {
|
|
|
968
1078
|
return false;
|
|
969
1079
|
}
|
|
970
1080
|
}
|
|
971
|
-
};
|
|
972
|
-
|
|
973
|
-
app.container.addEventListener('click', commandHandler);
|
|
974
|
-
app.container.addEventListener('submit', commandHandler);
|
|
975
|
-
app.container.addEventListener('change', commandHandler);
|
|
976
|
-
app.container.addEventListener('input', commandHandler);
|
|
977
|
-
|
|
978
|
-
return commands;
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
app.container.addEventListener('click', commandHandler);
|
|
1084
|
+
app.container.addEventListener('submit', commandHandler);
|
|
1085
|
+
app.container.addEventListener('change', commandHandler);
|
|
1086
|
+
app.container.addEventListener('input', commandHandler);
|
|
1087
|
+
|
|
1088
|
+
return commands;
|
|
1089
|
+
};
|
|
1090
|
+
|
|
1091
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1092
|
+
module.exports = command;
|
|
1093
|
+
} else {
|
|
1094
|
+
if (!global.simply) {
|
|
1095
|
+
global.simply = {};
|
|
1096
|
+
}
|
|
1097
|
+
global.simply.command = command;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
})(this);
|
|
1101
|
+
(function(global) {
|
|
1102
|
+
'use strict';
|
|
1103
|
+
|
|
1104
|
+
function keyboard(app, config) {
|
|
1105
|
+
var keys = config;
|
|
1106
|
+
|
|
1107
|
+
if (!app) {
|
|
1108
|
+
app = {};
|
|
1109
|
+
}
|
|
1110
|
+
if (!app.container) {
|
|
1111
|
+
app.container = document.body;
|
|
1112
|
+
}
|
|
1113
|
+
app.container.addEventListener('keydown', (e) => {
|
|
1114
|
+
if (e.isComposing || e.keyCode === 229) {
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
if (e.defaultPrevented) {
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
if (!e.target) {
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
let selectedKeyboard = 'default';
|
|
1125
|
+
if (e.target.closest('[data-simply-keyboard]')) {
|
|
1126
|
+
selectedKeyboard = e.target.closest('[data-simply-keyboard]').dataset.simplyKeyboard;
|
|
1127
|
+
}
|
|
1128
|
+
if (keys[selectedKeyboard] && keys[selectedKeyboard][e.code]) {
|
|
1129
|
+
keys[selectedKeyboard][e.code].call(app,e);
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
return keys;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1138
|
+
module.exports = keyboard;
|
|
1139
|
+
} else {
|
|
1140
|
+
if (!global.simply) {
|
|
1141
|
+
global.simply = {};
|
|
1142
|
+
}
|
|
1143
|
+
global.simply.keyboard = keyboard;
|
|
1144
|
+
}
|
|
1145
|
+
})(this);
|
|
1146
|
+
(function(global) {
|
|
1147
|
+
'use strict';
|
|
1148
|
+
|
|
1149
|
+
var defaultActions = {
|
|
1150
|
+
'simply-hide': function(el) {
|
|
1151
|
+
el.classList.remove('simply-visible');
|
|
1152
|
+
return Promise.resolve();
|
|
1153
|
+
},
|
|
1154
|
+
'simply-show': function(el) {
|
|
1155
|
+
el.classList.add('simply-visible');
|
|
1156
|
+
return Promise.resolve();
|
|
1157
|
+
},
|
|
1158
|
+
'simply-select': function(el,group,target,targetGroup) {
|
|
1159
|
+
if (group) {
|
|
1160
|
+
this.call('simply-deselect', this.app.container.querySelectorAll('[data-simply-group='+group+']'));
|
|
1161
|
+
}
|
|
1162
|
+
el.classList.add('simply-selected');
|
|
1163
|
+
if (target) {
|
|
1164
|
+
this.call('simply-select',target,targetGroup);
|
|
1165
|
+
}
|
|
1166
|
+
return Promise.resolve();
|
|
1167
|
+
},
|
|
1168
|
+
'simply-toggle-select': function(el,group,target,targetGroup) {
|
|
1169
|
+
if (!el.classList.contains('simply-selected')) {
|
|
1170
|
+
this.call('simply-select',el,group,target,targetGroup);
|
|
1171
|
+
} else {
|
|
1172
|
+
this.call('simply-deselect',el,target);
|
|
1173
|
+
}
|
|
1174
|
+
return Promise.resolve();
|
|
1175
|
+
},
|
|
1176
|
+
'simply-toggle-class': function(el,className,target) {
|
|
1177
|
+
if (!target) {
|
|
1178
|
+
target = el;
|
|
1179
|
+
}
|
|
1180
|
+
return Promise.resolve(target.classList.toggle(className));
|
|
1181
|
+
},
|
|
1182
|
+
'simply-deselect': function(el,target) {
|
|
1183
|
+
if ( typeof el.length=='number' && typeof el.item=='function') {
|
|
1184
|
+
el = Array.prototype.slice.call(el);
|
|
1185
|
+
}
|
|
1186
|
+
if ( Array.isArray(el) ) {
|
|
1187
|
+
for (var i=0,l=el.length; i<l; i++) {
|
|
1188
|
+
this.call('simply-deselect',el[i],target);
|
|
1189
|
+
target = null;
|
|
1190
|
+
}
|
|
1191
|
+
} else {
|
|
1192
|
+
el.classList.remove('simply-selected');
|
|
1193
|
+
if (target) {
|
|
1194
|
+
this.call('simply-deselect',target);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
return Promise.resolve();
|
|
1198
|
+
},
|
|
1199
|
+
'simply-fullscreen': function(target) {
|
|
1200
|
+
var methods = {
|
|
1201
|
+
'requestFullscreen':{exit:'exitFullscreen',event:'fullscreenchange',el:'fullscreenElement'},
|
|
1202
|
+
'webkitRequestFullScreen':{exit:'webkitCancelFullScreen',event:'webkitfullscreenchange',el:'webkitFullscreenElement'},
|
|
1203
|
+
'msRequestFullscreen':{exit:'msExitFullscreen',event:'MSFullscreenChange',el:'msFullscreenElement'},
|
|
1204
|
+
'mozRequestFullScreen':{exit:'mozCancelFullScreen',event:'mozfullscreenchange',el:'mozFullScreenElement'}
|
|
1205
|
+
};
|
|
1206
|
+
for ( var i in methods ) {
|
|
1207
|
+
if ( typeof document.documentElement[i] != 'undefined' ) {
|
|
1208
|
+
var requestMethod = i;
|
|
1209
|
+
var cancelMethod = methods[i].exit;
|
|
1210
|
+
var event = methods[i].event;
|
|
1211
|
+
var element = methods[i].el;
|
|
1212
|
+
break;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
if ( !requestMethod ) {
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
if (!target.classList.contains('simply-fullscreen')) {
|
|
1219
|
+
target.classList.add('simply-fullscreen');
|
|
1220
|
+
target[requestMethod]();
|
|
1221
|
+
var exit = function() {
|
|
1222
|
+
if ( !document[element] ) {
|
|
1223
|
+
target.classList.remove('simply-fullscreen');
|
|
1224
|
+
document.removeEventListener(event,exit);
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
document.addEventListener(event,exit);
|
|
1228
|
+
} else {
|
|
1229
|
+
target.classList.remove('simply-fullscreen');
|
|
1230
|
+
document[cancelMethod]();
|
|
1231
|
+
}
|
|
1232
|
+
return Promise.resolve();
|
|
1233
|
+
}
|
|
979
1234
|
};
|
|
980
1235
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
simply.view = function(app, view) {
|
|
987
|
-
|
|
988
|
-
app.view = view || {};
|
|
1236
|
+
var action = function(app, inActions) {
|
|
1237
|
+
var actions = Object.create(defaultActions);
|
|
1238
|
+
for ( var i in inActions ) {
|
|
1239
|
+
actions[i] = inActions[i];
|
|
1240
|
+
}
|
|
989
1241
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
var
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
app.view[key] = data[key];
|
|
996
|
-
});
|
|
1242
|
+
actions.app = app;
|
|
1243
|
+
actions.call = function(name) {
|
|
1244
|
+
var params = Array.prototype.slice.call(arguments);
|
|
1245
|
+
params.shift();
|
|
1246
|
+
return this[name].apply(this, params);
|
|
997
1247
|
};
|
|
1248
|
+
return actions;
|
|
1249
|
+
};
|
|
998
1250
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
});
|
|
1251
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1252
|
+
module.exports = action;
|
|
1253
|
+
} else {
|
|
1254
|
+
if (!global.simply) {
|
|
1255
|
+
global.simply = {};
|
|
1005
1256
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
};
|
|
1257
|
+
global.simply.action = action;
|
|
1258
|
+
}
|
|
1009
1259
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1260
|
+
})(this);
|
|
1261
|
+
(function(global) {
|
|
1262
|
+
'use strict';
|
|
1013
1263
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1264
|
+
var resize = function(app, config) {
|
|
1265
|
+
if (!config) {
|
|
1266
|
+
config = {};
|
|
1267
|
+
}
|
|
1268
|
+
if (!config.sizes) {
|
|
1269
|
+
config.sizes = {
|
|
1270
|
+
'simply-tiny' : 0,
|
|
1271
|
+
'simply-xsmall' : 480,
|
|
1272
|
+
'simply-small' : 768,
|
|
1273
|
+
'simply-medium' : 992,
|
|
1274
|
+
'simply-large' : 1200
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1027
1277
|
|
|
1028
1278
|
var lastSize = 0;
|
|
1029
1279
|
function resizeSniffer() {
|
|
@@ -1042,6 +1292,7 @@ this.simply = (function(simply, global) {
|
|
|
1042
1292
|
} else {
|
|
1043
1293
|
if ( !app.container.classList.contains(match) ) {
|
|
1044
1294
|
app.container.classList.add(match);
|
|
1295
|
+
match = sizes.pop(); // skip to next match to remove these
|
|
1045
1296
|
}
|
|
1046
1297
|
break;
|
|
1047
1298
|
}
|
|
@@ -1051,7 +1302,7 @@ this.simply = (function(simply, global) {
|
|
|
1051
1302
|
if ( app.container.classList.contains(match)) {
|
|
1052
1303
|
app.container.classList.remove(match);
|
|
1053
1304
|
}
|
|
1054
|
-
match=sizes.pop();
|
|
1305
|
+
match = sizes.pop();
|
|
1055
1306
|
}
|
|
1056
1307
|
var toolbars = app.container.querySelectorAll('.simply-toolbar');
|
|
1057
1308
|
[].forEach.call(toolbars, function(toolbar) {
|
|
@@ -1075,534 +1326,740 @@ this.simply = (function(simply, global) {
|
|
|
1075
1326
|
});
|
|
1076
1327
|
}
|
|
1077
1328
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
return simply;
|
|
1329
|
+
return resizeSniffer;
|
|
1330
|
+
};
|
|
1082
1331
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
if (!options.container) {
|
|
1089
|
-
console.warn('No simply.app application container element specified, using document.body.');
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
function simplyApp(options) {
|
|
1093
|
-
if (!options) {
|
|
1094
|
-
options = {};
|
|
1095
|
-
}
|
|
1096
|
-
if ( options.routes ) {
|
|
1097
|
-
simply.route.load(options.routes);
|
|
1098
|
-
simply.route.handleEvents();
|
|
1099
|
-
global.setTimeout(function() {
|
|
1100
|
-
simply.route.match(global.location.pathname);
|
|
1101
|
-
});
|
|
1102
|
-
}
|
|
1103
|
-
this.container = options.container || document.body;
|
|
1104
|
-
this.actions = simply.action ? simply.action(this, options.actions) : false;
|
|
1105
|
-
this.commands = simply.command ? simply.command(this, options.commands) : false;
|
|
1106
|
-
this.resize = simply.resize ? simply.resize(this, options.resize) : false;
|
|
1107
|
-
this.view = simply.view ? simply.view(this, options.view) : false;
|
|
1108
|
-
if (!(global.editor && global.editor.field) && simply.bind) {
|
|
1109
|
-
// skip simplyview databinding if SimplyEdit is loaded
|
|
1110
|
-
options.bind = simply.render(options.bind || {});
|
|
1111
|
-
options.bind.model = this.view;
|
|
1112
|
-
options.bind.container = this.container;
|
|
1113
|
-
this.bind = options.bindings = simply.bind(options.bind);
|
|
1114
|
-
}
|
|
1332
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1333
|
+
module.exports = resize;
|
|
1334
|
+
} else {
|
|
1335
|
+
if (!global.simply) {
|
|
1336
|
+
global.simply = {};
|
|
1115
1337
|
}
|
|
1338
|
+
global.simply.resize = resize;
|
|
1339
|
+
}
|
|
1340
|
+
})(this);(function (global) {
|
|
1341
|
+
'use strict';
|
|
1116
1342
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1343
|
+
var throttle = function( callbackFunction, intervalTime ) {
|
|
1344
|
+
var eventId = 0;
|
|
1345
|
+
return function() {
|
|
1346
|
+
var myArguments = arguments;
|
|
1347
|
+
var me = this;
|
|
1348
|
+
if ( eventId ) {
|
|
1349
|
+
return;
|
|
1350
|
+
} else {
|
|
1351
|
+
eventId = global.setTimeout( function() {
|
|
1352
|
+
callbackFunction.apply(me, myArguments);
|
|
1353
|
+
eventId = 0;
|
|
1354
|
+
}, intervalTime );
|
|
1355
|
+
}
|
|
1119
1356
|
};
|
|
1120
|
-
|
|
1121
|
-
var app = new simplyApp(options);
|
|
1122
|
-
|
|
1123
|
-
return app;
|
|
1124
1357
|
};
|
|
1125
1358
|
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1359
|
+
var runWhenIdle = (function() {
|
|
1360
|
+
if (global.requestIdleCallback) {
|
|
1361
|
+
return function(callback) {
|
|
1362
|
+
global.requestIdleCallback(callback, {timeout: 500});
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
return global.requestAnimationFrame;
|
|
1366
|
+
})();
|
|
1129
1367
|
|
|
1130
|
-
var
|
|
1368
|
+
var rebaseHref = function(relative, base) {
|
|
1369
|
+
if (/^[a-z-]*:?\//.test(relative)) {
|
|
1370
|
+
return relative; // absolute href, no need to rebase
|
|
1371
|
+
}
|
|
1131
1372
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
var
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
if (matches) {
|
|
1143
|
-
params.push(matches[1]);
|
|
1144
|
-
}
|
|
1145
|
-
} while(matches);
|
|
1146
|
-
routeInfo.push({
|
|
1147
|
-
match: new RegExp(path.replace(/:\w+/g, '([^/]+)').replace(/:\*/, '(.*)')),
|
|
1148
|
-
params: params,
|
|
1149
|
-
action: routes[path]
|
|
1150
|
-
});
|
|
1373
|
+
var stack = base.split('/'),
|
|
1374
|
+
parts = relative.split('/');
|
|
1375
|
+
stack.pop(); // remove current file name (or empty string)
|
|
1376
|
+
for (var i=0; i<parts.length; i++) {
|
|
1377
|
+
if (parts[i] == '.')
|
|
1378
|
+
continue;
|
|
1379
|
+
if (parts[i] == '..')
|
|
1380
|
+
stack.pop();
|
|
1381
|
+
else
|
|
1382
|
+
stack.push(parts[i]);
|
|
1151
1383
|
}
|
|
1384
|
+
return stack.join('/');
|
|
1385
|
+
};
|
|
1386
|
+
|
|
1387
|
+
var observer, loaded = {};
|
|
1388
|
+
var head = global.document.querySelector('head');
|
|
1389
|
+
var currentScript = global.document.currentScript;
|
|
1390
|
+
if (!currentScript) {
|
|
1391
|
+
var getScriptURL = (function() {
|
|
1392
|
+
var scripts = document.getElementsByTagName('script');
|
|
1393
|
+
var index = scripts.length - 1;
|
|
1394
|
+
var myScript = scripts[index];
|
|
1395
|
+
return function() { return myScript.src; };
|
|
1396
|
+
})();
|
|
1397
|
+
var currentScriptURL = getScriptURL();
|
|
1398
|
+
} else {
|
|
1399
|
+
var currentScriptURL = currentScript.src;
|
|
1152
1400
|
}
|
|
1153
1401
|
|
|
1154
|
-
var
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
&& !link.dataset.simplyCommand
|
|
1170
|
-
&& simply.route.has(link.pathname)
|
|
1171
|
-
) {
|
|
1172
|
-
simply.route.goto(link.pathname);
|
|
1173
|
-
evt.preventDefault();
|
|
1174
|
-
return false;
|
|
1175
|
-
}
|
|
1402
|
+
var waitForPreviousScripts = function() {
|
|
1403
|
+
// because of the async=false attribute, this script will run after
|
|
1404
|
+
// the previous scripts have been loaded and run
|
|
1405
|
+
// simply.include.next.js only fires the simply-next-script event
|
|
1406
|
+
// that triggers the Promise.resolve method
|
|
1407
|
+
return new Promise(function(resolve) {
|
|
1408
|
+
var next = global.document.createElement('script');
|
|
1409
|
+
next.src = rebaseHref('simply.include.next.js', currentScriptURL);
|
|
1410
|
+
next.async = false;
|
|
1411
|
+
global.document.addEventListener('simply-include-next', function() {
|
|
1412
|
+
head.removeChild(next);
|
|
1413
|
+
resolve();
|
|
1414
|
+
}, { once: true, passive: true});
|
|
1415
|
+
head.appendChild(next);
|
|
1416
|
+
});
|
|
1176
1417
|
};
|
|
1177
1418
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
match: function(path, options) {
|
|
1189
|
-
var matches;
|
|
1190
|
-
for ( var i=0; i<routeInfo.length; i++) {
|
|
1191
|
-
if (path[path.length-1]!='/') {
|
|
1192
|
-
matches = routeInfo[i].match.exec(path+'/');
|
|
1193
|
-
if (matches) {
|
|
1194
|
-
path+='/';
|
|
1195
|
-
history.replaceState({}, '', path);
|
|
1196
|
-
}
|
|
1419
|
+
var scriptLocations = [];
|
|
1420
|
+
|
|
1421
|
+
var include = {
|
|
1422
|
+
scripts: function(scripts, base) {
|
|
1423
|
+
var arr = [];
|
|
1424
|
+
for(var i = scripts.length; i--; arr.unshift(scripts[i]));
|
|
1425
|
+
var importScript = function() {
|
|
1426
|
+
var script = arr.shift();
|
|
1427
|
+
if (!script) {
|
|
1428
|
+
return;
|
|
1197
1429
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1430
|
+
var attrs = [].map.call(script.attributes, function(attr) {
|
|
1431
|
+
return attr.name;
|
|
1432
|
+
});
|
|
1433
|
+
var clone = global.document.createElement('script');
|
|
1434
|
+
attrs.forEach(function(attr) {
|
|
1435
|
+
clone.setAttribute(attr, script.getAttribute(attr));
|
|
1436
|
+
});
|
|
1437
|
+
clone.removeAttribute('data-simply-location');
|
|
1438
|
+
if (!clone.src) {
|
|
1439
|
+
// this is an inline script, so copy the content and wait for previous scripts to run
|
|
1440
|
+
clone.innerHTML = script.innerHTML;
|
|
1441
|
+
waitForPreviousScripts()
|
|
1442
|
+
.then(function() {
|
|
1443
|
+
var node = scriptLocations[script.dataset.simplyLocation];
|
|
1444
|
+
node.parentNode.insertBefore(clone, node);
|
|
1445
|
+
node.parentNode.removeChild(node);
|
|
1446
|
+
importScript();
|
|
1447
|
+
});
|
|
1448
|
+
} else {
|
|
1449
|
+
clone.src = rebaseHref(clone.src, base);
|
|
1450
|
+
if (!clone.hasAttribute('async') && !clone.hasAttribute('defer')) {
|
|
1451
|
+
clone.async = false; //important! do not use clone.setAttribute('async', false) - it has no effect
|
|
1452
|
+
}
|
|
1453
|
+
var node = scriptLocations[script.dataset.simplyLocation];
|
|
1454
|
+
node.parentNode.insertBefore(clone, node);
|
|
1455
|
+
node.parentNode.removeChild(node);
|
|
1456
|
+
loaded[clone.src]=true;
|
|
1457
|
+
importScript();
|
|
1209
1458
|
}
|
|
1459
|
+
};
|
|
1460
|
+
if (arr.length) {
|
|
1461
|
+
importScript();
|
|
1210
1462
|
}
|
|
1211
1463
|
},
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1464
|
+
html: function(html, link) {
|
|
1465
|
+
var fragment = global.document.createRange().createContextualFragment(html);
|
|
1466
|
+
var stylesheets = fragment.querySelectorAll('link[rel="stylesheet"],style');
|
|
1467
|
+
// add all stylesheets to head
|
|
1468
|
+
[].forEach.call(stylesheets, function(stylesheet) {
|
|
1469
|
+
if (stylesheet.href) {
|
|
1470
|
+
stylesheet.href = rebaseHref(stylesheet.href, link.href);
|
|
1471
|
+
}
|
|
1472
|
+
head.appendChild(stylesheet);
|
|
1473
|
+
});
|
|
1474
|
+
// remove the scripts from the fragment, as they will not run in the
|
|
1475
|
+
// order in which they are defined
|
|
1476
|
+
var scriptsFragment = global.document.createDocumentFragment();
|
|
1477
|
+
// FIXME: this loses the original position of the script
|
|
1478
|
+
// should add a placeholder so we can reinsert the clone
|
|
1479
|
+
var scripts = fragment.querySelectorAll('script');
|
|
1480
|
+
[].forEach.call(scripts, function(script) {
|
|
1481
|
+
var placeholder = global.document.createComment(script.src || 'inline script');
|
|
1482
|
+
script.parentNode.insertBefore(placeholder, script);
|
|
1483
|
+
script.dataset.simplyLocation = scriptLocations.length;
|
|
1484
|
+
scriptLocations.push(placeholder);
|
|
1485
|
+
scriptsFragment.appendChild(script);
|
|
1486
|
+
});
|
|
1487
|
+
// add the remainder before the include link
|
|
1488
|
+
link.parentNode.insertBefore(fragment, link ? link : null);
|
|
1489
|
+
global.setTimeout(function() {
|
|
1490
|
+
if (global.editor && global.editor.data && fragment.querySelector('[data-simply-field],[data-simply-list]')) {
|
|
1491
|
+
//TODO: remove this dependency and let simply.bind listen for dom node insertions (and simply-edit.js use simply.bind)
|
|
1492
|
+
global.editor.data.apply(global.editor.currentData, global.document);
|
|
1221
1493
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1494
|
+
simply.include.scripts(scriptsFragment.childNodes, link ? link.href : global.location.href );
|
|
1495
|
+
}, 10);
|
|
1224
1496
|
}
|
|
1225
1497
|
};
|
|
1226
1498
|
|
|
1227
|
-
|
|
1499
|
+
var included = {};
|
|
1500
|
+
var includeLinks = function(links) {
|
|
1501
|
+
// mark them as in progress, so handleChanges doesn't find them again
|
|
1502
|
+
var remainingLinks = [].reduce.call(links, function(remainder, link) {
|
|
1503
|
+
if (link.rel=='simply-include-once' && included[link.href]) {
|
|
1504
|
+
link.parentNode.removeChild(link);
|
|
1505
|
+
} else {
|
|
1506
|
+
included[link.href]=true;
|
|
1507
|
+
link.rel = 'simply-include-loading';
|
|
1508
|
+
remainder.push(link);
|
|
1509
|
+
}
|
|
1510
|
+
return remainder;
|
|
1511
|
+
}, []);
|
|
1512
|
+
[].forEach.call(remainingLinks, function(link) {
|
|
1513
|
+
if (!link.href) {
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
// fetch the html
|
|
1517
|
+
fetch(link.href)
|
|
1518
|
+
.then(function(response) {
|
|
1519
|
+
if (response.ok) {
|
|
1520
|
+
console.log('simply-include: loaded '+link.href);
|
|
1521
|
+
return response.text();
|
|
1522
|
+
} else {
|
|
1523
|
+
console.log('simply-include: failed to load '+link.href);
|
|
1524
|
+
}
|
|
1525
|
+
})
|
|
1526
|
+
.then(function(html) {
|
|
1527
|
+
// if succesfull import the html
|
|
1528
|
+
simply.include.html(html, link);
|
|
1529
|
+
// remove the include link
|
|
1530
|
+
link.parentNode.removeChild(link);
|
|
1531
|
+
});
|
|
1532
|
+
});
|
|
1533
|
+
};
|
|
1228
1534
|
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
* It doesn't register directly assigning new entries in an array on a previously
|
|
1238
|
-
* non-existant index.
|
|
1239
|
-
*
|
|
1240
|
-
* usage:
|
|
1241
|
-
*
|
|
1242
|
-
* (function) simply.observe( (object) model, (string) path, (function) callback)
|
|
1243
|
-
*
|
|
1244
|
-
* var model = { foo: { bar: 'baz' } };
|
|
1245
|
-
* var removeObserver = simply.observe(model, 'foo.bar', function(value, sourcePath) {
|
|
1246
|
-
* console.log(sourcePath+': '+value);
|
|
1247
|
-
* };
|
|
1248
|
-
*
|
|
1249
|
-
* The function returns a function that removes the observer when called.
|
|
1250
|
-
*
|
|
1251
|
-
* The component can observe in place changes in arrays, either by changing
|
|
1252
|
-
* an item in a specific index, by calling methods on the array that change
|
|
1253
|
-
* the array in place or by reassigning the array with a new value.
|
|
1254
|
-
*
|
|
1255
|
-
* The sourcePath contains the exact entry that was changed, the value is the
|
|
1256
|
-
* value for the path passed to simply.observe.
|
|
1257
|
-
* If an array method was called that changes the array in place, the sourcePath
|
|
1258
|
-
* also contains that method and its arguments JSON serialized.
|
|
1259
|
-
*
|
|
1260
|
-
* sourcePath parts are always seperated with '.', even for array indexes.
|
|
1261
|
-
* so if foo = [ 'bar' ], the path to 'bar' would be 'foo.0'
|
|
1262
|
-
*/
|
|
1535
|
+
var handleChanges = throttle(function() {
|
|
1536
|
+
runWhenIdle(function() {
|
|
1537
|
+
var links = global.document.querySelectorAll('link[rel="simply-include"],link[rel="simply-include-once"]');
|
|
1538
|
+
if (links.length) {
|
|
1539
|
+
includeLinks(links);
|
|
1540
|
+
}
|
|
1541
|
+
});
|
|
1542
|
+
});
|
|
1263
1543
|
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1544
|
+
var observe = function() {
|
|
1545
|
+
observer = new MutationObserver(handleChanges);
|
|
1546
|
+
observer.observe(global.document, {
|
|
1547
|
+
subtree: true,
|
|
1548
|
+
childList: true,
|
|
1549
|
+
});
|
|
1550
|
+
};
|
|
1270
1551
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
var parentListeners = new WeakMap();
|
|
1274
|
-
var childListeners = new WeakMap();
|
|
1275
|
-
var changesSignalled = {};
|
|
1276
|
-
var observersPaused = 0;
|
|
1552
|
+
observe();
|
|
1553
|
+
handleChanges(); // check if there are include links in the dom already
|
|
1277
1554
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1555
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1556
|
+
module.exports = include;
|
|
1557
|
+
} else {
|
|
1558
|
+
if (!global.simply) {
|
|
1559
|
+
global.simply = {};
|
|
1281
1560
|
}
|
|
1561
|
+
global.simply.include = include;
|
|
1562
|
+
}
|
|
1282
1563
|
|
|
1283
|
-
sourcePath = sourcePath ? sourcePath : path;
|
|
1284
|
-
changesSignalled = {};
|
|
1285
1564
|
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
changesSignalled[path] = true;
|
|
1291
|
-
callback(value, sourcePath);
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
};
|
|
1565
|
+
})(this);
|
|
1566
|
+
(function(global) {
|
|
1567
|
+
'use strict';
|
|
1568
|
+
var view = function(app, view) {
|
|
1295
1569
|
|
|
1296
|
-
|
|
1297
|
-
//previous version only triggered parentListeners when no changeListeners were
|
|
1298
|
-
//triggered. that created problems with arrays. make an exhaustive unit test.
|
|
1299
|
-
signalRecursion(model, path, value, sourcePath);
|
|
1300
|
-
|
|
1301
|
-
if (parentListeners.has(model) && parentListeners.get(model)[path]) {
|
|
1302
|
-
// parentListeners[model][path] contains child paths to signal change on
|
|
1303
|
-
// if a parent object is changed, this signals the change to the child objects
|
|
1304
|
-
parentListeners.get(model)[path].forEach(function(childPath) {
|
|
1305
|
-
if (!changesSignalled[childPath]) {
|
|
1306
|
-
var value = getByPath(model, childPath);
|
|
1307
|
-
if (value) {
|
|
1308
|
-
attach(model, childPath);
|
|
1309
|
-
}
|
|
1310
|
-
signalRecursion(model, childPath, value, sourcePath);
|
|
1311
|
-
changesSignalled[childPath] = true;
|
|
1312
|
-
}
|
|
1313
|
-
});
|
|
1314
|
-
}
|
|
1570
|
+
app.view = view || {};
|
|
1315
1571
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
// check if the parent object still has this child property
|
|
1325
|
-
//FIXME: add a setter trigger here to restore observers once the child property get set again
|
|
1572
|
+
var load = function() {
|
|
1573
|
+
var data = app.view;
|
|
1574
|
+
var path = global.editor.data.getDataPath(app.container);
|
|
1575
|
+
app.view = global.editor.currentData[path];
|
|
1576
|
+
Object.keys(data).forEach(function(key) {
|
|
1577
|
+
app.view[key] = data[key];
|
|
1578
|
+
});
|
|
1579
|
+
};
|
|
1326
1580
|
|
|
1327
|
-
|
|
1581
|
+
if (global.editor && global.editor.currentData) {
|
|
1582
|
+
load();
|
|
1583
|
+
} else {
|
|
1584
|
+
global.document.addEventListener('simply-content-loaded', function() {
|
|
1585
|
+
load();
|
|
1328
1586
|
});
|
|
1329
1587
|
}
|
|
1588
|
+
|
|
1589
|
+
return app.view;
|
|
1590
|
+
};
|
|
1330
1591
|
|
|
1592
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1593
|
+
module.exports = view;
|
|
1594
|
+
} else {
|
|
1595
|
+
if (!global.simply) {
|
|
1596
|
+
global.simply = {};
|
|
1597
|
+
}
|
|
1598
|
+
global.simply.view = view;
|
|
1331
1599
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
var curr = model;
|
|
1336
|
-
do {
|
|
1337
|
-
curr = curr[parts.shift()];
|
|
1338
|
-
} while (parts.length && curr);
|
|
1339
|
-
return curr;
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
function parent(path) {
|
|
1343
|
-
var parts = path.split('.');
|
|
1344
|
-
parts.pop();
|
|
1345
|
-
return parts.join('.');
|
|
1346
|
-
}
|
|
1600
|
+
})(this);
|
|
1601
|
+
(function(global) {
|
|
1602
|
+
'use strict';
|
|
1347
1603
|
|
|
1348
|
-
function
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
parent = (parent ? parent + '.' + head : head );
|
|
1363
|
-
} while (parents.length);
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
function onChildren(model, path, callback) {
|
|
1367
|
-
var onChildObjects = function(object, path, callback) {
|
|
1368
|
-
if (typeof object != 'object' || object == null) {
|
|
1369
|
-
return;
|
|
1370
|
-
}
|
|
1371
|
-
if (Array.isArray(object)) {
|
|
1372
|
-
return;
|
|
1373
|
-
}
|
|
1374
|
-
// register the current keys
|
|
1375
|
-
Object.keys(object).forEach(function(key) {
|
|
1376
|
-
callback(object, key, path+'.'+key);
|
|
1377
|
-
onChildObjects(object[key], path+'.'+key, callback);
|
|
1378
|
-
});
|
|
1604
|
+
function ViewModel(name, data, options) {
|
|
1605
|
+
this.name = name;
|
|
1606
|
+
this.data = data || [];
|
|
1607
|
+
this.view = {
|
|
1608
|
+
options: {},
|
|
1609
|
+
data: [] //Array.from(this.data).slice()
|
|
1610
|
+
};
|
|
1611
|
+
this.options = options || {};
|
|
1612
|
+
this.plugins = {
|
|
1613
|
+
start: [],
|
|
1614
|
+
select: [],
|
|
1615
|
+
order: [],
|
|
1616
|
+
render: [],
|
|
1617
|
+
finish: []
|
|
1379
1618
|
};
|
|
1380
|
-
var parent = getByPath(model, path);
|
|
1381
|
-
onChildObjects(parent, path, callback);
|
|
1382
1619
|
}
|
|
1383
1620
|
|
|
1384
|
-
function
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
});
|
|
1388
|
-
if (!allChildren.length) {
|
|
1389
|
-
return;
|
|
1621
|
+
ViewModel.prototype.update = function(params) {
|
|
1622
|
+
if (!params) {
|
|
1623
|
+
params = {};
|
|
1390
1624
|
}
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1625
|
+
if (params.data) {
|
|
1626
|
+
// this.data is a reference to the data passed, so that any changes in it will get applied
|
|
1627
|
+
// to the original
|
|
1628
|
+
this.data = params.data;
|
|
1629
|
+
}
|
|
1630
|
+
// the view is a shallow copy of the array, so that changes in sort order and filtering
|
|
1631
|
+
// won't get applied to the original, but databindings on its children will still work
|
|
1632
|
+
this.view.data = Array.from(this.data).slice();
|
|
1633
|
+
var plugins = this.plugins.start.concat(this.plugins.select, this.plugins.order, this.plugins.render, this.plugins.finish);
|
|
1634
|
+
var self = this;
|
|
1635
|
+
plugins.forEach(function(plugin) {
|
|
1636
|
+
plugin.call(self, params);
|
|
1403
1637
|
});
|
|
1404
|
-
}
|
|
1405
1638
|
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1639
|
+
if (global.editor) {
|
|
1640
|
+
global.editor.addDataSource(this.name,{
|
|
1641
|
+
load: function(el, callback) {
|
|
1642
|
+
callback(self.view.data);
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
updateDataSource(this.name);
|
|
1409
1646
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1647
|
+
};
|
|
1648
|
+
|
|
1649
|
+
ViewModel.prototype.addPlugin = function(pipe, plugin) {
|
|
1650
|
+
if (typeof this.plugins[pipe] == 'undefined') {
|
|
1651
|
+
throw new Error('Unknown pipeline '+pipe);
|
|
1412
1652
|
}
|
|
1413
|
-
|
|
1653
|
+
this.plugins[pipe].push(plugin);
|
|
1654
|
+
};
|
|
1655
|
+
|
|
1656
|
+
ViewModel.prototype.removePlugin = function(pipe, plugin) {
|
|
1657
|
+
if (typeof this.plugins[pipe] == 'undefined') {
|
|
1658
|
+
throw new Error('Unknown pipeline '+pipe);
|
|
1659
|
+
}
|
|
1660
|
+
this.plugins[pipe] = this.plugins[pipe].filter(function(p) {
|
|
1661
|
+
return p != plugin;
|
|
1662
|
+
});
|
|
1663
|
+
};
|
|
1664
|
+
|
|
1665
|
+
var updateDataSource = function(name) {
|
|
1666
|
+
global.document.querySelectorAll('[data-simply-data="'+name+'"]').forEach(function(list) {
|
|
1667
|
+
global.editor.list.applyDataSource(list, name);
|
|
1668
|
+
});
|
|
1669
|
+
};
|
|
1670
|
+
|
|
1671
|
+
var createSort = function(options) {
|
|
1672
|
+
var defaultOptions = {
|
|
1673
|
+
name: 'sort',
|
|
1674
|
+
getSort: function(params) {
|
|
1675
|
+
return Array.prototype.sort;
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
options = Object.assign(defaultOptions, options || {});
|
|
1414
1679
|
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
onParents(model, parentPath, function(parentOb, key, currPath) {
|
|
1420
|
-
if (!parentListeners.get(model)[currPath]) {
|
|
1421
|
-
parentListeners.get(model)[currPath] = [];
|
|
1680
|
+
return function(params) {
|
|
1681
|
+
this.options[options.name] = options;
|
|
1682
|
+
if (params[options.name]) {
|
|
1683
|
+
options = Object.assign(options, params[options.name]);
|
|
1422
1684
|
}
|
|
1423
|
-
|
|
1424
|
-
}
|
|
1685
|
+
this.view.data.sort(options.getSort.call(this, options));
|
|
1686
|
+
};
|
|
1687
|
+
};
|
|
1425
1688
|
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1689
|
+
var createPaging = function(options) {
|
|
1690
|
+
var defaultOptions = {
|
|
1691
|
+
name: 'paging',
|
|
1692
|
+
page: 1,
|
|
1693
|
+
pageSize: 100,
|
|
1694
|
+
max: 1,
|
|
1695
|
+
prev: 0,
|
|
1696
|
+
next: 0
|
|
1697
|
+
};
|
|
1698
|
+
options = Object.assign(defaultOptions, options || {});
|
|
1699
|
+
|
|
1700
|
+
return function(params) {
|
|
1701
|
+
this.options[options.name] = options;
|
|
1702
|
+
if (this.view.data) {
|
|
1703
|
+
options.max = Math.max(1, Math.ceil(Array.from(this.view.data).length / options.pageSize));
|
|
1704
|
+
} else {
|
|
1705
|
+
options.max = 1;
|
|
1706
|
+
}
|
|
1707
|
+
if (this.view.changed) {
|
|
1708
|
+
options.page = 1; // reset to page 1 when something in the view data has changed
|
|
1709
|
+
}
|
|
1710
|
+
if (params[options.name]) {
|
|
1711
|
+
options = Object.assign(options, params[options.name]);
|
|
1712
|
+
}
|
|
1713
|
+
options.page = Math.max(1, Math.min(options.max, options.page)); // clamp page nr
|
|
1714
|
+
options.prev = options.page - 1; // calculate previous page, 0 is allowed
|
|
1715
|
+
if (options.page<options.max) {
|
|
1716
|
+
options.next = options.page + 1;
|
|
1717
|
+
} else {
|
|
1718
|
+
options.next = 0; // no next page
|
|
1432
1719
|
}
|
|
1433
|
-
childListeners.get(model)[currPath].push(path);
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1436
1720
|
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1721
|
+
var start = (options.page - 1) * options.pageSize;
|
|
1722
|
+
var end = start + options.pageSize;
|
|
1723
|
+
|
|
1724
|
+
this.view.data = this.view.data.slice(start, end);
|
|
1725
|
+
};
|
|
1726
|
+
};
|
|
1727
|
+
|
|
1728
|
+
var createFilter = function(options) {
|
|
1729
|
+
var defaultOptions = {
|
|
1730
|
+
name: 'filter',
|
|
1731
|
+
label: 'A filter',
|
|
1732
|
+
getMatch: function(entry) {
|
|
1733
|
+
return false;
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
options = Object.assign(defaultOptions, options || {});
|
|
1737
|
+
if (options.init) {
|
|
1738
|
+
options.init.call(this, options);
|
|
1440
1739
|
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1740
|
+
return function(params) {
|
|
1741
|
+
this.options[options.name] = options;
|
|
1742
|
+
if (params[options.name]) {
|
|
1743
|
+
options = Object.assign(options, params[options.name]);
|
|
1744
|
+
}
|
|
1745
|
+
var match = options.getMatch.call(this, options);
|
|
1746
|
+
if (match) {
|
|
1747
|
+
options.enabled = true;
|
|
1748
|
+
this.view.data = this.view.data.filter(match);
|
|
1749
|
+
} else if (options.enabled) {
|
|
1750
|
+
options.enabled = false;
|
|
1751
|
+
}
|
|
1445
1752
|
}
|
|
1446
1753
|
}
|
|
1447
1754
|
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1755
|
+
var viewmodel = {
|
|
1756
|
+
create: function(name, data, options) {
|
|
1757
|
+
return new ViewModel(name, data, options);
|
|
1758
|
+
},
|
|
1759
|
+
createFilter: createFilter,
|
|
1760
|
+
createSort: createSort,
|
|
1761
|
+
createPaging: createPaging,
|
|
1762
|
+
updateDataSource: updateDataSource
|
|
1763
|
+
};
|
|
1451
1764
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1765
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1766
|
+
module.exports = viewmodel;
|
|
1767
|
+
} else {
|
|
1768
|
+
if (!global.simply) {
|
|
1769
|
+
global.simply = {};
|
|
1770
|
+
}
|
|
1771
|
+
global.simply.viewmodel = viewmodel;
|
|
1454
1772
|
}
|
|
1455
1773
|
|
|
1456
|
-
|
|
1774
|
+
})(this);(function(global) {
|
|
1775
|
+
'use strict';
|
|
1776
|
+
|
|
1777
|
+
var api = {
|
|
1778
|
+
/**
|
|
1779
|
+
* Returns a Proxy object that translates property access to a URL in the api
|
|
1780
|
+
* and method calls to a fetch on that URL.
|
|
1781
|
+
* @param options: a list of options for fetch(),
|
|
1782
|
+
* see the 'init' parameter at https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters
|
|
1783
|
+
* additionally:
|
|
1784
|
+
* - baseURL: (required) the endpoint of the API
|
|
1785
|
+
* - path: the current path in the API, is appended to the baseURL
|
|
1786
|
+
* - verbs: list of http verbs to allow as methods, default ['get','post']
|
|
1787
|
+
* - handlers.fetch: alternative fetch method
|
|
1788
|
+
* - handlers.result: alternative getResult method
|
|
1789
|
+
* - handlers.error: alternative error method
|
|
1790
|
+
* - user (and password): if set, a basic authentication header will be added
|
|
1791
|
+
* - paramsFormat: either 'formData', 'json' or 'search'. Default is search.
|
|
1792
|
+
* - responseFormat: test, formData, blob, json, arrayBuffer or unbuffered. Default is json.
|
|
1793
|
+
* @return Proxy
|
|
1794
|
+
*/
|
|
1795
|
+
proxy: function(options) {
|
|
1796
|
+
var cache = () => {};
|
|
1797
|
+
cache.$options = Object.assign({}, options);
|
|
1798
|
+
return new Proxy( cache, getApiHandler(cache.$options) );
|
|
1799
|
+
},
|
|
1457
1800
|
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1801
|
+
/**
|
|
1802
|
+
* Fetches the options.baseURL using the fetch api and returns a promise
|
|
1803
|
+
* Extra options in addition to those of global.fetch():
|
|
1804
|
+
* - user (and password): if set, a basic authentication header will be added
|
|
1805
|
+
* - paramsFormat: either 'formData', 'json' or 'search'
|
|
1806
|
+
* By default params, if set, will be added to the baseURL as searchParams
|
|
1807
|
+
* @param method one of the http verbs, e.g. get, post, etc.
|
|
1808
|
+
* @param options the options for fetch(), with some additions
|
|
1809
|
+
* @param params the parameters to send with the request, as javascript/json data
|
|
1810
|
+
* @return Promise
|
|
1811
|
+
*/
|
|
1812
|
+
fetch: function(method, params, options) {
|
|
1813
|
+
if (!options.url) {
|
|
1814
|
+
if (!options.baseURL) {
|
|
1815
|
+
throw new Error('No url or baseURL in options object');
|
|
1816
|
+
}
|
|
1817
|
+
while (options.baseURL[options.baseURL.length-1]=='/') {
|
|
1818
|
+
options.baseURL = options.baseURL.substr(0, options.baseURL.length-1);
|
|
1819
|
+
}
|
|
1820
|
+
var url = new URL(options.baseURL+options.path);
|
|
1821
|
+
} else {
|
|
1822
|
+
var url = options.url;
|
|
1823
|
+
}
|
|
1824
|
+
var fetchOptions = Object.assign({}, options);
|
|
1825
|
+
if (!fetchOptions.headers) {
|
|
1826
|
+
fetchOptions.headers = {};
|
|
1827
|
+
}
|
|
1828
|
+
if (params) {
|
|
1829
|
+
if (method=='GET') {
|
|
1830
|
+
var paramsFormat = 'search';
|
|
1831
|
+
} else {
|
|
1832
|
+
var paramsFormat = options.paramsFormat;
|
|
1833
|
+
}
|
|
1834
|
+
switch(paramsFormat) {
|
|
1835
|
+
case 'formData':
|
|
1836
|
+
var formData = new FormData();
|
|
1837
|
+
for (const name in params) {
|
|
1838
|
+
formData.append(name, params[name]);
|
|
1482
1839
|
}
|
|
1483
|
-
|
|
1840
|
+
if (!fetchOptions.headers['Content-Type']) {
|
|
1841
|
+
fetchOptions.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
1842
|
+
}
|
|
1843
|
+
break;
|
|
1844
|
+
case 'json':
|
|
1845
|
+
var formData = JSON.stringify(params);
|
|
1846
|
+
if (!fetchOptions.headers['Content-Type']) {
|
|
1847
|
+
fetchOptions.headers['Content-Type'] = 'application/json';
|
|
1848
|
+
}
|
|
1849
|
+
break;
|
|
1850
|
+
case 'search':
|
|
1851
|
+
var searchParams = url.searchParams; //new URLSearchParams(url.search.slice(1));
|
|
1852
|
+
for (const name in params) {
|
|
1853
|
+
searchParams.set(name, params[name]);
|
|
1854
|
+
}
|
|
1855
|
+
url.search = searchParams.toString();
|
|
1856
|
+
break;
|
|
1857
|
+
default:
|
|
1858
|
+
throw Error('Unknown options.paramsFormat '+options.paramsFormat+'. Select one of formData, json or search.');
|
|
1859
|
+
break;
|
|
1484
1860
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1861
|
+
}
|
|
1862
|
+
if (formData) {
|
|
1863
|
+
fetchOptions.body = formData
|
|
1864
|
+
}
|
|
1865
|
+
if (options.user) {
|
|
1866
|
+
fetchOptions.headers['Authorization'] = 'Basic '+btoa(options.user+':'+options.password);
|
|
1867
|
+
}
|
|
1868
|
+
fetchOptions.method = method.toUpperCase();
|
|
1869
|
+
var fetchURL = url.toString()
|
|
1870
|
+
return fetch(fetchURL, fetchOptions);
|
|
1871
|
+
},
|
|
1872
|
+
/**
|
|
1873
|
+
* Creates a function to call one or more graphql queries
|
|
1874
|
+
*/
|
|
1875
|
+
graphqlQuery: function(url, query, options) {
|
|
1876
|
+
options = Object.assign({ paramsFormat: 'json', url: url, responseFormat: 'json' }, options);
|
|
1877
|
+
return function(params, operationName) {
|
|
1878
|
+
let postParams = {
|
|
1879
|
+
query: query
|
|
1880
|
+
};
|
|
1881
|
+
if (operationName) {
|
|
1882
|
+
postParams.operationName = operationName;
|
|
1883
|
+
}
|
|
1884
|
+
postParams.variables = params || {};
|
|
1885
|
+
return simply.api.fetch('POST', postParams, options )
|
|
1886
|
+
.then(function(response) {
|
|
1887
|
+
return simply.api.getResult(response, options);
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
},
|
|
1891
|
+
/**
|
|
1892
|
+
* Handles the response and returns a Promise with the response data as specified
|
|
1893
|
+
* @param response Response
|
|
1894
|
+
* @param options
|
|
1895
|
+
* - responseFormat: one of 'text', 'formData', 'blob', 'arrayBuffer', 'unbuffered' or 'json'.
|
|
1896
|
+
* The default is json.
|
|
1897
|
+
*/
|
|
1898
|
+
getResult: function(response, options) {
|
|
1899
|
+
if (response.ok) {
|
|
1900
|
+
switch(options.responseFormat) {
|
|
1901
|
+
case 'text':
|
|
1902
|
+
return response.text();
|
|
1903
|
+
break;
|
|
1904
|
+
case 'formData':
|
|
1905
|
+
return response.formData();
|
|
1906
|
+
break;
|
|
1907
|
+
case 'blob':
|
|
1908
|
+
return response.blob();
|
|
1909
|
+
break;
|
|
1910
|
+
case 'arrayBuffer':
|
|
1911
|
+
return response.arrayBuffer();
|
|
1912
|
+
break;
|
|
1913
|
+
case 'unbuffered':
|
|
1914
|
+
return response.body;
|
|
1915
|
+
break;
|
|
1916
|
+
case 'json':
|
|
1917
|
+
default:
|
|
1918
|
+
return response.json();
|
|
1919
|
+
break;
|
|
1920
|
+
}
|
|
1921
|
+
} else {
|
|
1922
|
+
throw {
|
|
1923
|
+
status: response.status,
|
|
1924
|
+
message: response.statusText,
|
|
1925
|
+
response: response
|
|
1492
1926
|
}
|
|
1493
1927
|
}
|
|
1494
|
-
|
|
1928
|
+
},
|
|
1495
1929
|
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
object[key] = value;
|
|
1501
|
-
},
|
|
1502
|
-
configurable: true,
|
|
1503
|
-
readable: false,
|
|
1504
|
-
enumerable: false
|
|
1505
|
-
});
|
|
1506
|
-
};
|
|
1930
|
+
logError: function(error, options) {
|
|
1931
|
+
console.error(error.status, error.message);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1507
1934
|
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1935
|
+
var defaultOptions = {
|
|
1936
|
+
path: '',
|
|
1937
|
+
responseFormat: 'json',
|
|
1938
|
+
paramsFormat: 'search',
|
|
1939
|
+
verbs: ['get','post'],
|
|
1940
|
+
handlers: {
|
|
1941
|
+
fetch: api.fetch,
|
|
1942
|
+
result: api.getResult,
|
|
1943
|
+
error: api.logError
|
|
1944
|
+
}
|
|
1945
|
+
};
|
|
1946
|
+
|
|
1947
|
+
function cd(path, name) {
|
|
1948
|
+
name = name.replace(/\//g,'');
|
|
1949
|
+
if (!path.length || path[path.length-1]!=='/') {
|
|
1950
|
+
path+='/';
|
|
1951
|
+
}
|
|
1952
|
+
return path+encodeURIComponent(name);
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
function fetchChain(prop, params) {
|
|
1956
|
+
var options = this;
|
|
1957
|
+
return this.handlers.fetch
|
|
1958
|
+
.call(this, prop, params, options)
|
|
1959
|
+
.then(function(res) {
|
|
1960
|
+
return options.handlers.result.call(options, res, options);
|
|
1961
|
+
})
|
|
1962
|
+
.catch(function(error) {
|
|
1963
|
+
return options.handlers.error.call(options, error, options);
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
function getApiHandler(options) {
|
|
1968
|
+
options.handlers = Object.assign({}, defaultOptions.handlers, options.handlers);
|
|
1969
|
+
options = Object.assign({}, defaultOptions, options);
|
|
1970
|
+
|
|
1971
|
+
return {
|
|
1972
|
+
get: function(cache, prop) {
|
|
1973
|
+
if (!cache[prop]) {
|
|
1974
|
+
if (options.verbs.indexOf(prop)!=-1) {
|
|
1975
|
+
cache[prop] = function(params) {
|
|
1976
|
+
return fetchChain.call(options, prop, params);
|
|
1520
1977
|
}
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
attachArray(object[key], currPath, options);
|
|
1978
|
+
} else {
|
|
1979
|
+
cache[prop] = api.proxy(Object.assign({}, options, {
|
|
1980
|
+
path: cd(options.path, prop)
|
|
1981
|
+
}));
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
return cache[prop];
|
|
1985
|
+
},
|
|
1986
|
+
apply: function(cache, thisArg, params) {
|
|
1987
|
+
return fetchChain.call(options, 'get', params[0] ? params[0] : null)
|
|
1532
1988
|
}
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
onParents(model, path, addSetter);
|
|
1536
|
-
onChildren(model, path, addSetter);
|
|
1989
|
+
}
|
|
1537
1990
|
}
|
|
1538
1991
|
|
|
1539
|
-
// FIXME: if you remove a key by reassigning the parent object
|
|
1540
|
-
// and then assign that missing key a new value
|
|
1541
|
-
// the observer doesn't get triggered
|
|
1542
|
-
// var model = { foo: { bar: 'baz' } };
|
|
1543
|
-
// simply.observer(model, 'foo.bar', ...)
|
|
1544
|
-
// model.foo = { }
|
|
1545
|
-
// model.foo.bar = 'zab'; // this should trigger the observer but doesn't
|
|
1546
1992
|
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
addChangeListener(model, key, callback);
|
|
1553
|
-
});
|
|
1554
|
-
return function() {
|
|
1555
|
-
keys.forEach(function(key) {
|
|
1556
|
-
removeChangeListener(model, key, callback);
|
|
1557
|
-
});
|
|
1558
|
-
};
|
|
1559
|
-
} else {
|
|
1560
|
-
attach(model, path, options);
|
|
1561
|
-
addChangeListener(model, path, callback);
|
|
1562
|
-
return function() {
|
|
1563
|
-
removeChangeListener(model, path, callback);
|
|
1564
|
-
};
|
|
1993
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1994
|
+
module.exports = api;
|
|
1995
|
+
} else {
|
|
1996
|
+
if (!global.simply) {
|
|
1997
|
+
global.simply = {};
|
|
1565
1998
|
}
|
|
1566
|
-
|
|
1999
|
+
global.simply.api = api;
|
|
2000
|
+
}
|
|
1567
2001
|
|
|
1568
|
-
|
|
1569
|
-
|
|
2002
|
+
})(this);
|
|
2003
|
+
(function(global) {
|
|
2004
|
+
'use strict';
|
|
1570
2005
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
2006
|
+
var app = function(options) {
|
|
2007
|
+
if (!options) {
|
|
2008
|
+
options = {};
|
|
2009
|
+
}
|
|
2010
|
+
if (!options.container) {
|
|
2011
|
+
console.warn('No simply.app application container element specified, using document.body.');
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
function simplyApp(options) {
|
|
2015
|
+
if (!options) {
|
|
2016
|
+
options = {};
|
|
2017
|
+
}
|
|
2018
|
+
if ( options.routes ) {
|
|
2019
|
+
simply.route.load(options.routes);
|
|
2020
|
+
if (options.routeEvents) {
|
|
2021
|
+
Object.keys(options.routeEvents).forEach(function(action) {
|
|
2022
|
+
Object.keys(options.routeEvents[action]).forEach(function(route) {
|
|
2023
|
+
options.routeEvents[action][route].forEach(function(callback) {
|
|
2024
|
+
simply.route.addListener(action, route, callback);
|
|
2025
|
+
});
|
|
2026
|
+
});
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
simply.route.handleEvents();
|
|
2030
|
+
global.setTimeout(function() {
|
|
2031
|
+
simply.route.match(global.location.pathname+global.location.hash);
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
this.container = options.container || document.body;
|
|
2035
|
+
this.keyboard = simply.keyboard ? simply.keyboard(this, options.keyboard || {}) : false;
|
|
2036
|
+
this.actions = simply.action ? simply.action(this, options.actions) : false;
|
|
2037
|
+
this.commands = simply.command ? simply.command(this, options.commands) : false;
|
|
2038
|
+
this.resize = simply.resize ? simply.resize(this, options.resize) : false;
|
|
2039
|
+
this.view = simply.view ? simply.view(this, options.view) : false;
|
|
2040
|
+
if (!(global.editor && global.editor.field) && simply.bind) {
|
|
2041
|
+
// skip simplyview databinding if SimplyEdit is loaded
|
|
2042
|
+
options.bind = simply.render(options.bind || {});
|
|
2043
|
+
options.bind.model = this.view;
|
|
2044
|
+
options.bind.container = this.container;
|
|
2045
|
+
this.bind = options.bindings = simply.bind(options.bind);
|
|
1575
2046
|
}
|
|
1576
|
-
return path.split('.').reduce(function(acc, name) {
|
|
1577
|
-
return (acc && acc[name] ? acc[name] : null);
|
|
1578
|
-
}, model);
|
|
1579
|
-
},
|
|
1580
|
-
set: function(model, path, value) {
|
|
1581
|
-
var lastName = simply.path.pop(path);
|
|
1582
|
-
var parentPath = simply.path.parent(path);
|
|
1583
|
-
var parentOb = simply.path.get(model, parentPath);
|
|
1584
|
-
parentOb[lastName] = value;
|
|
1585
|
-
},
|
|
1586
|
-
pop: function(path) {
|
|
1587
|
-
return path.split('.').pop();
|
|
1588
|
-
},
|
|
1589
|
-
push: function(path, name) {
|
|
1590
|
-
return (path ? path + '.' : '') + name;
|
|
1591
|
-
},
|
|
1592
|
-
parent: function(path) {
|
|
1593
|
-
var p = path.split('.');
|
|
1594
|
-
p.pop();
|
|
1595
|
-
return p.join('.');
|
|
1596
|
-
},
|
|
1597
|
-
parents: function(path) {
|
|
1598
|
-
var result = [];
|
|
1599
|
-
path.split('.').reduce(function(acc, name) {
|
|
1600
|
-
acc.push( (acc.length ? acc[acc.length-1] + '.' : '') + name );
|
|
1601
|
-
return acc;
|
|
1602
|
-
},result);
|
|
1603
|
-
return result;
|
|
1604
2047
|
}
|
|
2048
|
+
|
|
2049
|
+
simplyApp.prototype.get = function(id) {
|
|
2050
|
+
return this.container.querySelector('[data-simply-id='+id+']') || document.getElementById(id);
|
|
2051
|
+
};
|
|
2052
|
+
|
|
2053
|
+
return new simplyApp(options);
|
|
1605
2054
|
};
|
|
1606
2055
|
|
|
1607
|
-
|
|
1608
|
-
|
|
2056
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
2057
|
+
module.exports = app;
|
|
2058
|
+
} else {
|
|
2059
|
+
if (!global.simply) {
|
|
2060
|
+
global.simply = {};
|
|
2061
|
+
}
|
|
2062
|
+
global.simply.app = app;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
})(this);
|