simplyview 2.1.0 → 3.0.0

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.
@@ -1,226 +0,0 @@
1
- (function (global) {
2
- 'use strict';
3
-
4
- var throttle = function( callbackFunction, intervalTime ) {
5
- var eventId = 0;
6
- return function() {
7
- var myArguments = arguments;
8
- var me = this;
9
- if ( eventId ) {
10
- return;
11
- } else {
12
- eventId = global.setTimeout( function() {
13
- callbackFunction.apply(me, myArguments);
14
- eventId = 0;
15
- }, intervalTime );
16
- }
17
- };
18
- };
19
-
20
- var runWhenIdle = (function() {
21
- if (global.requestIdleCallback) {
22
- return function(callback) {
23
- global.requestIdleCallback(callback, {timeout: 500});
24
- };
25
- }
26
- return global.requestAnimationFrame;
27
- })();
28
-
29
- var rebaseHref = function(relative, base) {
30
- if (/^[a-z-]*:?\//.test(relative)) {
31
- return relative; // absolute href, no need to rebase
32
- }
33
-
34
- var stack = base.split('/'),
35
- parts = relative.split('/');
36
- stack.pop(); // remove current file name (or empty string)
37
- for (var i=0; i<parts.length; i++) {
38
- if (parts[i] == '.')
39
- continue;
40
- if (parts[i] == '..')
41
- stack.pop();
42
- else
43
- stack.push(parts[i]);
44
- }
45
- return stack.join('/');
46
- };
47
-
48
- var observer, loaded = {};
49
- var head = global.document.querySelector('head');
50
- var currentScript = global.document.currentScript;
51
- if (!currentScript) {
52
- var getScriptURL = (function() {
53
- var scripts = document.getElementsByTagName('script');
54
- var index = scripts.length - 1;
55
- var myScript = scripts[index];
56
- return function() { return myScript.src; };
57
- })();
58
- var currentScriptURL = getScriptURL();
59
- } else {
60
- var currentScriptURL = currentScript.src;
61
- }
62
-
63
- var waitForPreviousScripts = function() {
64
- // because of the async=false attribute, this script will run after
65
- // the previous scripts have been loaded and run
66
- // simply.include.next.js only fires the simply-next-script event
67
- // that triggers the Promise.resolve method
68
- return new Promise(function(resolve) {
69
- var next = global.document.createElement('script');
70
- next.src = rebaseHref('simply.include.next.js', currentScriptURL);
71
- next.async = false;
72
- global.document.addEventListener('simply-include-next', function() {
73
- head.removeChild(next);
74
- resolve();
75
- }, { once: true, passive: true});
76
- head.appendChild(next);
77
- });
78
- };
79
-
80
- var scriptLocations = [];
81
-
82
- var include = {
83
- scripts: function(scripts, base) {
84
- var arr = [];
85
- for(var i = scripts.length; i--; arr.unshift(scripts[i]));
86
- var importScript = function() {
87
- var script = arr.shift();
88
- if (!script) {
89
- return;
90
- }
91
- var attrs = [].map.call(script.attributes, function(attr) {
92
- return attr.name;
93
- });
94
- var clone = global.document.createElement('script');
95
- attrs.forEach(function(attr) {
96
- clone.setAttribute(attr, script.getAttribute(attr));
97
- });
98
- clone.removeAttribute('data-simply-location');
99
- if (!clone.src) {
100
- // this is an inline script, so copy the content and wait for previous scripts to run
101
- clone.innerHTML = script.innerHTML;
102
- waitForPreviousScripts()
103
- .then(function() {
104
- var node = scriptLocations[script.dataset.simplyLocation];
105
- node.parentNode.insertBefore(clone, node);
106
- node.parentNode.removeChild(node);
107
- importScript();
108
- });
109
- } else {
110
- clone.src = rebaseHref(clone.src, base);
111
- if (!clone.hasAttribute('async') && !clone.hasAttribute('defer')) {
112
- clone.async = false; //important! do not use clone.setAttribute('async', false) - it has no effect
113
- }
114
- var node = scriptLocations[script.dataset.simplyLocation];
115
- node.parentNode.insertBefore(clone, node);
116
- node.parentNode.removeChild(node);
117
- loaded[clone.src]=true;
118
- importScript();
119
- }
120
- };
121
- if (arr.length) {
122
- importScript();
123
- }
124
- },
125
- html: function(html, link) {
126
- var fragment = global.document.createRange().createContextualFragment(html);
127
- var stylesheets = fragment.querySelectorAll('link[rel="stylesheet"],style');
128
- // add all stylesheets to head
129
- [].forEach.call(stylesheets, function(stylesheet) {
130
- if (stylesheet.href) {
131
- stylesheet.href = rebaseHref(stylesheet.href, link.href);
132
- }
133
- head.appendChild(stylesheet);
134
- });
135
- // remove the scripts from the fragment, as they will not run in the
136
- // order in which they are defined
137
- var scriptsFragment = global.document.createDocumentFragment();
138
- // FIXME: this loses the original position of the script
139
- // should add a placeholder so we can reinsert the clone
140
- var scripts = fragment.querySelectorAll('script');
141
- [].forEach.call(scripts, function(script) {
142
- var placeholder = global.document.createComment(script.src || 'inline script');
143
- script.parentNode.insertBefore(placeholder, script);
144
- script.dataset.simplyLocation = scriptLocations.length;
145
- scriptLocations.push(placeholder);
146
- scriptsFragment.appendChild(script);
147
- });
148
- // add the remainder before the include link
149
- link.parentNode.insertBefore(fragment, link ? link : null);
150
- global.setTimeout(function() {
151
- if (global.editor && global.editor.data && fragment.querySelector('[data-simply-field],[data-simply-list]')) {
152
- //TODO: remove this dependency and let simply.bind listen for dom node insertions (and simply-edit.js use simply.bind)
153
- global.editor.data.apply(global.editor.currentData, global.document);
154
- }
155
- simply.include.scripts(scriptsFragment.childNodes, link ? link.href : global.location.href );
156
- }, 10);
157
- }
158
- };
159
-
160
- var included = {};
161
- var includeLinks = function(links) {
162
- // mark them as in progress, so handleChanges doesn't find them again
163
- var remainingLinks = [].reduce.call(links, function(remainder, link) {
164
- if (link.rel=='simply-include-once' && included[link.href]) {
165
- link.parentNode.removeChild(link);
166
- } else {
167
- included[link.href]=true;
168
- link.rel = 'simply-include-loading';
169
- remainder.push(link);
170
- }
171
- return remainder;
172
- }, []);
173
- [].forEach.call(remainingLinks, function(link) {
174
- if (!link.href) {
175
- return;
176
- }
177
- // fetch the html
178
- fetch(link.href)
179
- .then(function(response) {
180
- if (response.ok) {
181
- console.log('simply-include: loaded '+link.href);
182
- return response.text();
183
- } else {
184
- console.log('simply-include: failed to load '+link.href);
185
- }
186
- })
187
- .then(function(html) {
188
- // if succesfull import the html
189
- simply.include.html(html, link);
190
- // remove the include link
191
- link.parentNode.removeChild(link);
192
- });
193
- });
194
- };
195
-
196
- var handleChanges = throttle(function() {
197
- runWhenIdle(function() {
198
- var links = global.document.querySelectorAll('link[rel="simply-include"],link[rel="simply-include-once"]');
199
- if (links.length) {
200
- includeLinks(links);
201
- }
202
- });
203
- });
204
-
205
- var observe = function() {
206
- observer = new MutationObserver(handleChanges);
207
- observer.observe(global.document, {
208
- subtree: true,
209
- childList: true,
210
- });
211
- };
212
-
213
- observe();
214
- handleChanges(); // check if there are include links in the dom already
215
-
216
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
217
- module.exports = include;
218
- } else {
219
- if (!global.simply) {
220
- global.simply = {};
221
- }
222
- global.simply.include = include;
223
- }
224
-
225
-
226
- })(this);
@@ -1,62 +0,0 @@
1
- (function(global) {
2
- 'use strict';
3
-
4
- function keyboard(app, config) {
5
- var keys = config;
6
-
7
- if (!app) {
8
- app = {};
9
- }
10
- if (!app.container) {
11
- app.container = document.body;
12
- }
13
- app.container.addEventListener('keydown', (e) => {
14
- if (e.isComposing || e.keyCode === 229) {
15
- return;
16
- }
17
- if (e.defaultPrevented) {
18
- return;
19
- }
20
- if (!e.target) {
21
- return;
22
- }
23
-
24
- let selectedKeyboard = 'default';
25
- if (e.target.closest('[data-simply-keyboard]')) {
26
- selectedKeyboard = e.target.closest('[data-simply-keyboard]').dataset.simplyKeyboard;
27
- }
28
- let key = '';
29
- if (e.ctrlKey && e.keyCode!=17) {
30
- key+='Control+';
31
- }
32
- if (e.metaKey && e.keyCode!=224) {
33
- key+='Meta+';
34
- }
35
- if (e.altKey && e.keyCode!=18) {
36
- key+='Alt+';
37
- }
38
- if (e.shiftKey && e.keyCode!=16) {
39
- key+='Shift+';
40
- }
41
- key+=e.key;
42
-
43
- if (keys[selectedKeyboard] && keys[selectedKeyboard][key]) {
44
- let keyboard = keys[selectedKeyboard]
45
- keyboard.app = app;
46
- keyboard[key].call(keyboard,e);
47
- }
48
- });
49
-
50
- return keys;
51
- }
52
-
53
-
54
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
55
- module.exports = keyboard;
56
- } else {
57
- if (!global.simply) {
58
- global.simply = {};
59
- }
60
- global.simply.keyboard = keyboard;
61
- }
62
- })(this);
@@ -1,22 +0,0 @@
1
- (function() {
2
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
3
- var simply = {
4
- command: require('simply.command.js'),
5
- action: require('simply.action.js'),
6
- route: require('simply.route.js'),
7
- view: require('simply.view.js'),
8
- viewmodel: require('simply.viewmodel.js'),
9
- resize: require('simply.resize.js'),
10
- activate:require('simply.active.js'),
11
- include: require('simply.include.js'),
12
- render: require('simply.render.js'),
13
- observe: require('simply.observe.js'),
14
- bind: require('simply.bind.js'),
15
- app: require('simply.app.js'),
16
- collect: require('simply.collect.js'),
17
- path: require('simply.path.js')
18
- }
19
-
20
- module.exports = simply;
21
- }
22
- })();
@@ -1,349 +0,0 @@
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
- });
66
- }
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;
85
- }
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
-
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];
134
- }
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;
143
- }
144
- if (Array.isArray(object)) {
145
- return;
146
- }
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
- }
173
- } else {
174
- onMissingChildren(model, path+'.'+key, callback);
175
- }
176
- });
177
- }
178
-
179
- function addChangeListener(model, path, callback) {
180
- if (!changeListeners.has(model)) {
181
- changeListeners.set(model, {});
182
- }
183
- if (!changeListeners.get(model)[path]) {
184
- changeListeners.get(model)[path] = [];
185
- }
186
- changeListeners.get(model)[path].push(callback);
187
-
188
- if (!parentListeners.has(model)) {
189
- parentListeners.set(model, {});
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
- });
198
-
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
- }
209
-
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
- }
220
-
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
- // }
265
- }
266
- }
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
- };
307
-
308
- onParents(model, path, addSetter);
309
- onChildren(model, path, addSetter);
310
- }
311
-
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
319
-
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
- };
340
-
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);