simplyview 3.0.1 → 3.0.3

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/src/bind.mjs CHANGED
@@ -7,14 +7,28 @@ class SimplyBind {
7
7
  container: document.body,
8
8
  attribute: 'data-bind',
9
9
  transformers: [],
10
- defaultTransformers: [defaultTransformer]
10
+ defaultTransformers: {
11
+ field: [defaultFieldTransformer],
12
+ list: [defaultListTransformer],
13
+ map: [defaultMapTransformer]
14
+ }
11
15
  }
12
16
  if (!options?.root) {
13
17
  throw new Error('bind needs at least options.root set')
14
18
  }
15
19
  this.options = Object.assign({}, defaultOptions, options)
16
20
 
17
- const attribute = this.options.attribute
21
+ const attribute = this.options.attribute
22
+ const bindAttributes = [attribute+'-field',attribute+'-list',attribute+'-map']
23
+ const bindSelector = `[${attribute}-field],[${attribute}-list],[${attribute}-map]`
24
+
25
+ const getBindingAttribute = (el) => {
26
+ const foundAttribute = bindAttributes.find(attr => el.hasAttribute(attr))
27
+ if (!foundAttribute) {
28
+ console.error('No matching attribute found',el)
29
+ }
30
+ return foundAttribute
31
+ }
18
32
 
19
33
  // sets up the effect that updates the element if its
20
34
  // data binding value changes
@@ -23,8 +37,9 @@ class SimplyBind {
23
37
  this.bindings.set(el, throttledEffect(() => {
24
38
  const context = {
25
39
  templates: el.querySelectorAll(':scope > template'),
26
- path: this.getBindingPath(el)
40
+ attribute: getBindingAttribute(el)
27
41
  }
42
+ context.path = this.getBindingPath(el)
28
43
  context.value = getValueByPath(this.options.root, context.path)
29
44
  context.element = el
30
45
  runTransformers(context)
@@ -36,7 +51,18 @@ class SimplyBind {
36
51
  // each transformer can opt to call the next or not
37
52
  // transformers should return the context object (possibly altered)
38
53
  const runTransformers = (context) => {
39
- let transformers = this.options.defaultTransformers || []
54
+ let transformers
55
+ switch(context.attribute) {
56
+ case this.options.attribute+'-field':
57
+ transformers = this.options.defaultTransformers.field || []
58
+ break
59
+ case this.options.attribute+'-list':
60
+ transformers = this.options.defaultTransformers.list || []
61
+ break
62
+ case this.options.attribute+'-map':
63
+ transformers = this.options.defaultTransformers.map || []
64
+ break
65
+ }
40
66
  if (context.element.dataset.transform) {
41
67
  context.element.dataset.transform.split(' ').filter(Boolean).forEach(t => {
42
68
  if (this.options.transformers[t]) {
@@ -69,12 +95,13 @@ class SimplyBind {
69
95
  // if any element is added, and has a data bind attribute
70
96
  // it applies that data binding
71
97
  const updateBindings = (changes) => {
98
+ const selector = `[${attribute}-field],[${attribute}-list],[${attribute}-map]`
72
99
  for (const change of changes) {
73
100
  if (change.type=="childList" && change.addedNodes) {
74
101
  for (let node of change.addedNodes) {
75
102
  if (node instanceof HTMLElement) {
76
- let bindings = Array.from(node.querySelectorAll(`[${attribute}]`))
77
- if (node.matches(`[${attribute}]`)) {
103
+ let bindings = Array.from(node.querySelectorAll(selector))
104
+ if (node.matches(selector)) {
78
105
  bindings.unshift(node)
79
106
  }
80
107
  if (bindings.length) {
@@ -100,7 +127,11 @@ class SimplyBind {
100
127
  // this finds elements with data binding attributes and applies those bindings
101
128
  // must come after setting up the observer, or included templates
102
129
  // won't trigger their own bindings
103
- const bindings = this.options.container.querySelectorAll('['+this.options.attribute+']:not(template)')
130
+ const bindings = this.options.container.querySelectorAll(
131
+ '['+this.options.attribute+'-field]'+
132
+ ',['+this.options.attribute+'-list]'+
133
+ ',['+this.options.attribute+'-map]'
134
+ )
104
135
  if (bindings.length) {
105
136
  applyBindings(bindings)
106
137
  }
@@ -127,23 +158,25 @@ class SimplyBind {
127
158
  }
128
159
  let clone = template.content.cloneNode(true)
129
160
  if (!clone.children?.length) {
130
- throw new Error('template must contain a single html element', { cause: template })
161
+ return clone
131
162
  }
132
163
  if (clone.children.length>1) {
133
164
  throw new Error('template must contain a single root node', { cause: template })
134
165
  }
135
- const bindings = clone.querySelectorAll('['+this.options.attribute+']')
136
166
  const attribute = this.options.attribute
167
+ const attributes = [attribute+'-field',attribute+'-list',attribute+'-map']
168
+ const bindings = clone.querySelectorAll(`[${attribute}-field],[${attribute}-list],[${attribute}-map]`)
137
169
  for (let binding of bindings) {
138
- const bind = binding.getAttribute(attribute)
139
- if (bind.substring(0, '#root.'.length)=='#root.') {
140
- binding.setAttribute(attribute, bind.substring('#root.'.length))
141
- } else if (bind=='#value' && index!=null) {
142
- binding.setAttribute(attribute, path+'.'+index)
170
+ const attr = attributes.find(attr => binding.hasAttribute(attr))
171
+ const bind = binding.getAttribute(attr)
172
+ if (bind.substring(0, ':root.'.length)==':root.') {
173
+ binding.setAttribute(attr, bind.substring(':root.'.length))
174
+ } else if (bind==':value' && index!=null) {
175
+ binding.setAttribute(attr, path+'.'+index)
143
176
  } else if (index!=null) {
144
- binding.setAttribute(attribute, path+'.'+index+'.'+bind)
177
+ binding.setAttribute(attr, path+'.'+index+'.'+bind)
145
178
  } else {
146
- binding.setAttribute(attribute, parent+'.'+bind)
179
+ binding.setAttribute(attr, parent+'.'+bind)
147
180
  }
148
181
  }
149
182
  if (typeof index !== 'undefined') {
@@ -156,7 +189,16 @@ class SimplyBind {
156
189
  }
157
190
 
158
191
  getBindingPath(el) {
159
- return el.getAttribute(this.options.attribute)
192
+ const attributes = [
193
+ this.options.attribute+'-field',
194
+ this.options.attribute+'-list',
195
+ this.options.attribute+'-map'
196
+ ]
197
+ for (let attr of attributes) {
198
+ if (el.hasAttribute(attr)) {
199
+ return el.getAttribute(attr)
200
+ }
201
+ }
160
202
  }
161
203
 
162
204
  /**
@@ -169,7 +211,7 @@ class SimplyBind {
169
211
  let path = this.getBindingPath(t)
170
212
  let currentItem
171
213
  if (path) {
172
- if (path.substr(0,6)=='#root.') {
214
+ if (path.substr(0,6)==':root.') {
173
215
  currentItem = getValueByPath(this.options.root, path)
174
216
  } else {
175
217
  currentItem = getValueByPath(value, path)
@@ -182,20 +224,21 @@ class SimplyBind {
182
224
  const strItem = ''+currentItem
183
225
  let matches = t.getAttribute(this.options.attribute+'-match')
184
226
  if (matches) {
185
- if (matches==='#empty' && !currentItem) {
227
+ if (matches===':empty' && !currentItem) {
186
228
  return t
187
- } else if (matches==='#notempty' && currentItem) {
229
+ } else if (matches===':notempty' && currentItem) {
188
230
  return t
189
231
  }
190
232
  if (strItem.match(matches)) {
191
233
  return t
192
234
  }
193
235
  }
194
- if (!matches) {
195
- // no data-bind-match is set, so return this template is currentItem is truthy
196
- if (currentItem) {
197
- return t
198
- }
236
+ if (!matches && currentItem!==null && currentItem!==undefined) {
237
+ //FIXME: this doesn't run templates in lists where list entry is null
238
+ //which messes up the count
239
+ //
240
+ // no data-bind-match is set, so return this template
241
+ return t
199
242
  }
200
243
  }
201
244
  let template = Array.from(templates).find(templateMatches)
@@ -231,13 +274,13 @@ export function bind(options)
231
274
 
232
275
  /**
233
276
  * Returns true if a matches b, either by having the
234
- * same string value, or matching string #empty against a falsy value
277
+ * same string value, or matching string :empty against a falsy value
235
278
  */
236
279
  export function matchValue(a,b) {
237
- if (a=='#empty' && !b) {
280
+ if (a==':empty' && !b) {
238
281
  return true
239
282
  }
240
- if (b=='#empty' && !a) {
283
+ if (b==':empty' && !a) {
241
284
  return true
242
285
  }
243
286
  if (''+a == ''+b) {
@@ -259,11 +302,11 @@ export function getValueByPath(root, path)
259
302
  let part, prevPart;
260
303
  while (parts.length && curr) {
261
304
  part = parts.shift()
262
- if (part=='#key') {
305
+ if (part==':key') {
263
306
  return prevPart
264
- } else if (part=='#value') {
307
+ } else if (part==':value') {
265
308
  return curr
266
- } else if (part=='#root') {
309
+ } else if (part==':root') {
267
310
  curr = root
268
311
  } else {
269
312
  part = decodeURIComponent(part)
@@ -278,7 +321,7 @@ export function getValueByPath(root, path)
278
321
  * Default transformer for data binding
279
322
  * Will be used unless overriden in the SimplyBind options parameter
280
323
  */
281
- export function defaultTransformer(context) {
324
+ export function defaultFieldTransformer(context) {
282
325
  const el = context.element
283
326
  const templates = context.templates
284
327
  const templatesCount = templates.length
@@ -286,11 +329,7 @@ export function defaultTransformer(context) {
286
329
  const value = context.value
287
330
  const attribute = this.options.attribute
288
331
 
289
- if (Array.isArray(value) && templates?.length) {
290
- transformArrayByTemplates.call(this, context)
291
- } else if (typeof value == 'object' && templates?.length) {
292
- transformObjectByTemplates.call(this, context)
293
- } else if (templates?.length) {
332
+ if (templates?.length) {
294
333
  transformLiteralByTemplates.call(this, context)
295
334
  } else if (el.tagName=='INPUT') {
296
335
  transformInput.call(this, context)
@@ -306,10 +345,49 @@ export function defaultTransformer(context) {
306
345
  return context
307
346
  }
308
347
 
348
+ export function defaultListTransformer(context) {
349
+ const el = context.element
350
+ const templates = context.templates
351
+ const templatesCount = templates.length
352
+ const path = context.path
353
+ const value = context.value
354
+ const attribute = this.options.attribute
355
+
356
+ if (!Array.isArray(value)) {
357
+ console.error('Value is not an array.', el, value)
358
+ } else if (!templates?.length) {
359
+ console.error('No templates found in', el)
360
+ } else {
361
+ transformArrayByTemplates.call(this, context)
362
+ }
363
+ return context
364
+ }
365
+
366
+ export function defaultMapTransformer(context) {
367
+ const el = context.element
368
+ const templates = context.templates
369
+ const templatesCount = templates.length
370
+ const path = context.path
371
+ const value = context.value
372
+ const attribute = this.options.attribute
373
+
374
+ if (typeof value != 'object') {
375
+ console.error('Value is not an object.', el, value)
376
+ } else if (!templates?.length) {
377
+ console.error('No templates found in', el)
378
+ } else {
379
+ transformObjectByTemplates.call(this, context)
380
+ }
381
+ return context
382
+ }
383
+
384
+
309
385
  /**
310
386
  * Renders an array value by applying templates for each entry
311
387
  * Replaces or removes existing DOM children if needed
312
388
  * Reuses (doesn't touch) DOM children if template doesn't change
389
+ * FIXME: this doesn't handle situations where there is no matching template
390
+ * this messes up self healing. check transformObjectByTemplates for a better implementation
313
391
  */
314
392
  export function transformArrayByTemplates(context) {
315
393
  const el = context.element
@@ -335,14 +413,14 @@ export function transformArrayByTemplates(context) {
335
413
  // remove this
336
414
  item.remove()
337
415
  } else {
338
- // check that all data-bind params start with current json path or a '#', otherwise replaceChild
416
+ // check that all data-bind params start with current json path or ':root', otherwise replaceChild
339
417
  let bindings = Array.from(item.querySelectorAll(`[${attribute}]`))
340
418
  if (item.matches(`[${attribute}]`)) {
341
419
  bindings.unshift(item)
342
420
  }
343
421
  let needsReplacement = bindings.find(b => {
344
422
  let databind = b.getAttribute(attribute)
345
- return (databind.substr(0,5)!=='#root'
423
+ return (databind.substr(0,5)!==':root'
346
424
  && databind.substr(0, path.length)!==path)
347
425
  })
348
426
  if (!needsReplacement) {
@@ -385,7 +463,7 @@ export function transformArrayByTemplates(context) {
385
463
 
386
464
  /**
387
465
  * Renders an object value by applying templates for each entry (Object.entries)
388
- * Replaces or removes existing DOM children if needed
466
+ * Replaces,moves or removes existing DOM children if needed
389
467
  * Reuses (doesn't touch) DOM children if template doesn't change
390
468
  */
391
469
  export function transformObjectByTemplates(context) {
@@ -397,61 +475,55 @@ export function transformObjectByTemplates(context) {
397
475
  const attribute = this.options.attribute
398
476
  context.list = value
399
477
 
400
- let list = Object.entries(value)
401
- let items = el.querySelectorAll(':scope > ['+attribute+'-key]')
402
- let current = 0
403
- let skipped = 0
404
- for (let item of items) {
405
- if (current>=list.length) {
406
- break
478
+ let items = Array.from(el.querySelectorAll(':scope > ['+attribute+'-key]'))
479
+ for (let key in context.list) {
480
+ context.index = key
481
+ let item = items.shift()
482
+ if (!item) { // more properties than rendered items
483
+ let clone = this.applyTemplate(context)
484
+ if (clone.firstElementChild) {
485
+ el.appendChild(clone)
486
+ }
487
+ continue
407
488
  }
408
- let key = list[current][0]
409
- current++
410
- let keypath = path+'.'+key
411
- // check that all data-bind params start with current json path or a '#', otherwise replaceChild
412
- let needsReplacement
413
- const databind = item.getAttribute(attribute)
414
- if (databind && databind.substr(0, keypath.length)!=keypath) {
415
- needsReplacement=true
416
- } else {
417
- let bindings = Array.from(item.querySelectorAll(`[${attribute}]`))
418
- needsReplacement = bindings.find(b => {
419
- const db = b.getAttribute(attribute)
420
- return (db.substr(0,5)!=='#root' && db.substr(0, keypath.length)!==keypath)
421
- })
422
- if (!needsReplacement) {
423
- if (item.$bindTemplate) {
424
- let newTemplate = this.findTemplate(templates, value[key])
425
- if (newTemplate != item.$bindTemplate){
426
- needsReplacement = true
427
- if (!newTemplate) {
428
- skipped++
429
- }
430
- }
489
+ if (item.getAttribute[attribute+'-key']!=key) {
490
+ // next item doesn't match key
491
+ items.unshift(item) // put item back for next cycle
492
+ let outOfOrderItem = el.querySelector(':scope > ['+attribute+'-key="'+key+'"]') //FIXME: escape key
493
+ if (!outOfOrderItem) {
494
+ let clone = this.applyTemplate(context)
495
+ if (clone.firstElementChild) {
496
+ el.insertBefore(clone, item)
431
497
  }
498
+ continue // new template doesn't need replacement, so continue
499
+ } else {
500
+ el.insertBefore(outOfOrderItem, item)
501
+ item = outOfOrderItem // check needsreplacement next
502
+ items = items.filter(i => i!=outOfOrderItem)
432
503
  }
433
504
  }
434
- if (needsReplacement) {
435
- context.index = key
505
+ let newTemplate = this.findTemplate(templates, value[key])
506
+ if (newTemplate != item.$bindTemplate){
436
507
  let clone = this.applyTemplate(context)
437
508
  el.replaceChild(clone, item)
438
509
  }
439
510
  }
440
- items = el.querySelectorAll(':scope > ['+attribute+'-key]')
441
- let length = items.length + skipped
442
- if (length>list.length) {
443
- while (length>list.length) {
444
- let child = el.querySelectorAll(':scope > :not(template)')?.[length-1]
445
- child?.remove()
446
- length--
447
- }
448
- } else if (length < list.length) {
449
- while (length < list.length) {
450
- context.index = list[length][0]
451
- el.appendChild(this.applyTemplate(context))
452
- length++
453
- }
454
- }
511
+ // clean up remaining items
512
+ while (items.length) {
513
+ item = items.shift()
514
+ item.remove()
515
+ }
516
+ }
517
+
518
+ function getParentPath(el, attribute) {
519
+ const parentEl = el.parentElement?.closest(`[${attribute}-list],[${attribute}-map]`)
520
+ if (!parentEl) {
521
+ return ':root'
522
+ }
523
+ if (parentEl.hasAttribute(`${attribute}-list`)) {
524
+ return parentEl.getAttribute(`${attribute}-list`)
525
+ }
526
+ return parentEl.getAttribute(`${attribute}-map`)
455
527
  }
456
528
 
457
529
  /**
@@ -468,7 +540,8 @@ export function transformLiteralByTemplates(context) {
468
540
 
469
541
  const rendered = el.querySelector(':scope > :not(template)')
470
542
  const template = this.findTemplate(templates, value)
471
- context.parent = el.parentElement?.closest(`[${attribute}]`)?.getAttribute(attribute) || '#root'
543
+
544
+ context.parent = getParentPath(el, attribute)
472
545
  if (rendered) {
473
546
  if (template) {
474
547
  if (rendered?.$bindTemplate != template) {
@@ -567,6 +640,10 @@ export function transformElement(context) {
567
640
  const value = context.value
568
641
 
569
642
  if (!matchValue(el.innerHTML, value)) {
570
- el.innerHTML = ''+value
643
+ if (typeof value=='undefined' || value==null) {
644
+ el.innerHTML = ''
645
+ } else {
646
+ el.innerHTML = ''+value
647
+ }
571
648
  }
572
649
  }
package/src/command.mjs CHANGED
@@ -21,7 +21,7 @@ class SimplyCommands {
21
21
  return
22
22
  }
23
23
  const shouldContinue = this[command.name].call(options.app, command.source, command.value)
24
- if (shouldContinue===false) {
24
+ if (shouldContinue!==true) {
25
25
  evt.preventDefault()
26
26
  evt.stopPropagation()
27
27
  return false
@@ -1,25 +1,21 @@
1
1
  import { activate } from './activate.mjs'
2
- import * as action from './action.mjs'
2
+ import { actions as action } from './action.mjs'
3
3
  import { app } from './app.mjs'
4
- import { bind } from './bind.mjs'
5
- import * as command from './command.mjs'
4
+ import { commands as command } from './command.mjs'
6
5
  import { include } from './include.mjs'
7
- import * as key from './key.mjs'
8
- import * as model from './model.mjs'
9
- import * as route from './route.mjs'
10
- import * as state from './state.mjs'
6
+ import { keys as key } from './key.mjs'
7
+ import { routes as route } from './route.mjs'
8
+ import { view } from './view.mjs'
11
9
 
12
10
  const simply = {
13
11
  activate,
14
12
  action,
15
13
  app,
16
- bind,
17
14
  command,
18
15
  include,
19
16
  key,
20
- model,
21
17
  route,
22
- state
18
+ view
23
19
  }
24
20
 
25
21
  window.simply = simply
package/src/include.mjs CHANGED
@@ -53,7 +53,7 @@ const waitForPreviousScripts = async () => {
53
53
  // that triggers the Promise.resolve method
54
54
  return new Promise(function(resolve) {
55
55
  var next = globalThis.document.createElement('script')
56
- next.src = rebaseHref('simply.include.next.js', currentScriptURL)
56
+ next.src = "https://cdn.jsdelivr.net/gh/simplyedit/simplyview/dist/simply.include.next.js"
57
57
  next.async = false
58
58
  globalThis.document.addEventListener('simply-include-next', () => {
59
59
  head.removeChild(next)
@@ -122,18 +122,21 @@ export const include = {
122
122
  // order in which they are defined
123
123
  let scriptsFragment = globalThis.document.createDocumentFragment()
124
124
  const scripts = fragment.querySelectorAll('script')
125
- for (let script of scripts) {
126
- let placeholder = globalThis.document.createComment(script.src || 'inline script')
127
- script.parentNode.insertBefore(placeholder, script)
128
- script.dataset.simplyLocation = scriptLocations.length
129
- scriptLocations.push(placeholder)
130
- scriptsFragment.appendChild(script)
125
+ if (scripts.length) {
126
+ for (let script of scripts) {
127
+ let placeholder = globalThis.document.createComment(script.src || 'inline script')
128
+ script.parentNode.insertBefore(placeholder, script)
129
+ script.dataset.simplyLocation = scriptLocations.length
130
+ scriptLocations.push(placeholder)
131
+ scriptsFragment.appendChild(script)
132
+ }
133
+ globalThis.setTimeout(function() {
134
+ include.scripts(Array.from(scriptsFragment.children), link ? link.href : globalThis.location.href )
135
+ }, 10)
131
136
  }
132
137
  // add the remainder before the include link
133
138
  link.parentNode.insertBefore(fragment, link ? link : null)
134
- globalThis.setTimeout(function() {
135
- include.scripts(scriptsFragment.childNodes, link ? link.href : globalThis.location.href )
136
- }, 10)
139
+
137
140
  }
138
141
  }
139
142
 
package/src/key.mjs CHANGED
@@ -1,4 +1,12 @@
1
- class SimplyKeys {
1
+ const KEY = Object.freeze({
2
+ Compose: 229,
3
+ Control: 17,
4
+ Meta: 224,
5
+ Alt: 18,
6
+ Shift: 16
7
+ })
8
+
9
+ class SimplyKey {
2
10
  constructor(options = {}) {
3
11
  if (!options.app) {
4
12
  options.app = {}
@@ -9,38 +17,83 @@ class SimplyKeys {
9
17
  Object.assign(this, options.keys)
10
18
 
11
19
  const keyHandler = (e) => {
12
- if (e.isComposing || e.keyCode === 229) {
13
- return;
20
+ if (e.isComposing || e.keyCode === KEY.Compose) {
21
+ return
14
22
  }
15
23
  if (e.defaultPrevented) {
16
- return;
24
+ return
17
25
  }
18
26
  if (!e.target) {
19
- return;
27
+ return
20
28
  }
21
29
 
22
- let selectedKeyboard = 'default';
30
+ let selectedKeyboard = 'default'
23
31
  if (e.target.closest('[data-simply-keyboard]')) {
24
- selectedKeyboard = e.target.closest('[data-simply-keyboard]').dataset.simplyKeyboard;
32
+ selectedKeyboard = e.target.closest('[data-simply-keyboard]')
33
+ .dataset.simplyKeyboard
34
+ }
35
+ let keyCombination = []
36
+ if (e.ctrlKey && e.keyCode!=KEY.Control) {
37
+ keyCombination.push('Control')
25
38
  }
26
- let key = '';
27
- if (e.ctrlKey && e.keyCode!=17) {
28
- key+='Control+';
39
+ if (e.metaKey && e.keyCode!=KEY.Meta) {
40
+ keyCombination.push('Meta')
29
41
  }
30
- if (e.metaKey && e.keyCode!=224) {
31
- key+='Meta+';
42
+ if (e.altKey && e.keyCode!=KEY.Alt) {
43
+ keyCombination.push('Alt')
32
44
  }
33
- if (e.altKey && e.keyCode!=18) {
34
- key+='Alt+';
45
+ if (e.shiftKey && e.keyCode!=KEY.Shift) {
46
+ keyCombination.push('Shift')
35
47
  }
36
- if (e.shiftKey && e.keyCode!=16) {
37
- key+='Shift+';
48
+ keyCombination.push(e.key.toLowerCase())
49
+
50
+ let keyboards = []
51
+ let keyboardElement = event.target.closest('[data-simply-keyboard]')
52
+ while (keyboardElement) {
53
+ keyboards.push(keyboardElement.dataset.simplyKeyboard)
54
+ keyboardElement = keyboardElement.parentNode.closest('[data-simply-keyboard]')
38
55
  }
39
- key+=e.key;
56
+ keyboards.push('')
57
+
58
+ let keyboard, subkeyboard
59
+ let separators = ['+','-']
60
+
61
+ for (i in keyboards) {
62
+ keyboard = keyboards[i]
63
+ if (keyboard == '') {
64
+ subkeyboard = 'default'
65
+ } else {
66
+ subkeyboard = keyboard
67
+ keyboard += '.'
68
+ }
69
+ for (let separator of separators) {
70
+ let keyString = keyCombination.join(separator)
71
+
72
+ if (this[subkeyboard] && (typeof this[subkeyboard][keyString]=='function')) {
73
+ let _continue = this[subkeyboard][keyString].call(this[subkeyboard], e)
74
+ if (!_continue) {
75
+ e.preventDefault()
76
+ return
77
+ }
78
+ }
79
+ if (typeof this[subkeyboard + keyString] == 'function') {
80
+ let _continue = this[subkeyboard + keyString].call(this, e)
81
+ if (!_continue) {
82
+ e.preventDefault()
83
+ return
84
+ }
85
+ }
86
+
87
+ if (this[selectedKeyboard] && this[selectedKeyboard][keyString]) {
88
+ let targets = options.app.container.querySelectorAll('[data-simply-accesskey="'
89
+ + keyboard + keyString + '"]')
90
+ if (targets.length) {
91
+ targets.forEach(t => t.click())
92
+ e.preventDefault()
93
+ }
94
+ }
40
95
 
41
- if (this[selectedKeyboard] && this[selectedKeyboard][key]) {
42
- let keyboard = this[selectedKeyboard]
43
- keyboard[key].call(options.app,e);
96
+ }
44
97
  }
45
98
  }
46
99
 
@@ -50,6 +103,6 @@ class SimplyKeys {
50
103
  }
51
104
 
52
105
  export function keys(options={}) {
53
- return new SimplyKeys(options)
106
+ return new SimplyKey(options)
54
107
  }
55
108
 
package/src/route.mjs CHANGED
@@ -65,6 +65,8 @@ class SimplyRoute {
65
65
  if (path && path[path.length-1]!='/') {
66
66
  return this.match(path+'/', options)
67
67
  }
68
+ console.log(path, this.routeInfo)
69
+ process.exit()
68
70
  return false
69
71
  }
70
72
 
@@ -199,8 +201,7 @@ function getRegexpFromRoute(route) {
199
201
  return new RegExp('^'+route.replace(/:\w+/g, '([^/]+)').replace(/:\*/, '(.*)'));
200
202
  }
201
203
 
202
- function parseRoutes(routes) {
203
- let routeInfo = []
204
+ function parseRoutes(routes, routeInfo) {
204
205
  const paths = Object.keys(routes)
205
206
  const matchParams = /:(\w+|\*)/g
206
207
  for (let path of paths) {