fleetio_spark 0.2.27 → 0.2.28

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc42c14c4aab7798c8153757249be9c4fface8724b422471b15328148947c462
4
- data.tar.gz: 86980573ee2acb25dcb635a107f790b65fed14b13c2703ca5a5931ebf5c52d42
3
+ metadata.gz: 6ae67716c57e2a7d14b83575192dbb948f5aee51a653a3ec07a79fa54ec1bd54
4
+ data.tar.gz: b995d27caef6905dc0b8030d16097438ac1883118097f222d57f7a033d715c85
5
5
  SHA512:
6
- metadata.gz: 26f10ccefbd2422364eea1f1ca80cf81883b20067e3f33a8edae10a824aae1c2fed58a6cb521ceaf77402c50e91f7c2b878394411f8dc4802a8f68e1b80db1f4
7
- data.tar.gz: 883b263a816346b45b7ee7b03b04910aed1cdacaccf9ef14e2830e1627391f1ed9b2afe91b6fc7dd01bd7376d221538b4fc60c71129ebf295dd83ee877c04812
6
+ metadata.gz: b593cd1e85c41b3ee0f4fa67154036c93419cc5e2c4d59fcdbbef22da2220c68738e665c94dd1b261b713b0186e6cd792d5f2970b5c57f3376464c356488cc2d
7
+ data.tar.gz: 655489cb5b0716f7fb5debc574cb6a0efb816972dbc7e5a3b0b76621d08611c2284a9289fb505594b6200194ecb5d5b7657f1ce02ef3c5520ddc26130e6a1b6a
@@ -0,0 +1,74 @@
1
+ var toolbox = require('@spark-engine/toolbox'),
2
+ Event = require('@spark-engine/event')
3
+
4
+ function navigateMenu(event) {
5
+ var link,
6
+ activeEl = document.activeElement
7
+
8
+ if(Event.key.isPressed('down')) {
9
+ if (activeEl.tagName.match(/select|button/i) || activeEl.closest('[aria-hidden="true"]')) { return }
10
+ // Prevent page scrolling as a result of keypress
11
+ event.preventDefault()
12
+ event.stopImmediatePropagation()
13
+ link = getNextLink()
14
+
15
+ } else if(Event.key.isPressed('up')) {
16
+ // Prevent page scrolling as a result of keypress
17
+ if (activeEl.tagName.match(/select|button/i)) { return }
18
+ event.preventDefault()
19
+ event.stopImmediatePropagation()
20
+ link = getPreviousLink()
21
+ } else {
22
+ link = false
23
+ }
24
+
25
+ // Only focus if there is a next or previous link to move to
26
+ // At top or bottom of a list there is no "next" or "previous"
27
+ if (link) link.focus()
28
+
29
+ }
30
+
31
+ // Find the next focusable link
32
+ function getNextLink() {
33
+ var items = links(),
34
+ pos = items.indexOf(document.activeElement)
35
+
36
+ // No active element: return first element
37
+ if (pos == -1) return items[ 0 ]
38
+
39
+ // Last element focused, return nothing (no next element)
40
+ else if (pos == items.length) return
41
+
42
+ // return next focusable link
43
+ else return items[ pos + 1 ]
44
+ }
45
+
46
+ // Find the previous focusable link
47
+ function getPreviousLink (el) {
48
+ var items = links(),
49
+ pos = items.indexOf(document.activeElement)
50
+
51
+ // No previous element to select
52
+ if (pos == -1 || pos == 0) return
53
+
54
+ // return previous focusable link
55
+ else return items[ pos - 1 ]
56
+ }
57
+
58
+ // Return all links in current modal
59
+ function links() {
60
+ var menu = document.activeElement.closest('[role="menu"]')
61
+ return Array.prototype.filter.call(menu.querySelectorAll('a'), function(a) {
62
+ return a.offsetParent != null
63
+ })
64
+ }
65
+
66
+ function setup () {
67
+ Event.ready(function() {
68
+ Event.on(document, 'keydown', 'nav[role="menu"]', navigateMenu)
69
+ })
70
+ }
71
+
72
+ module.exports = {
73
+ setup: setup
74
+ }
@@ -12,7 +12,7 @@ var style = '<style id="modal-toggle-style">body[data-active-modal] * { p
12
12
 
13
13
  // types of modals
14
14
  // Menu - trigger toggles, clicking outside closes
15
- // Panel - trigger opens, but does not close, clicking outside closes
15
+ // Panel - trigger opens, but does not close, clicking outside (or esc) closes
16
16
  // Dialog - trigger opens, clicking outside is ignored, must be closed by clicking a close button or the escape key
17
17
 
18
18
 
@@ -50,6 +50,7 @@ var Modal = {
50
50
  el.dataset.modalId = modal.id
51
51
  // Hide modal by default
52
52
  el.classList.add('hidden')
53
+ el.setAttribute('hidden', true)
53
54
  el.setAttribute('aria-hidden', true)
54
55
  el.setAttribute('aria-modal', true)
55
56
 
@@ -78,6 +79,7 @@ var Modal = {
78
79
  document.body.classList.add('modal-active')
79
80
  document.body.dataset.modal = el.id || ''
80
81
 
82
+ el.removeAttribute('hidden')
81
83
  el.classList.remove('hidden')
82
84
  el.setAttribute('aria-hidden', false)
83
85
 
@@ -118,6 +120,7 @@ var Modal = {
118
120
 
119
121
  el.classList.remove('modal-is-closing')
120
122
  el.classList.add('hidden')
123
+ el.setAttribute('hidden', true)
121
124
  el.setAttribute('aria-hidden', true)
122
125
 
123
126
  // Set state on modal triggers
@@ -184,12 +187,8 @@ function open (modal) {
184
187
  function activeClick (event) {
185
188
  var modal = activeModal()
186
189
 
187
- // Did the click happen in side the modal, or in a modal safe control?
188
- var modalClick = event.target.closest('[data-modal-id="'+modal.id+'"]')
189
- var panelClick = modal.panel && event.target.closest('[data-for-modal="'+modal.id+'"]')
190
-
191
190
  // Stop the click if it happened outside the modal or panel control
192
- if (!modalClick && !panelClick) {
191
+ if (!isWithinModal(event.target)) {
193
192
  event.stopImmediatePropagation()
194
193
  event.preventDefault()
195
194
 
@@ -197,6 +196,27 @@ function activeClick (event) {
197
196
  }
198
197
  }
199
198
 
199
+ function focused(event) {
200
+ var modal = activeModal()
201
+
202
+ // If a modal panel, close when focus occurs outside.
203
+ if (document.activeElement && !isWithinModal(document.activeElement)) {
204
+ event.stopImmediatePropagation()
205
+ if (modal.panel) modal.close()
206
+ else event.preventDefault()
207
+ }
208
+ }
209
+
210
+ function isWithinModal(el) {
211
+ var modal = activeModal(),
212
+ // Did the click happen in side the modal
213
+ modalClick = el.closest('[data-modal-id="'+modal.id+'"]'),
214
+ // Or in a modal safe control?
215
+ panelClick = modal.panel && !!el.closest('[data-for-modal="'+modal.id+'"]')
216
+
217
+ return modalClick || panelClick
218
+ }
219
+
200
220
  // Use the stack position to determine the current modal
201
221
  function activeModal () {
202
222
  return Stack[ Stack.length - 1 ]
@@ -276,7 +296,7 @@ function triggerEvent (event) {
276
296
  if (el.tagName == 'INPUT') {
277
297
 
278
298
  // Don't open when input is focused
279
- //if (event.type == 'focusin' && el.value == '') return
299
+ // if (event.type == 'focusin' && el.value == '') return
280
300
 
281
301
  // Do not trigger open if input event clears input value
282
302
  if (event.type == 'input' && el.value == '') return
@@ -304,11 +324,11 @@ function keyPress (event) {
304
324
  return close()
305
325
  }
306
326
 
307
- if (activeModal().modal && Event.key.isPressed("tab") && !Event.key.shift) {
327
+ if (activeModal() && Event.key.isPressed("tab") && !Event.key.shift) {
308
328
  focusNext(event)
309
329
  }
310
330
 
311
- //
331
+ /*
312
332
  if (activeModal().panel || activeModal().menu) {
313
333
  var link
314
334
 
@@ -331,70 +351,20 @@ function keyPress (event) {
331
351
  // At top or bottom of a list there is no "next" or "previous"
332
352
  if (link) link.focus()
333
353
 
334
- }
354
+ }*/
335
355
  }
336
356
 
337
357
  function focusNext(event) {
338
358
  var modalEl = activeModal().el,
339
- focusable = modalEl.querySelectorAll('input:not([type=hidden]), textarea, select, button'),
359
+ focusable = modalEl.querySelectorAll('input:not([type=hidden]), textarea, select, button, [tabindex]:not([tabindex="-1"])'),
360
+ focusable = Array.prototype.filter.call(focusable, function(el) {
361
+ return !el.closest('[hidden], [aria-hidden="true"]')
362
+ }),
340
363
  first = focusable[0],
341
364
  last = focusable[focusable.length - 1],
342
365
  focused = document.activeElement
343
366
 
344
367
  // If focused on the last focusable element, tab to the first element.
345
- if (focused == last && !Event.key.shift) {
346
- if (event){ event.preventDefault() }
347
- first.focus()
348
- }
349
-
350
- if (focused == first && Event.key.shift) {
351
- if (event){ event.preventDefault() }
352
- last.focus()
353
- }
354
-
355
- // Focus on the first element if the focused element is not a child of the modal
356
- if (!focused || !toolbox.childOf(focused, modalEl)) {
357
- first.focus()
358
- }
359
- }
360
-
361
- // Find the next focusable link
362
- function getNextLink (el) {
363
- var items = links()
364
- var pos = activePosition()
365
-
366
- // No active element: return first element
367
- if (pos == -1) return items[ 0 ]
368
-
369
- // Last element focused, return nothing (no next element)
370
- else if (pos == items.length) return
371
-
372
- // return next focusable link
373
- else return items[ pos + 1 ]
374
- }
375
-
376
- // Find the previous focusable link
377
- function getPreviousLink (el) {
378
- var items = links()
379
- var pos = activePosition()
380
-
381
- // No previous element to select
382
- if (pos == -1 || pos == 0) return
383
-
384
- // return previous focusable link
385
- else return items[ pos - 1 ]
386
- }
387
-
388
- // Search links in the current modal for an active (focused) element
389
- function activePosition () {
390
- return links().indexOf(document.activeElement)
391
- }
392
-
393
- // Return all links in current modal
394
- function links () {
395
- return toolbox.slice(activeModal().el.querySelectorAll('a')).filter(function(a) {
396
- return !a.closest('[aria-hidden="true"]')
397
- })
398
368
  }
399
369
 
400
370
  function setup () {
@@ -403,6 +373,9 @@ function setup () {
403
373
 
404
374
  // Check all body clicks to see if they should be permitted
405
375
  Event.on(document, 'click', 'body.modal-active', activeClick, { useCapture: true })
376
+
377
+ // Focus outisde of modal (if a panel) should close modal
378
+ Event.on(document, 'focus', '.modal-active', focused, { useCapture: true })
406
379
 
407
380
  // Trigger modals on input events (like a search results panel that waits until typing to show)
408
381
  Event.on(document, 'input', 'input[data-for-modal], [data-for-modal] input', Event.debounce(triggerEvent, 50, { leading: true }))
@@ -419,7 +392,6 @@ function setup () {
419
392
 
420
393
  module.exports = {
421
394
  new: Modal.new,
422
- links: links,
423
395
  setup: setup,
424
396
  modals: Modals,
425
397
  init: init,
@@ -12,6 +12,12 @@ Event.keyOn('/', function(event){
12
12
  }
13
13
  })
14
14
 
15
+ function autoClose(event) {
16
+ if (!document.activeElement.closest('#search_modal')) {
17
+ modal.get('#search-results').close()
18
+ }
19
+ }
20
+
15
21
  function setup() {
16
22
  var q = document.querySelector('[name=q]'),
17
23
  filter = document.querySelector('#search_model')
@@ -35,6 +41,10 @@ function setup() {
35
41
  } else if (focusEl == q && Event.key.isPressed("esc")) {
36
42
  q.value = ''
37
43
  Event.fire(q, 'input')
44
+ } else if (Event.key.isPressed("down")) {
45
+ if (document.activeElement && document.activeElement.tagName.match(/select|button/i)) { return }
46
+ var result = searchStack.currentPanel().querySelector('[role=menu] a')
47
+ if (result) result.focus()
38
48
  }
39
49
  }
40
50
 
@@ -56,6 +66,7 @@ function setup() {
56
66
 
57
67
  searchModal.on('open', function() {
58
68
  Event.on(document, 'keydown', keyWatcher)
69
+ Event.on(document, 'blur', autoClose)
59
70
  })
60
71
 
61
72
  // Reset stack when modal is closed and query is clear
@@ -69,6 +80,7 @@ function setup() {
69
80
  searchPanel.classList.remove('search-in-progress')
70
81
 
71
82
  Event.off(document, 'keydown', keyWatcher)
83
+ Event.off(document, 'blur', autoClose)
72
84
  })
73
85
  }
74
86
 
@@ -95,17 +95,16 @@ var Stack = {
95
95
 
96
96
  stack.updateWatchers()
97
97
 
98
- if (direction == 'forward') {
99
- // If the previous focused element was in the stack
100
- //if (toolbox.childOf(stack.lastFocus(), stack.root)) {
101
-
102
- // focus on the first input
103
- //var firstItem = el.querySelector('input:not([hidden]), textarea, select, a[tabindex]')
104
- //if (firstItem) firstItem.focus()
105
-
98
+ // When going forward remove focus from elements in the previous panel
99
+ //if (direction == 'forward') {
100
+ //if (toolbox.childOf(document.activeElement, stack.root)) {
101
+ //document.activeElement.blur()
102
+ //if (navigated) {
103
+ //var navEl = el.querySelector('[data-stack-nav]')
104
+ //if (navEl) navEl.focus()
105
+ //}
106
106
  //}
107
-
108
- }
107
+ //}
109
108
 
110
109
  // When reversing, focus on the previously focused element
111
110
  if (direction == 'reverse' && stack.focus.length > 0) {
@@ -215,23 +214,25 @@ var Stack = {
215
214
  }
216
215
  }
217
216
 
218
- function showEl (el) {
217
+ function showEl(el) {
218
+ el.removeAttribute('hidden')
219
219
  el.setAttribute('aria-hidden', false)
220
220
  }
221
221
 
222
- function isEmpty (el) {
222
+ function isEmpty(el) {
223
223
  return el.childElementCount == 0
224
224
  }
225
225
 
226
- function hideEl (el) {
226
+ function hideEl(el) {
227
227
  el.setAttribute('aria-hidden', true)
228
+ el.setAttribute('hidden', true)
228
229
  }
229
230
 
230
- function isElement (item) {
231
+ function isElement(item) {
231
232
  return item.constructor.toString().search(/HTML.+Element/) > -1
232
233
  }
233
234
 
234
- function navClick (event) {
235
+ function navClick(event) {
235
236
  var el = event.currentTarget
236
237
  var panel = el.dataset.stackNav
237
238
  var stack = getStack(el.closest('[data-stack="root"]'))
@@ -239,10 +240,23 @@ function navClick (event) {
239
240
 
240
241
  if (panel == 'next') stack.next()
241
242
  else if (panel == 'back') stack.back()
242
- else if (stack.findPanel(panel)) stack.show(panel)
243
- else return
243
+ else if (stack.findPanel(panel)) {
244
+ stack.show(panel, true)
245
+ }
246
+ }
244
247
 
245
- //event.preventDefault()
248
+ function navKey(event) {
249
+ var panel = event.currentTarget.closest('[data-stack="root"]').querySelector('[data-stack-index][aria-hidden="false"]')
250
+ if (!panel) { return }
251
+
252
+ if (Event.key.isPressed("left")) {
253
+ var back = panel.querySelector('[data-stack-nav].nav-back')
254
+ if (back) Event.fire(back, 'click')
255
+ }
256
+ if (Event.key.isPressed("right")) {
257
+ var next = panel.querySelector('[data-stack-nav].nav-next')
258
+ if (next) Event.fire(next, 'click')
259
+ }
246
260
  }
247
261
 
248
262
  function prevPanel (event) {
@@ -258,7 +272,10 @@ function setup () {
258
272
 
259
273
  // Localise clicks to a stack root
260
274
  // Future: consider expanding this to allow controls to live anywhere and point to a stack
261
- Event.on(document, 'click', '[data-stack="root"] [data-stack-nav]', navClick)
275
+ Event.ready(function() {
276
+ Event.on(document, 'click', '[data-stack="root"] [data-stack-nav]', navClick)
277
+ Event.on(document, 'keydown', '[data-stack-index]', navKey)
278
+ })
262
279
  }
263
280
 
264
281
  function getStack (search) {
@@ -24,18 +24,27 @@ function setCookie (node) {
24
24
  }
25
25
 
26
26
  function click (event) {
27
- var target = event.currentTarget,
28
- parent = target.parentElement,
29
- expanded = parent.getAttribute('aria-expanded')
27
+ toggleNode(event.currentTarget)
28
+ }
29
+
30
+ function toggleNode(target) {
31
+ parent = target.parentElement,
32
+ expanded = parent.getAttribute('aria-expanded')
30
33
 
31
34
  // Add a classname to indicate that it was manually triggered
32
35
  // This allows for animating interactions, but not other attribute changes
33
36
  parent.classList.add('triggered')
34
- parent.setAttribute('aria-expanded', expanded != 'true')
37
+ toggleExpansion(parent, expanded != 'true')
38
+ select(target)
35
39
 
36
40
  setCookie(parent)
37
41
  }
38
42
 
43
+ function toggleExpansion(el, expanded) {
44
+ el.setAttribute('aria-expanded', expanded)
45
+ setupItemTabIndex(el)
46
+ }
47
+
39
48
  // Sets tree nav state based off of cookies
40
49
  function restoreNav () {
41
50
  toolbox.each(document.querySelectorAll('[data-tree]'), function(tree) {
@@ -44,22 +53,117 @@ function restoreNav () {
44
53
  var data = cookie.get(key)
45
54
 
46
55
  Object.keys(data).forEach(function(node) {
47
- var nodeEl = tree.querySelector('[data-node='+node+']')
56
+ var nodeEl = tree.querySelector('[data-node='+node+']'),
57
+ expanded = data[node] == 'true'
48
58
  // Use cookies to expand.
49
- if (nodeEl && data[node] == 'true') nodeEl.setAttribute('aria-expanded', data[node])
59
+ if (nodeEl) {
60
+ nodeEl.setAttribute('aria-expanded', expanded)
61
+ toggleExpansion(nodeEl, expanded)
62
+ }
50
63
  })
51
64
  }
52
65
  })
53
66
  }
54
67
 
68
+ function navigateTree(event) {
69
+ var item = document.activeElement
70
+ if (!item) return
71
+
72
+ var tree = item.closest('[role="tree"]')
73
+ if (!tree) return
74
+
75
+ var trigger = item.matches('.tree-trigger')
76
+
77
+ if (trigger) {
78
+ var expanded = item.parentElement.getAttribute('aria-expanded') != 'false'
79
+
80
+ if (Event.key.isPressed('space')) {
81
+ toggleNode(item)
82
+ event.preventDefault()
83
+ }
84
+
85
+ if (Event.key.isPressed('right')) {
86
+ event.preventDefault()
87
+ if (expanded) return select(getNextItem(tree, item))
88
+ else return toggleNode(item)
89
+ }
90
+
91
+ if (Event.key.isPressed('left')) {
92
+ event.preventDefault()
93
+ if (expanded) return toggleNode(item)
94
+ else return select(getUpwardItem(tree, item))
95
+ }
96
+ }
97
+
98
+ if (Event.key.isPressed('down')) {
99
+ event.preventDefault()
100
+ select(getNextItem(tree, item))
101
+ }
102
+
103
+ if (Event.key.isPressed('left')) {
104
+ event.preventDefault()
105
+ select(getUpwardItem(tree, item))
106
+ }
107
+
108
+ else if (Event.key.isPressed('up')) {
109
+ event.preventDefault()
110
+ select(getPreviousItem(tree, item))
111
+ }
112
+ }
113
+
114
+ function select(el) {
115
+ if (!el) return
116
+ el.focus()
117
+ }
118
+
119
+ function getNextItem(tree, item) {
120
+ items = getSelectableItems(tree)
121
+ return items[ items.indexOf(item) + 1]
122
+ }
123
+
124
+ function getPreviousItem(tree, item) {
125
+ items = getSelectableItems(tree)
126
+ return items[ items.indexOf(item) - 1]
127
+ }
128
+
129
+ function getUpwardItem(tree, item) {
130
+ var upward = item.parentElement.closest('[aria-expanded]')
131
+ if (upward) return upward.querySelector('.tree-trigger')
132
+ }
133
+
134
+ function getSelectableItems(tree) {
135
+ return Array.prototype.filter.call(tree.querySelectorAll('[tabindex]'), function(el) {
136
+ return !el.closest('[aria-expanded="false"] [role="group"]')
137
+ })
138
+ }
139
+
140
+ // Remove hidden items from the tabindex
141
+ function setupItemTabIndex(tree) {
142
+ toolbox.each(tree.querySelectorAll('a'), function(el) {
143
+ if (el.closest('[aria-expanded="false"] [role="group"]')) {
144
+ el.setAttribute('tabindex', -1)
145
+ } else {
146
+ el.setAttribute('tabindex', 0)
147
+ }
148
+ })
149
+ }
150
+
151
+
55
152
  function setup() {
56
153
  Event.ready(function() {
57
154
 
58
155
  // The first child of a node is the trigger
59
- Event.on(document, 'click', '[aria-expanded] > *:first-child', click)
156
+ Event.on(document, 'click', '.tree-trigger', click)
157
+ Event.on(document, 'keydown', '[role="tree"]', navigateTree)
60
158
 
61
159
  // Set states according to cookies
62
- //restoreNav()
160
+ // restoreNav()
161
+ })
162
+
163
+ Event.change(function() {
164
+ toolbox.each(document.querySelectorAll('[role="tree"]'), function(el) {
165
+ setupItemTabIndex(el)
166
+ })
63
167
  })
64
168
  }
65
169