simplyview 2.0.1 → 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.
@@ -1098,6 +1098,51 @@ properties for a given parent, keep seperate index for this?
1098
1098
  }
1099
1099
 
1100
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);
1101
1146
  (function(global) {
1102
1147
  'use strict';
1103
1148
 
@@ -1986,7 +2031,8 @@ properties for a given parent, keep seperate index for this?
1986
2031
  simply.route.match(global.location.pathname+global.location.hash);
1987
2032
  });
1988
2033
  }
1989
- this.container = options.container || document.body;
2034
+ this.container = options.container || document.body;
2035
+ this.keyboard = simply.keyboard ? simply.keyboard(this, options.keyboard || {}) : false;
1990
2036
  this.actions = simply.action ? simply.action(this, options.actions) : false;
1991
2037
  this.commands = simply.command ? simply.command(this, options.commands) : false;
1992
2038
  this.resize = simply.resize ? simply.resize(this, options.resize) : false;
@@ -0,0 +1,60 @@
1
+ # simply.keyboard
2
+
3
+ simply.keyboard is a simple library to add keyboard support to your application:
4
+
5
+ ```javascript
6
+ let myKeys = {
7
+ default: {
8
+ ArrowDown: (e) => {
9
+ // handle arrow down
10
+ }
11
+ }
12
+ }
13
+ simply.keyboard(myApp, myKeys);
14
+ ```
15
+
16
+ But generally you won't use this directly, but through simply.app:
17
+
18
+ ```javascript
19
+ var myApp = simply.app({
20
+ keyboard: {
21
+ default: {
22
+ ArrowDown: (e) => {
23
+
24
+ }
25
+ }
26
+ }
27
+ });
28
+ ```
29
+
30
+ You can add multiple keyboard definitions:
31
+
32
+ ```javascript
33
+ var counterApp = simply.app({
34
+ keyboard: {
35
+ default: {
36
+ ArrowDown: (e) => {
37
+
38
+ }
39
+ },
40
+ alternate: {
41
+ ArrowDown: (e) => {
42
+
43
+ }
44
+ }
45
+ }
46
+ });
47
+ ```
48
+
49
+ The default keyboard is 'default', but you can switch the keyboard by setting this attribute:
50
+
51
+ ```html
52
+ <div data-simply-keyboard="alternate">
53
+ <input type="text" name="example">
54
+ </div>
55
+ ```
56
+
57
+ Whenever a keyboard `keydown` is fired, simply.keyboard will look for the closest parent with a `data-simply-keyboard` attribute. If found, it will use that keyboard definition. If not found, it will use `default`.
58
+
59
+ The `keydown` event is only handled if the activeElement (the element that has focus) is inside the application container. See `simply.app` for more on that.
60
+
@@ -16,6 +16,7 @@
16
16
  <div>Counter is now: <span data-simply-field="counter"></span></div>
17
17
  </div>
18
18
 
19
+ <script src="//cdn.simplyedit.io/1/simply-edit.js"></script>
19
20
  <script src="../dist/simply.everything.js"></script>
20
21
  <script>
21
22
  var counterApp = simply.app({
@@ -0,0 +1,41 @@
1
+ <h1>Examples</h1>
2
+ <h2>Keyboard</h2>
3
+ <link rel="stylesheet" href="examples.css">
4
+
5
+ <div id="myApp">
6
+ <input type="text" data-simply-field="counter">
7
+ <button data-simply-command="add1">+</button>
8
+ <button data-simply-command="sub1">-</button>
9
+ <div>Counter is now: <span data-simply-field="counter"></span></div>
10
+ </div>
11
+
12
+ <script src="../dist/simply.everything.js"></script>
13
+ <script src="//cdn.simplyedit.io/1/simply-edit.js"></script>
14
+ <script>
15
+ var myApp = simply.app({
16
+ container: document.getElementById('myApp'),
17
+ keyboard: {
18
+ default: {
19
+ ArrowDown: function(e) {
20
+ this.view.counter--;
21
+ e.preventDefault();
22
+ },
23
+ ArrowUp: function(e) {
24
+ this.view.counter++;
25
+ e.preventDefault();
26
+ }
27
+ }
28
+ },
29
+ commands: {
30
+ add1: function(el, value) {
31
+ this.app.view.counter++;
32
+ },
33
+ sub1: function(el, value) {
34
+ this.app.view.counter--;
35
+ }
36
+ },
37
+ view: {
38
+ counter: 1
39
+ }
40
+ });
41
+ </script>
package/js/simply.app.js CHANGED
@@ -29,7 +29,8 @@
29
29
  simply.route.match(global.location.pathname+global.location.hash);
30
30
  });
31
31
  }
32
- this.container = options.container || document.body;
32
+ this.container = options.container || document.body;
33
+ this.keyboard = simply.keyboard ? simply.keyboard(this, options.keyboard || {}) : false;
33
34
  this.actions = simply.action ? simply.action(this, options.actions) : false;
34
35
  this.commands = simply.command ? simply.command(this, options.commands) : false;
35
36
  this.resize = simply.resize ? simply.resize(this, options.resize) : false;
@@ -0,0 +1,45 @@
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
+ if (keys[selectedKeyboard] && keys[selectedKeyboard][e.code]) {
29
+ keys[selectedKeyboard][e.code].call(app,e);
30
+ }
31
+ });
32
+
33
+ return keys;
34
+ }
35
+
36
+
37
+ if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
38
+ module.exports = keyboard;
39
+ } else {
40
+ if (!global.simply) {
41
+ global.simply = {};
42
+ }
43
+ global.simply.keyboard = keyboard;
44
+ }
45
+ })(this);
package/make CHANGED
@@ -7,6 +7,7 @@ cat js/simply.observe.js \
7
7
  js/simply.activate.js \
8
8
  js/simply.collect.js \
9
9
  js/simply.command.js \
10
+ js/simply.keyboard.js \
10
11
  js/simply.action.js \
11
12
  js/simply.resize.js \
12
13
  js/simply.include.js \
package/make~ ADDED
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+ rm dist/simply.everything.js
3
+ cat js/simply.observe.js \
4
+ js/simply.render.js \
5
+ js/simply.path.js \
6
+ js/simply.route.js \
7
+ js/simply.activate.js \
8
+ js/simply.collect.js \
9
+ js/simply.command.js \
10
+ js/simply.action.js \
11
+ js/simply.resize.js \
12
+ js/simply.include.js \
13
+ js/simply.view.js \
14
+ js/simply.viewmodel.js \
15
+ js/simply.api.js \
16
+ js/simply.app.js > dist/simply.everything.js
17
+ cp js/simply.include.next.js dist/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simplyview",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Library to rapidly build UI components, using declarative tools",
5
5
  "main": "dist/simply.everything.js",
6
6
  "directories": {
package/package.json~ CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simplyview",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Library to rapidly build UI components, using declarative tools",
5
5
  "main": "dist/simply.everything.js",
6
6
  "directories": {
package/js/simply.api.js~ DELETED
@@ -1,225 +0,0 @@
1
- (function(global) {
2
- 'use strict';
3
-
4
- var api = {
5
- /**
6
- * Returns a Proxy object that translates property access to a URL in the api
7
- * and method calls to a fetch on that URL.
8
- * @param options: a list of options for fetch(),
9
- * see the 'init' parameter at https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters
10
- * additionally:
11
- * - baseURL: (required) the endpoint of the API
12
- * - path: the current path in the API, is appended to the baseURL
13
- * - verbs: list of http verbs to allow as methods, default ['get','post']
14
- * - handlers.fetch: alternative fetch method
15
- * - handlers.result: alternative getResult method
16
- * - handlers.error: alternative error method
17
- * - user (and password): if set, a basic authentication header will be added
18
- * - paramsFormat: either 'formData', 'json' or 'search'. Default is search.
19
- * - responseFormat: test, formData, blob, json, arrayBuffer or unbuffered. Default is json.
20
- * @return Proxy
21
- */
22
- proxy: function(options) {
23
- var cache = () => {};
24
- cache.$options = Object.assign({}, options);
25
- return new Proxy( cache, getApiHandler(cache.$options) );
26
- },
27
-
28
- /**
29
- * Fetches the options.baseURL using the fetch api and returns a promise
30
- * Extra options in addition to those of global.fetch():
31
- * - user (and password): if set, a basic authentication header will be added
32
- * - paramsFormat: either 'formData', 'json' or 'search'
33
- * By default params, if set, will be added to the baseURL as searchParams
34
- * @param method one of the http verbs, e.g. get, post, etc.
35
- * @param options the options for fetch(), with some additions
36
- * @param params the parameters to send with the request, as javascript/json data
37
- * @return Promise
38
- */
39
- fetch: function(method, params, options) {
40
- if (!options.url) {
41
- if (!options.baseURL) {
42
- throw new Error('No url or baseURL in options object');
43
- }
44
- while (options.baseURL[options.baseURL.length-1]=='/') {
45
- options.baseURL = options.baseURL.substr(0, options.baseURL.length-1);
46
- }
47
- var url = new URL(options.baseURL+options.path);
48
- } else {
49
- var url = options.url;
50
- }
51
- var fetchOptions = Object.assign({}, options);
52
- if (!fetchOptions.headers) {
53
- fetchOptions.headers = {};
54
- }
55
- if (params) {
56
- if (method=='GET') {
57
- var paramsFormat = 'search';
58
- } else {
59
- var paramsFormat = options.paramsFormat;
60
- }
61
- switch(paramsFormat) {
62
- case 'formData':
63
- var formData = new FormData();
64
- for (const name in params) {
65
- formData.append(name, params[name]);
66
- }
67
- if (!fetchOptions.headers['Content-Type']) {
68
- fetchOptions.headers['Content-Type'] = 'application/x-www-form-urlencoded';
69
- }
70
- break;
71
- case 'json':
72
- var formData = JSON.stringify(params);
73
- if (!fetchOptions.headers['Content-Type']) {
74
- fetchOptions.headers['Content-Type'] = 'application/json';
75
- }
76
- break;
77
- case 'search':
78
- var searchParams = url.searchParams; //new URLSearchParams(url.search.slice(1));
79
- for (const name in params) {
80
- searchParams.set(name, params[name]);
81
- }
82
- url.search = searchParams.toString();
83
- break;
84
- default:
85
- throw Error('Unknown options.paramsFormat '+options.paramsFormat+'. Select one of formData, json or search.');
86
- break;
87
- }
88
- }
89
- if (formData) {
90
- fetchOptions.body = formData
91
- }
92
- if (options.user) {
93
- fetchOptions.headers['Authorization'] = 'Basic '+btoa(options.user+':'+options.password);
94
- }
95
- fetchOptions.method = method.toUpperCase();
96
- var fetchURL = url.toString()
97
- return fetch(fetchURL, fetchOptions);
98
- },
99
- graphqlQuery: function(url, operationName, query, options) {
100
- options = Object.assign({ paramsFormat: 'json', url: url, responseFormat: 'json' }, options)
101
- return function(params) {
102
- return simply.api.fetch(
103
- 'POST',
104
- {
105
- operationName: operationName,
106
- query: query,
107
- variables: params || {}
108
- },
109
- options
110
- ).then(function(response) {
111
- return simply.api.getResult(response, options);
112
- });
113
- }
114
- },
115
- /**
116
- * Handles the response and returns a Promise with the response data as specified
117
- * @param response Response
118
- * @param options
119
- * - responseFormat: one of 'text', 'formData', 'blob', 'arrayBuffer', 'unbuffered' or 'json'.
120
- * The default is json.
121
- */
122
- getResult: function(response, options) {
123
- if (response.ok) {
124
- switch(options.responseFormat) {
125
- case 'text':
126
- return response.text();
127
- break;
128
- case 'formData':
129
- return response.formData();
130
- break;
131
- case 'blob':
132
- return response.blob();
133
- break;
134
- case 'arrayBuffer':
135
- return response.arrayBuffer();
136
- break;
137
- case 'unbuffered':
138
- return response.body;
139
- break;
140
- case 'json':
141
- default:
142
- return response.json();
143
- break;
144
- }
145
- } else {
146
- throw {
147
- status: response.status,
148
- message: response.statusText,
149
- response: response
150
- }
151
- }
152
- },
153
- logError: function(error, options) {
154
- console.error(error.status, error.message);
155
- }
156
- }
157
-
158
- var defaultOptions = {
159
- path: '',
160
- responseFormat: 'json',
161
- paramsFormat: 'search',
162
- verbs: ['get','post'],
163
- handlers: {
164
- fetch: api.fetch,
165
- result: api.getResult,
166
- error: api.logError
167
- }
168
- };
169
-
170
- function cd(path, name) {
171
- name = name.replace(/\//g,'');
172
- if (!path.length || path[path.length-1]!=='/') {
173
- path+='/';
174
- }
175
- return path+encodeURIComponent(name);
176
- }
177
-
178
- function fetchChain(prop, params) {
179
- var options = this;
180
- return this.handlers.fetch
181
- .call(this, prop, params, options)
182
- .then(function(res) {
183
- return options.handlers.result.call(options, res, options);
184
- })
185
- .catch(function(error) {
186
- return options.handlers.error.call(options, error, options);
187
- });
188
- }
189
-
190
- function getApiHandler(options) {
191
- options.handlers = Object.assign({}, defaultOptions.handlers, options.handlers);
192
- options = Object.assign({}, defaultOptions, options);
193
-
194
- return {
195
- get: function(cache, prop) {
196
- if (!cache[prop]) {
197
- if (options.verbs.indexOf(prop)!=-1) {
198
- cache[prop] = function(params) {
199
- return fetchChain.call(options, prop, params);
200
- }
201
- } else {
202
- cache[prop] = api.proxy(Object.assign({}, options, {
203
- path: cd(options.path, prop)
204
- }));
205
- }
206
- }
207
- return cache[prop];
208
- },
209
- apply: function(cache, thisArg, params) {
210
- return fetchChain.call(options, 'get', params[0] ? params[0] : null)
211
- }
212
- }
213
- }
214
-
215
-
216
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
217
- module.exports = api;
218
- } else {
219
- if (!global.simply) {
220
- global.simply = {};
221
- }
222
- global.simply.api = api;
223
- }
224
-
225
- })(this);