simplyview 2.0.2 → 2.1.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.
- package/dist/simply.everything.js +105 -70
- package/js/simply.api.js +46 -47
- package/js/simply.keyboard.js +19 -2
- package/js/simply.route.js +18 -16
- package/js/simply.viewmodel.js +20 -5
- package/package.json +7 -2
- package/docs/examples.md +0 -82
- package/docs/readme.md +0 -33
- package/docs/simply.action.md +0 -42
- package/docs/simply.activate.md +0 -27
- package/docs/simply.api.md +0 -188
- package/docs/simply.app.md +0 -27
- package/docs/simply.collect.md +0 -64
- package/docs/simply.command.md +0 -110
- package/docs/simply.include.md +0 -61
- package/docs/simply.keyboard.md +0 -60
- package/docs/simply.path.md +0 -3
- package/docs/simply.route.md +0 -133
- package/docs/simply.view.md +0 -53
- package/docs/simply.viewmodel.md +0 -3
- package/examples/commands.html +0 -70
- package/examples/counter.html +0 -52
- package/examples/examples.css +0 -3
- package/examples/github.html +0 -39
- package/examples/githubv4.html +0 -107
- package/examples/graphql.html +0 -51
- package/examples/graphql.html~ +0 -35
- package/examples/include/fifth.js +0 -1
- package/examples/include/first.js +0 -1
- package/examples/include/include.html +0 -4
- package/examples/include/include2.html +0 -1
- package/examples/include/index.html +0 -18
- package/examples/include/scripts.html +0 -16
- package/examples/include/third.js +0 -3
- package/examples/keyboard.html +0 -41
- package/examples/todo.html +0 -48
- package/examples/viewmodel.html +0 -359
- package/make +0 -18
- package/make~ +0 -17
- package/package.json~ +0 -31
- package/test/simply.route.test.js +0 -102
|
@@ -639,8 +639,8 @@ properties for a given parent, keep seperate index for this?
|
|
|
639
639
|
handleEvents: function() {
|
|
640
640
|
global.addEventListener('popstate', function() {
|
|
641
641
|
if (route.match(getPath(document.location.pathname + document.location.hash)) === false) {
|
|
642
|
-
|
|
643
|
-
|
|
642
|
+
route.match(getPath(document.location.pathname));
|
|
643
|
+
}
|
|
644
644
|
});
|
|
645
645
|
global.document.addEventListener('click', linkHandler);
|
|
646
646
|
},
|
|
@@ -665,22 +665,24 @@ properties for a given parent, keep seperate index for this?
|
|
|
665
665
|
|
|
666
666
|
var matches;
|
|
667
667
|
if (!path) {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
668
|
+
if (route.match(document.location.pathname+document.location.hash)) {
|
|
669
|
+
return true;
|
|
670
|
+
} else {
|
|
671
|
+
return route.match(document.location.pathname);
|
|
672
|
+
}
|
|
673
673
|
}
|
|
674
674
|
path = getPath(path);
|
|
675
675
|
for ( var i=0; i<routeInfo.length; i++) {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
if (
|
|
679
|
-
path
|
|
680
|
-
|
|
676
|
+
matches = routeInfo[i].match.exec(path);
|
|
677
|
+
if (!matches || !matches.length) {
|
|
678
|
+
if (path && path[path.length-1]!='/') {
|
|
679
|
+
matches = routeInfo[i].match.exec(path+'/');
|
|
680
|
+
if (matches) {
|
|
681
|
+
path+='/';
|
|
682
|
+
history.replaceState({}, '', getUrl(path));
|
|
683
|
+
}
|
|
681
684
|
}
|
|
682
685
|
}
|
|
683
|
-
matches = routeInfo[i].match.exec(path);
|
|
684
686
|
if (matches && matches.length) {
|
|
685
687
|
var params = {};
|
|
686
688
|
routeInfo[i].params.forEach(function(key, i) {
|
|
@@ -697,9 +699,9 @@ properties for a given parent, keep seperate index for this?
|
|
|
697
699
|
args.result = routeInfo[i].action.call(route, params);
|
|
698
700
|
runListeners('finish', args);
|
|
699
701
|
return args.result;
|
|
700
|
-
|
|
702
|
+
}
|
|
701
703
|
}
|
|
702
|
-
|
|
704
|
+
return false;
|
|
703
705
|
},
|
|
704
706
|
goto: function(path) {
|
|
705
707
|
history.pushState({},'',getUrl(path));
|
|
@@ -734,7 +736,7 @@ properties for a given parent, keep seperate index for this?
|
|
|
734
736
|
listeners[action][route] = listeners[action][route].filter(function(listener) {
|
|
735
737
|
return listener != callback;
|
|
736
738
|
});
|
|
737
|
-
|
|
739
|
+
},
|
|
738
740
|
init: function(params) {
|
|
739
741
|
if (params.root) {
|
|
740
742
|
options.root = params.root;
|
|
@@ -1125,8 +1127,25 @@ properties for a given parent, keep seperate index for this?
|
|
|
1125
1127
|
if (e.target.closest('[data-simply-keyboard]')) {
|
|
1126
1128
|
selectedKeyboard = e.target.closest('[data-simply-keyboard]').dataset.simplyKeyboard;
|
|
1127
1129
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
+
let key = '';
|
|
1131
|
+
if (e.ctrlKey && e.keyCode!=17) {
|
|
1132
|
+
key+='Control+';
|
|
1133
|
+
}
|
|
1134
|
+
if (e.metaKey && e.keyCode!=224) {
|
|
1135
|
+
key+='Meta+';
|
|
1136
|
+
}
|
|
1137
|
+
if (e.altKey && e.keyCode!=18) {
|
|
1138
|
+
key+='Alt+';
|
|
1139
|
+
}
|
|
1140
|
+
if (e.shiftKey && e.keyCode!=16) {
|
|
1141
|
+
key+='Shift+';
|
|
1142
|
+
}
|
|
1143
|
+
key+=e.key;
|
|
1144
|
+
|
|
1145
|
+
if (keys[selectedKeyboard] && keys[selectedKeyboard][key]) {
|
|
1146
|
+
let keyboard = keys[selectedKeyboard]
|
|
1147
|
+
keyboard.app = app;
|
|
1148
|
+
keyboard[key].call(keyboard,e);
|
|
1130
1149
|
}
|
|
1131
1150
|
});
|
|
1132
1151
|
|
|
@@ -1582,6 +1601,7 @@ properties for a given parent, keep seperate index for this?
|
|
|
1582
1601
|
load();
|
|
1583
1602
|
} else {
|
|
1584
1603
|
global.document.addEventListener('simply-content-loaded', function() {
|
|
1604
|
+
console.log('switching...')
|
|
1585
1605
|
load();
|
|
1586
1606
|
});
|
|
1587
1607
|
}
|
|
@@ -1600,10 +1620,18 @@ properties for a given parent, keep seperate index for this?
|
|
|
1600
1620
|
})(this);
|
|
1601
1621
|
(function(global) {
|
|
1602
1622
|
'use strict';
|
|
1623
|
+
|
|
1624
|
+
function etag() {
|
|
1625
|
+
let d = '';
|
|
1626
|
+
while (d.length < 32) d += Math.random().toString(16).substr(2);
|
|
1627
|
+
const vr = ((parseInt(d.substr(16, 1), 16) & 0x3) | 0x8).toString(16);
|
|
1628
|
+
return `${d.substr(0, 8)}-${d.substr(8, 4)}-4${d.substr(13, 3)}-${vr}${d.substr(17, 3)}-${d.substr(20, 12)}`;
|
|
1629
|
+
}
|
|
1603
1630
|
|
|
1604
1631
|
function ViewModel(name, data, options) {
|
|
1605
1632
|
this.name = name;
|
|
1606
1633
|
this.data = data || [];
|
|
1634
|
+
this.data.etag = etag();
|
|
1607
1635
|
this.view = {
|
|
1608
1636
|
options: {},
|
|
1609
1637
|
data: [] //Array.from(this.data).slice()
|
|
@@ -1626,15 +1654,22 @@ properties for a given parent, keep seperate index for this?
|
|
|
1626
1654
|
// this.data is a reference to the data passed, so that any changes in it will get applied
|
|
1627
1655
|
// to the original
|
|
1628
1656
|
this.data = params.data;
|
|
1657
|
+
this.data.etag = etag()
|
|
1629
1658
|
}
|
|
1630
1659
|
// the view is a shallow copy of the array, so that changes in sort order and filtering
|
|
1631
1660
|
// won't get applied to the original, but databindings on its children will still work
|
|
1632
1661
|
this.view.data = Array.from(this.data).slice();
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
plugins.
|
|
1636
|
-
|
|
1662
|
+
this.view.data.etag = this.data.etag;
|
|
1663
|
+
let data = this.view.data;
|
|
1664
|
+
let plugins = this.plugins.start.concat(this.plugins.select, this.plugins.order, this.plugins.render, this.plugins.finish);
|
|
1665
|
+
plugins.forEach(plugin => {
|
|
1666
|
+
data = plugin.call(this, params, data);
|
|
1667
|
+
if (!data) {
|
|
1668
|
+
data = this.view.data;
|
|
1669
|
+
}
|
|
1670
|
+
this.view.data = data
|
|
1637
1671
|
});
|
|
1672
|
+
this.view.data = data;
|
|
1638
1673
|
|
|
1639
1674
|
if (global.editor) {
|
|
1640
1675
|
global.editor.addDataSource(this.name,{
|
|
@@ -1759,7 +1794,8 @@ properties for a given parent, keep seperate index for this?
|
|
|
1759
1794
|
createFilter: createFilter,
|
|
1760
1795
|
createSort: createSort,
|
|
1761
1796
|
createPaging: createPaging,
|
|
1762
|
-
updateDataSource: updateDataSource
|
|
1797
|
+
updateDataSource: updateDataSource,
|
|
1798
|
+
etag
|
|
1763
1799
|
};
|
|
1764
1800
|
|
|
1765
1801
|
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
@@ -1775,7 +1811,7 @@ properties for a given parent, keep seperate index for this?
|
|
|
1775
1811
|
'use strict';
|
|
1776
1812
|
|
|
1777
1813
|
var api = {
|
|
1778
|
-
|
|
1814
|
+
/**
|
|
1779
1815
|
* Returns a Proxy object that translates property access to a URL in the api
|
|
1780
1816
|
* and method calls to a fetch on that URL.
|
|
1781
1817
|
* @param options: a list of options for fetch(),
|
|
@@ -1897,27 +1933,27 @@ properties for a given parent, keep seperate index for this?
|
|
|
1897
1933
|
*/
|
|
1898
1934
|
getResult: function(response, options) {
|
|
1899
1935
|
if (response.ok) {
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1936
|
+
switch(options.responseFormat) {
|
|
1937
|
+
case 'text':
|
|
1938
|
+
return response.text();
|
|
1939
|
+
break;
|
|
1940
|
+
case 'formData':
|
|
1941
|
+
return response.formData();
|
|
1942
|
+
break;
|
|
1943
|
+
case 'blob':
|
|
1944
|
+
return response.blob();
|
|
1945
|
+
break;
|
|
1946
|
+
case 'arrayBuffer':
|
|
1947
|
+
return response.arrayBuffer();
|
|
1948
|
+
break;
|
|
1949
|
+
case 'unbuffered':
|
|
1950
|
+
return response.body;
|
|
1951
|
+
break;
|
|
1952
|
+
case 'json':
|
|
1953
|
+
default:
|
|
1954
|
+
return response.json();
|
|
1955
|
+
break;
|
|
1956
|
+
}
|
|
1921
1957
|
} else {
|
|
1922
1958
|
throw {
|
|
1923
1959
|
status: response.status,
|
|
@@ -1925,23 +1961,22 @@ properties for a given parent, keep seperate index for this?
|
|
|
1925
1961
|
response: response
|
|
1926
1962
|
}
|
|
1927
1963
|
}
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
logError: function(error, options) {
|
|
1964
|
+
},
|
|
1965
|
+
logError: function(error, options) {
|
|
1931
1966
|
console.error(error.status, error.message);
|
|
1932
|
-
|
|
1967
|
+
}
|
|
1933
1968
|
}
|
|
1934
1969
|
|
|
1935
1970
|
var defaultOptions = {
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1971
|
+
path: '',
|
|
1972
|
+
responseFormat: 'json',
|
|
1973
|
+
paramsFormat: 'search',
|
|
1974
|
+
verbs: ['get','post'],
|
|
1975
|
+
handlers: {
|
|
1976
|
+
fetch: api.fetch,
|
|
1977
|
+
result: api.getResult,
|
|
1978
|
+
error: api.logError
|
|
1979
|
+
}
|
|
1945
1980
|
};
|
|
1946
1981
|
|
|
1947
1982
|
function cd(path, name) {
|
|
@@ -1952,20 +1987,20 @@ properties for a given parent, keep seperate index for this?
|
|
|
1952
1987
|
return path+encodeURIComponent(name);
|
|
1953
1988
|
}
|
|
1954
1989
|
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1990
|
+
function fetchChain(prop, params) {
|
|
1991
|
+
var options = this;
|
|
1992
|
+
return this.handlers.fetch
|
|
1993
|
+
.call(this, prop, params, options)
|
|
1994
|
+
.then(function(res) {
|
|
1995
|
+
return options.handlers.result.call(options, res, options);
|
|
1996
|
+
})
|
|
1997
|
+
.catch(function(error) {
|
|
1998
|
+
return options.handlers.error.call(options, error, options);
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
1966
2001
|
|
|
1967
2002
|
function getApiHandler(options) {
|
|
1968
|
-
|
|
2003
|
+
options.handlers = Object.assign({}, defaultOptions.handlers, options.handlers);
|
|
1969
2004
|
options = Object.assign({}, defaultOptions, options);
|
|
1970
2005
|
|
|
1971
2006
|
return {
|
package/js/simply.api.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var api = {
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
6
|
* Returns a Proxy object that translates property access to a URL in the api
|
|
7
7
|
* and method calls to a fetch on that URL.
|
|
8
8
|
* @param options: a list of options for fetch(),
|
|
@@ -124,27 +124,27 @@
|
|
|
124
124
|
*/
|
|
125
125
|
getResult: function(response, options) {
|
|
126
126
|
if (response.ok) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
127
|
+
switch(options.responseFormat) {
|
|
128
|
+
case 'text':
|
|
129
|
+
return response.text();
|
|
130
|
+
break;
|
|
131
|
+
case 'formData':
|
|
132
|
+
return response.formData();
|
|
133
|
+
break;
|
|
134
|
+
case 'blob':
|
|
135
|
+
return response.blob();
|
|
136
|
+
break;
|
|
137
|
+
case 'arrayBuffer':
|
|
138
|
+
return response.arrayBuffer();
|
|
139
|
+
break;
|
|
140
|
+
case 'unbuffered':
|
|
141
|
+
return response.body;
|
|
142
|
+
break;
|
|
143
|
+
case 'json':
|
|
144
|
+
default:
|
|
145
|
+
return response.json();
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
148
|
} else {
|
|
149
149
|
throw {
|
|
150
150
|
status: response.status,
|
|
@@ -152,23 +152,22 @@
|
|
|
152
152
|
response: response
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
logError: function(error, options) {
|
|
155
|
+
},
|
|
156
|
+
logError: function(error, options) {
|
|
158
157
|
console.error(error.status, error.message);
|
|
159
|
-
|
|
158
|
+
}
|
|
160
159
|
}
|
|
161
160
|
|
|
162
161
|
var defaultOptions = {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
162
|
+
path: '',
|
|
163
|
+
responseFormat: 'json',
|
|
164
|
+
paramsFormat: 'search',
|
|
165
|
+
verbs: ['get','post'],
|
|
166
|
+
handlers: {
|
|
167
|
+
fetch: api.fetch,
|
|
168
|
+
result: api.getResult,
|
|
169
|
+
error: api.logError
|
|
170
|
+
}
|
|
172
171
|
};
|
|
173
172
|
|
|
174
173
|
function cd(path, name) {
|
|
@@ -179,20 +178,20 @@
|
|
|
179
178
|
return path+encodeURIComponent(name);
|
|
180
179
|
}
|
|
181
180
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
181
|
+
function fetchChain(prop, params) {
|
|
182
|
+
var options = this;
|
|
183
|
+
return this.handlers.fetch
|
|
184
|
+
.call(this, prop, params, options)
|
|
185
|
+
.then(function(res) {
|
|
186
|
+
return options.handlers.result.call(options, res, options);
|
|
187
|
+
})
|
|
188
|
+
.catch(function(error) {
|
|
189
|
+
return options.handlers.error.call(options, error, options);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
193
192
|
|
|
194
193
|
function getApiHandler(options) {
|
|
195
|
-
|
|
194
|
+
options.handlers = Object.assign({}, defaultOptions.handlers, options.handlers);
|
|
196
195
|
options = Object.assign({}, defaultOptions, options);
|
|
197
196
|
|
|
198
197
|
return {
|
package/js/simply.keyboard.js
CHANGED
|
@@ -25,8 +25,25 @@
|
|
|
25
25
|
if (e.target.closest('[data-simply-keyboard]')) {
|
|
26
26
|
selectedKeyboard = e.target.closest('[data-simply-keyboard]').dataset.simplyKeyboard;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
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);
|
|
30
47
|
}
|
|
31
48
|
});
|
|
32
49
|
|
package/js/simply.route.js
CHANGED
|
@@ -118,8 +118,8 @@
|
|
|
118
118
|
handleEvents: function() {
|
|
119
119
|
global.addEventListener('popstate', function() {
|
|
120
120
|
if (route.match(getPath(document.location.pathname + document.location.hash)) === false) {
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
route.match(getPath(document.location.pathname));
|
|
122
|
+
}
|
|
123
123
|
});
|
|
124
124
|
global.document.addEventListener('click', linkHandler);
|
|
125
125
|
},
|
|
@@ -144,22 +144,24 @@
|
|
|
144
144
|
|
|
145
145
|
var matches;
|
|
146
146
|
if (!path) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
if (route.match(document.location.pathname+document.location.hash)) {
|
|
148
|
+
return true;
|
|
149
|
+
} else {
|
|
150
|
+
return route.match(document.location.pathname);
|
|
151
|
+
}
|
|
152
152
|
}
|
|
153
153
|
path = getPath(path);
|
|
154
154
|
for ( var i=0; i<routeInfo.length; i++) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (
|
|
158
|
-
path
|
|
159
|
-
|
|
155
|
+
matches = routeInfo[i].match.exec(path);
|
|
156
|
+
if (!matches || !matches.length) {
|
|
157
|
+
if (path && path[path.length-1]!='/') {
|
|
158
|
+
matches = routeInfo[i].match.exec(path+'/');
|
|
159
|
+
if (matches) {
|
|
160
|
+
path+='/';
|
|
161
|
+
history.replaceState({}, '', getUrl(path));
|
|
162
|
+
}
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
|
-
matches = routeInfo[i].match.exec(path);
|
|
163
165
|
if (matches && matches.length) {
|
|
164
166
|
var params = {};
|
|
165
167
|
routeInfo[i].params.forEach(function(key, i) {
|
|
@@ -176,9 +178,9 @@
|
|
|
176
178
|
args.result = routeInfo[i].action.call(route, params);
|
|
177
179
|
runListeners('finish', args);
|
|
178
180
|
return args.result;
|
|
179
|
-
|
|
181
|
+
}
|
|
180
182
|
}
|
|
181
|
-
|
|
183
|
+
return false;
|
|
182
184
|
},
|
|
183
185
|
goto: function(path) {
|
|
184
186
|
history.pushState({},'',getUrl(path));
|
|
@@ -213,7 +215,7 @@
|
|
|
213
215
|
listeners[action][route] = listeners[action][route].filter(function(listener) {
|
|
214
216
|
return listener != callback;
|
|
215
217
|
});
|
|
216
|
-
|
|
218
|
+
},
|
|
217
219
|
init: function(params) {
|
|
218
220
|
if (params.root) {
|
|
219
221
|
options.root = params.root;
|
package/js/simply.viewmodel.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
(function(global) {
|
|
2
2
|
'use strict';
|
|
3
|
+
|
|
4
|
+
function etag() {
|
|
5
|
+
let d = '';
|
|
6
|
+
while (d.length < 32) d += Math.random().toString(16).substr(2);
|
|
7
|
+
const vr = ((parseInt(d.substr(16, 1), 16) & 0x3) | 0x8).toString(16);
|
|
8
|
+
return `${d.substr(0, 8)}-${d.substr(8, 4)}-4${d.substr(13, 3)}-${vr}${d.substr(17, 3)}-${d.substr(20, 12)}`;
|
|
9
|
+
}
|
|
3
10
|
|
|
4
11
|
function ViewModel(name, data, options) {
|
|
5
12
|
this.name = name;
|
|
6
13
|
this.data = data || [];
|
|
14
|
+
this.data.etag = etag();
|
|
7
15
|
this.view = {
|
|
8
16
|
options: {},
|
|
9
17
|
data: [] //Array.from(this.data).slice()
|
|
@@ -26,14 +34,20 @@
|
|
|
26
34
|
// this.data is a reference to the data passed, so that any changes in it will get applied
|
|
27
35
|
// to the original
|
|
28
36
|
this.data = params.data;
|
|
37
|
+
this.data.etag = etag()
|
|
29
38
|
}
|
|
30
39
|
// the view is a shallow copy of the array, so that changes in sort order and filtering
|
|
31
40
|
// won't get applied to the original, but databindings on its children will still work
|
|
32
41
|
this.view.data = Array.from(this.data).slice();
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
plugins.
|
|
36
|
-
|
|
42
|
+
this.view.data.etag = this.data.etag;
|
|
43
|
+
let data = this.view.data;
|
|
44
|
+
let plugins = this.plugins.start.concat(this.plugins.select, this.plugins.order, this.plugins.render, this.plugins.finish);
|
|
45
|
+
plugins.forEach(plugin => {
|
|
46
|
+
data = plugin.call(this, params, data);
|
|
47
|
+
if (!data) {
|
|
48
|
+
data = this.view.data;
|
|
49
|
+
}
|
|
50
|
+
this.view.data = data
|
|
37
51
|
});
|
|
38
52
|
|
|
39
53
|
if (global.editor) {
|
|
@@ -159,7 +173,8 @@
|
|
|
159
173
|
createFilter: createFilter,
|
|
160
174
|
createSort: createSort,
|
|
161
175
|
createPaging: createPaging,
|
|
162
|
-
updateDataSource: updateDataSource
|
|
176
|
+
updateDataSource: updateDataSource,
|
|
177
|
+
etag
|
|
163
178
|
};
|
|
164
179
|
|
|
165
180
|
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simplyview",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Library to rapidly build UI components, using declarative tools",
|
|
5
5
|
"main": "dist/simply.everything.js",
|
|
6
6
|
"directories": {
|
|
@@ -27,5 +27,10 @@
|
|
|
27
27
|
"homepage": "https://github.com/simplyedit/simplyview#readme",
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"jest": "^24.9.0"
|
|
30
|
-
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"README.md",
|
|
33
|
+
"dist/",
|
|
34
|
+
"js/"
|
|
35
|
+
]
|
|
31
36
|
}
|
package/docs/examples.md
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Examples
|
|
2
|
-
|
|
3
|
-
## Counter
|
|
4
|
-
|
|
5
|
-
The counter app is an example to introduce the basic concepts. Here is the HTML:
|
|
6
|
-
|
|
7
|
-
```html
|
|
8
|
-
<div id="counterApp">
|
|
9
|
-
<input type="text" data-simply-field="counter">
|
|
10
|
-
<button data-simply-command="add1">+</button>
|
|
11
|
-
<button data-simply-command="sub1">-</button>
|
|
12
|
-
<div>Counter is now: <span data-simply-field="counter"></span></div>
|
|
13
|
-
</div>
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
It uses two components of SimplyView and SimplyEdit, through
|
|
17
|
-
`data-simply-command` and `data-simply-field`.
|
|
18
|
-
|
|
19
|
-
`data-simply-command` is handled by [simply.command](simply.command.md). Both
|
|
20
|
-
commands are defined on buttons, so they will trigger when the button is
|
|
21
|
-
pressed. The javascript code tied to these commands is defined with the
|
|
22
|
-
[simply.app](simply.app.md) component:
|
|
23
|
-
|
|
24
|
-
```javascript
|
|
25
|
-
var counterApp = simply.app({
|
|
26
|
-
container: document.getElementById('counterApp'),
|
|
27
|
-
commands: {
|
|
28
|
-
add1: function() {
|
|
29
|
-
counterApp.view.counter++;
|
|
30
|
-
},
|
|
31
|
-
sub1: function() {
|
|
32
|
-
counterApp.view.counter--;
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
view: {
|
|
36
|
-
counter: 1
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
simply.app is a wrapper that combines a number of components with a single
|
|
42
|
-
configuration parameter. The commands section here is passed on to simply.command.
|
|
43
|
-
|
|
44
|
-
When you press the button with `data-simply-command="add1"`, the command
|
|
45
|
-
handler for this app is triggered and searches its commands for 'add1'.
|
|
46
|
-
It then calls this javascript function and it will increase
|
|
47
|
-
`counterApp.view.counter`.
|
|
48
|
-
|
|
49
|
-
This is where the second component, which uses `data-simply-field`, comes in.
|
|
50
|
-
The `counterApp.view` object is automatically tied to SimplyEdit, by simply.app.
|
|
51
|
-
So whenever you update a variable inside `counterApp.view`, SimplyEdit will
|
|
52
|
-
also update any HTML element which references the same variable.
|
|
53
|
-
|
|
54
|
-
In this case `counterApp.view.counter` is tied to the input element with
|
|
55
|
-
`data-simply-field="counter"`.
|
|
56
|
-
|
|
57
|
-
SimplyEdit also does the reverse, whenever you change the input value,
|
|
58
|
-
SimplyEdit will also change the `counterApp.view.counter` value. This is called
|
|
59
|
-
two-way databinding.
|
|
60
|
-
|
|
61
|
-
Two-way databinding is not instantanous, so whenever you change a value in
|
|
62
|
-
javascript or in the DOM, it will take a short while for SimplyEdit to update
|
|
63
|
-
the other side as well. There are a number of events that will tell you when
|
|
64
|
-
the values are in sync again.
|
|
65
|
-
|
|
66
|
-
## Todo
|
|
67
|
-
|
|
68
|
-
The TodoMVC application is a standard web application implemented in many different
|
|
69
|
-
javascript frameworks. We've build one using SimplyEdit and SimplyView, which you
|
|
70
|
-
can find at [todomvc.simplyedit.io](https://todomvc.simplyedit.io/).
|
|
71
|
-
|
|
72
|
-
The code is on github at
|
|
73
|
-
[github.com/simplyedit/todomvc](https://github.com/simplyedit/todomvc). The
|
|
74
|
-
Readme explains how it is build.
|
|
75
|
-
|
|
76
|
-
## Hackernews PWA
|
|
77
|
-
|
|
78
|
-
Just like the TodoMVC application, the Hackernews PWA is also a standard web
|
|
79
|
-
application implemented in many frameworks. You can find the SimplyEdit/SimplyView
|
|
80
|
-
version at [hnpwa.simplyedit.io](https://hnpwa.simplyedit.io/). The code is at
|
|
81
|
-
[github.com/simplyedit/hnpwa](https://github.com/simplyedit/hnpwa) and the
|
|
82
|
-
Readme explains how it was built.
|