fleetio_spark 0.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/app/assets/javascripts/spark/_cookie.js +23 -0
- data/app/assets/javascripts/spark/_esvg.js +73 -0
- data/app/assets/javascripts/spark/_icons.js +19 -0
- data/app/assets/javascripts/spark/_modal.js +421 -0
- data/app/assets/javascripts/spark/_search.js +79 -0
- data/app/assets/javascripts/spark/_sidebar.js +13 -0
- data/app/assets/javascripts/spark/_stack.js +248 -0
- data/app/assets/javascripts/spark/_tree.js +68 -0
- data/app/assets/javascripts/spark/shims/_dataset.js +241 -0
- data/app/assets/javascripts/spark/spark.js +31 -0
- data/app/assets/stylesheets/spark/_icons.scss +15 -0
- data/app/assets/stylesheets/spark/_index.scss +5 -0
- data/app/assets/stylesheets/spark/components/_index.scss +6 -0
- data/app/assets/stylesheets/spark/components/_modal.scss +73 -0
- data/app/assets/stylesheets/spark/components/_nav-menu.scss +102 -0
- data/app/assets/stylesheets/spark/components/_sidebar.scss +280 -0
- data/app/assets/stylesheets/spark/components/_tooltip.scss +42 -0
- data/app/assets/stylesheets/spark/components/_tree-nav.scss +13 -0
- data/app/assets/stylesheets/spark/components/header/_app-admin-header.scss +82 -0
- data/app/assets/stylesheets/spark/components/header/_app-nav-header.scss +154 -0
- data/app/assets/stylesheets/spark/components/header/_index.scss +5 -0
- data/app/assets/stylesheets/spark/components/header/_search-results.scss +29 -0
- data/app/assets/stylesheets/spark/components/header/_search.scss +195 -0
- data/app/assets/stylesheets/spark/components/header/_trial-status.scss +43 -0
- data/app/assets/stylesheets/spark/core/_animations.scss +154 -0
- data/app/assets/stylesheets/spark/core/_base.scss +11 -0
- data/app/assets/stylesheets/spark/core/_colors.scss +94 -0
- data/app/assets/stylesheets/spark/core/_index.scss +7 -0
- data/app/assets/stylesheets/spark/core/_layout.scss +39 -0
- data/app/assets/stylesheets/spark/core/_mixins.scss +86 -0
- data/app/assets/stylesheets/spark/core/_text.scss +5 -0
- data/app/assets/stylesheets/spark/core/_vars.scss +76 -0
- data/app/assets/stylesheets/spark/form/_base.scss +124 -0
- data/app/assets/stylesheets/spark/form/_check-switch.scss +99 -0
- data/app/assets/stylesheets/spark/form/_index.scss +2 -0
- data/app/assets/stylesheets/spark/spark.scss +1 -0
- data/app/assets/svgs/spark/add.svg +3 -0
- data/app/assets/svgs/spark/admin-user.svg +5 -0
- data/app/assets/svgs/spark/chevron-down.svg +3 -0
- data/app/assets/svgs/spark/chevron-up.svg +3 -0
- data/app/assets/svgs/spark/close.svg +3 -0
- data/app/assets/svgs/spark/contact.svg +6 -0
- data/app/assets/svgs/spark/dashboard.svg +3 -0
- data/app/assets/svgs/spark/fuel.svg +3 -0
- data/app/assets/svgs/spark/inspection.svg +3 -0
- data/app/assets/svgs/spark/issue.svg +3 -0
- data/app/assets/svgs/spark/leaderboard.svg +5 -0
- data/app/assets/svgs/spark/logo.svg +1 -0
- data/app/assets/svgs/spark/map.svg +4 -0
- data/app/assets/svgs/spark/nav-menu.svg +5 -0
- data/app/assets/svgs/spark/part.svg +6 -0
- data/app/assets/svgs/spark/place.svg +5 -0
- data/app/assets/svgs/spark/question.svg +10 -0
- data/app/assets/svgs/spark/reminder.svg +3 -0
- data/app/assets/svgs/spark/report.svg +5 -0
- data/app/assets/svgs/spark/search.svg +3 -0
- data/app/assets/svgs/spark/service.svg +3 -0
- data/app/assets/svgs/spark/settings.svg +3 -0
- data/app/assets/svgs/spark/trip.svg +4 -0
- data/app/assets/svgs/spark/vehicle.svg +3 -0
- data/app/assets/svgs/spark/vendor.svg +4 -0
- data/app/helpers/spark/application_helper.rb +42 -0
- data/app/helpers/spark/icon_helper.rb +40 -0
- data/app/helpers/spark/input_helper.rb +163 -0
- data/app/helpers/spark/menu_helper.rb +113 -0
- data/app/helpers/spark/modal_helper.rb +52 -0
- data/app/helpers/spark/nav_menu_helper.rb +167 -0
- data/app/helpers/spark/tag_helper.rb +27 -0
- data/app/helpers/spark/trial_helper.rb +23 -0
- data/app/views/layouts/spark/application.html.slim +28 -0
- data/app/views/layouts/spark/blank.html.slim +9 -0
- data/app/views/layouts/spark/default.html.slim +13 -0
- data/config/autoprefixer.yml +4 -0
- data/config/esvg.yml +20 -0
- data/lib/fleetio_spark.rb +14 -0
- data/lib/fleetio_spark/helper.rb +163 -0
- data/lib/fleetio_spark/version.rb +3 -0
- data/public/spark-0.1.0.css +1442 -0
- data/public/spark-0.1.0.css.gz +0 -0
- data/public/spark-0.1.0.js +11927 -0
- data/public/spark-0.1.0.js.gz +0 -0
- metadata +211 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var toolbox = require( 'compose-toolbox' ),
|
|
2
|
+
Event = toolbox.event,
|
|
3
|
+
modal = require( './_modal' ),
|
|
4
|
+
stack = require( './_stack' )
|
|
5
|
+
|
|
6
|
+
// Focus on search when `/` key is pressed
|
|
7
|
+
Event.keyOn( '/', function(event){
|
|
8
|
+
var q = document.querySelector('[name=q]')
|
|
9
|
+
if ( q ) {
|
|
10
|
+
event.preventDefault()
|
|
11
|
+
q.focus()
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
// Reset search results panel when query is cleared
|
|
16
|
+
Event.ready( function() {
|
|
17
|
+
var searchStack = stack.get( '#search-stack' )
|
|
18
|
+
var q = document.querySelector('[name=q]')
|
|
19
|
+
var searchModal = modal.get( '#search-results' )
|
|
20
|
+
|
|
21
|
+
if ( !searchModal || !q ) return
|
|
22
|
+
|
|
23
|
+
function keyWatcher ( event ) {
|
|
24
|
+
var focusEl = document.activeElement
|
|
25
|
+
|
|
26
|
+
// If a letter, number, or backspace is pressed focus on search input
|
|
27
|
+
if ( focusEl != q && event.key.length === 1 || Event.key.isPressed("backspace") ) {
|
|
28
|
+
q.focus()
|
|
29
|
+
|
|
30
|
+
// Restore default search input behavior
|
|
31
|
+
// When foucsed, esc clears input
|
|
32
|
+
} else if ( focusEl == q && Event.key.isPressed( "esc" ) ) {
|
|
33
|
+
q.value = ''
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Scroll all navs back to top
|
|
38
|
+
function resetScroll () {
|
|
39
|
+
toolbox.each( searchStack.root.querySelectorAll( 'nav' ), function (nav) {
|
|
40
|
+
nav.scrollTop = 0
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
searchModal.on( 'open', function() {
|
|
45
|
+
Event.on( document, 'keydown', keyWatcher )
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// Reset stack when modal is closed and query is clear
|
|
49
|
+
searchModal.on( 'close', function() {
|
|
50
|
+
// Restore state of search panel
|
|
51
|
+
if ( document.querySelector( 'input[name=q]' ).value == '' ) {
|
|
52
|
+
searchStack.reset()
|
|
53
|
+
resetScroll()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
Event.off( document, 'keydown', keyWatcher )
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// Show first panel stack when query is cleared
|
|
60
|
+
Event.on( document, 'input', '[name=q]', Event.debounce( function ( event ) {
|
|
61
|
+
if ( event.currentTarget.value == '' ) {
|
|
62
|
+
searchStack.show( 0 )
|
|
63
|
+
resetScroll()
|
|
64
|
+
}
|
|
65
|
+
}, 50 ))
|
|
66
|
+
|
|
67
|
+
// Wire up clear search input behavior
|
|
68
|
+
Event.on( document, 'click', '.clear-search', function( event ) {
|
|
69
|
+
var button = event.currentTarget
|
|
70
|
+
event.preventDefault()
|
|
71
|
+
event.stopImmediatePropagation()
|
|
72
|
+
|
|
73
|
+
var searchInput = toolbox.getClosest( button, 'label' ).querySelector( '.input-container input' )
|
|
74
|
+
searchInput.value = ''
|
|
75
|
+
Event.fire( searchInput, 'input' )
|
|
76
|
+
|
|
77
|
+
searchInput.focus()
|
|
78
|
+
}, { useCapture: true })
|
|
79
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var toolbox = require( 'compose-toolbox' ),
|
|
2
|
+
cookie = require( './_cookie' ),
|
|
3
|
+
Event = toolbox.event
|
|
4
|
+
|
|
5
|
+
Event.ready( function() {
|
|
6
|
+
Event.on( document, 'click', '.sidebar-nav-toggle', function( event ) {
|
|
7
|
+
document.body.classList.toggle( 'hide-sidebar' )
|
|
8
|
+
|
|
9
|
+
var visible = !document.body.classList.contains( 'hide-sidebar' )
|
|
10
|
+
cookie.update( 'sidebar-nav', { sidebar: visible } )
|
|
11
|
+
})
|
|
12
|
+
if ( cookie.get( 'sidebar-nav' ).sidebar === false ) document.body.classList.add( 'hide-sidebar' )
|
|
13
|
+
})
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
var toolbox = require( 'compose-toolbox' ),
|
|
2
|
+
Event = toolbox.event,
|
|
3
|
+
Stacks = []
|
|
4
|
+
|
|
5
|
+
var Stack = {
|
|
6
|
+
new: function( root ) {
|
|
7
|
+
|
|
8
|
+
if ( !isElement( root ) ) root = document.querySelector( root )
|
|
9
|
+
|
|
10
|
+
// Don't add a new stack if no element found or if stack already exists
|
|
11
|
+
if ( !isElement( root ) || root.dataset.stackId ) return
|
|
12
|
+
|
|
13
|
+
// Set up stack by searching DOM node under it.
|
|
14
|
+
// The first child found will be set up as a default
|
|
15
|
+
// After that each child will be added as a stack push
|
|
16
|
+
|
|
17
|
+
var stack = {
|
|
18
|
+
root: root,
|
|
19
|
+
current: 0,
|
|
20
|
+
panels: [],
|
|
21
|
+
focus: [],
|
|
22
|
+
|
|
23
|
+
add: function ( panelEl, name ) {
|
|
24
|
+
panelEl.dataset.stackIndex = stack.panels.length
|
|
25
|
+
|
|
26
|
+
// Hide all panels but the first panel
|
|
27
|
+
if ( stack.panels.length == 0 ) {
|
|
28
|
+
showEl( panelEl )
|
|
29
|
+
} else {
|
|
30
|
+
hideEl( panelEl )
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
stack.panels.push( panelEl )
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// Reset stack to first panel
|
|
37
|
+
reset: function () {
|
|
38
|
+
|
|
39
|
+
// Already reset? We're done.
|
|
40
|
+
if ( stack.current == 0 ) return
|
|
41
|
+
|
|
42
|
+
// If hidden, manually reset all
|
|
43
|
+
if ( stack.root.offsetParent == null ) {
|
|
44
|
+
stack.focus = [] // Clear focus stack
|
|
45
|
+
|
|
46
|
+
// Hide and reset scroll on all panels
|
|
47
|
+
stack.panels.forEach( function( el ) {
|
|
48
|
+
el.scrollTop = 0
|
|
49
|
+
hideEl( el )
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// Show first panel
|
|
53
|
+
stack.current = 0
|
|
54
|
+
showEl( stack.panels[0] )
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// If not hidden, dismiss current panel and reset to first panel
|
|
58
|
+
else stack.show( 0 )
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// Show a specific panel, hiding all others
|
|
62
|
+
show: function ( name ) {
|
|
63
|
+
var panel = stack.findPanel( name )
|
|
64
|
+
|
|
65
|
+
// If a panel isn't the current panel
|
|
66
|
+
// dismiss it before going to the requested panel
|
|
67
|
+
if ( panel && panel != stack.currentPanel() ) {
|
|
68
|
+
|
|
69
|
+
// Dismiss the current panel and with the callback load in the next panel
|
|
70
|
+
return stack.dismiss( stack.direction( panel ), function() {
|
|
71
|
+
stack.enter( panel )
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
enter: function ( el ) {
|
|
78
|
+
var direction = stack.direction( el )
|
|
79
|
+
el.dataset.direction = direction
|
|
80
|
+
stack.current = Number( el.dataset.stackIndex )
|
|
81
|
+
|
|
82
|
+
Event.afterAnimation( el, function() {
|
|
83
|
+
el.dataset.direction = ''
|
|
84
|
+
el.classList.remove( 'enter' )
|
|
85
|
+
}, 50 )
|
|
86
|
+
|
|
87
|
+
el.classList.add( 'enter' )
|
|
88
|
+
showEl( el )
|
|
89
|
+
|
|
90
|
+
if ( direction == 'forward' ) {
|
|
91
|
+
// If the previous focused element was in the stack
|
|
92
|
+
//if ( toolbox.childOf( stack.lastFocus(), stack.root ) ) {
|
|
93
|
+
|
|
94
|
+
// focus on the first input
|
|
95
|
+
//var firstItem = el.querySelector( 'input:not([hidden]), textarea, select, a[tabindex]' )
|
|
96
|
+
//if ( firstItem ) firstItem.focus()
|
|
97
|
+
|
|
98
|
+
//}
|
|
99
|
+
|
|
100
|
+
// Focus on the previous focused element
|
|
101
|
+
} else if ( direction == 'reverse' && stack.focus.length > 0 ) {
|
|
102
|
+
stack.focus.pop().focus()
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
dismiss: function ( direction, callback ) {
|
|
107
|
+
|
|
108
|
+
var el = stack.currentPanel()
|
|
109
|
+
|
|
110
|
+
if ( direction == 'forward' )
|
|
111
|
+
stack.focus.push( document.activeElement )
|
|
112
|
+
|
|
113
|
+
el.classList.remove( 'enter' )
|
|
114
|
+
el.classList.add( 'exit' )
|
|
115
|
+
el.dataset.direction = direction
|
|
116
|
+
|
|
117
|
+
Event.afterAnimation( el, function() {
|
|
118
|
+
// Ensure panel is scrolled to top
|
|
119
|
+
if ( direction == 'reverse' ) el.scrollTop = 0
|
|
120
|
+
|
|
121
|
+
hideEl( el )
|
|
122
|
+
el.classList.remove( 'exit' )
|
|
123
|
+
el.dataset.direction = ''
|
|
124
|
+
|
|
125
|
+
if ( typeof callback === 'function' ) callback()
|
|
126
|
+
|
|
127
|
+
}, 50 )
|
|
128
|
+
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
lastFocus: function() {
|
|
132
|
+
return stack.focus[ stack.focus.length -1 ]
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// Find a panel by name or index
|
|
136
|
+
findPanel: function ( name ) {
|
|
137
|
+
if ( isElement( name ) )
|
|
138
|
+
return name
|
|
139
|
+
else
|
|
140
|
+
return root.querySelector( '[data-stack="'+name+'"], [data-stack-index="'+name+'"]' )
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Walk backwards in the stack, showing the panel previous to the current panel
|
|
144
|
+
back: function () {
|
|
145
|
+
stack.show( stack.panels[ stack.current - 1 ] )
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
// add aria-hidden=false to the first hidden element
|
|
149
|
+
next: function () {
|
|
150
|
+
stack.show( stack.panels[ stack.current + 1 ] )
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
direction: function( panel ) {
|
|
154
|
+
var index = stack.panelIndex( panel )
|
|
155
|
+
|
|
156
|
+
if ( index == stack.current ) return 'none'
|
|
157
|
+
else return ( stack.current < index ) ? 'forward' : 'reverse'
|
|
158
|
+
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
currentPanel: function ( name ) {
|
|
162
|
+
if ( name ) {
|
|
163
|
+
return stack.panels[ stack.current ] == stack.findPanel( name )
|
|
164
|
+
}
|
|
165
|
+
return stack.panels[ stack.current ]
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
panelIndex: function ( panel ) {
|
|
169
|
+
return Number( panel.dataset.stackIndex )
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Add a queryable stack id
|
|
174
|
+
root.dataset.stackId = Stacks.length
|
|
175
|
+
|
|
176
|
+
Stacks.push( stack )
|
|
177
|
+
toolbox.each( root.children, stack.add )
|
|
178
|
+
|
|
179
|
+
return stack
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function showEl ( el ) {
|
|
184
|
+
el.setAttribute( 'aria-hidden', false )
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function hideEl ( el ) {
|
|
188
|
+
el.setAttribute( 'aria-hidden', true )
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function isElement ( item ) {
|
|
192
|
+
return item.constructor.toString().search(/HTML.+Element/) > -1
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function navClick ( event ) {
|
|
196
|
+
var el = event.currentTarget
|
|
197
|
+
var panel = el.dataset.stackNav
|
|
198
|
+
var stack = getStack( toolbox.getClosest( el, '[data-stack="root"]' ) )
|
|
199
|
+
if ( !stack ) return
|
|
200
|
+
|
|
201
|
+
if ( panel == 'next' ) stack.next()
|
|
202
|
+
else if ( panel == 'back' ) stack.back()
|
|
203
|
+
else if ( stack.findPanel( panel ) ) stack.show( panel )
|
|
204
|
+
else return
|
|
205
|
+
|
|
206
|
+
//event.preventDefault()
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function prevPanel ( event ) {
|
|
210
|
+
var stack = getStack( toolbox.getClosest( event.target, '[data-stack="root"]' ) )
|
|
211
|
+
stack.back()
|
|
212
|
+
event.preventDefault()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function setup () {
|
|
216
|
+
Event.change( function() {
|
|
217
|
+
toolbox.each( document.querySelectorAll( '[data-stack="root"]'), Stack.new )
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
// Localise clicks to a stack root
|
|
221
|
+
// Future: consider expanding this to allow controls to live anywhere and point to a stack
|
|
222
|
+
Event.on( document, 'click', '[data-stack="root"] [data-stack-nav]', navClick )
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function getStack ( search ) {
|
|
226
|
+
|
|
227
|
+
if ( isElement( search ) ) {
|
|
228
|
+
if ( search.dataset.stackId ) return Stacks[ search.dataset.stackId ]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if ( typeof search === 'string' ) {
|
|
232
|
+
|
|
233
|
+
// Well, let's hope it's a DOM selector
|
|
234
|
+
var stack = document.querySelector( search )
|
|
235
|
+
|
|
236
|
+
// If it is woo hoo
|
|
237
|
+
if ( stack && stack.dataset.stackId ) {
|
|
238
|
+
return Stacks[ stack.dataset.stackId ]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
module.exports = {
|
|
244
|
+
new: Stack.new,
|
|
245
|
+
setup: setup,
|
|
246
|
+
get: getStack,
|
|
247
|
+
stacks: Stacks
|
|
248
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Purpose: Toggles expansion of tree nav and stores cookies to retain state
|
|
2
|
+
//
|
|
3
|
+
// Usage:
|
|
4
|
+
// - Trees must have a [data-tree='tree-key']
|
|
5
|
+
// - Nodes are named by [data-node='node-name']
|
|
6
|
+
//
|
|
7
|
+
// Cookies are stored as tree-key => { node-name: true }
|
|
8
|
+
// node boolean matches aria-expanded state
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
var toolbox = require( 'compose-toolbox' ),
|
|
12
|
+
cookie = require( './_cookie' ),
|
|
13
|
+
Event = toolbox.event
|
|
14
|
+
|
|
15
|
+
function setCookie ( node ) {
|
|
16
|
+
if ( node.dataset.node ) {
|
|
17
|
+
var tree = toolbox.getClosest( node, '[data-tree]' )
|
|
18
|
+
if ( tree ) {
|
|
19
|
+
data = {}
|
|
20
|
+
data[ node.dataset.node ] = node.getAttribute( 'aria-expanded' ) == 'true'
|
|
21
|
+
cookie.update( tree.dataset.tree, data )
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function click ( event ) {
|
|
27
|
+
var target = event.currentTarget,
|
|
28
|
+
parent = target.parentElement,
|
|
29
|
+
expanded = parent.getAttribute( 'aria-expanded' )
|
|
30
|
+
|
|
31
|
+
// Add a classname to indicate that it was manually triggered
|
|
32
|
+
// This allows for animating interactions, but not other attribute changes
|
|
33
|
+
parent.classList.add( 'triggered' )
|
|
34
|
+
parent.setAttribute( 'aria-expanded', expanded != 'true' )
|
|
35
|
+
|
|
36
|
+
setCookie( parent )
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Sets tree nav state based off of cookies
|
|
40
|
+
function restoreNav () {
|
|
41
|
+
toolbox.each( document.querySelectorAll( '[data-tree]' ), function( tree ) {
|
|
42
|
+
var key = tree.dataset.tree
|
|
43
|
+
if ( key ) {
|
|
44
|
+
var data = cookie.get( key )
|
|
45
|
+
|
|
46
|
+
Object.keys( data ).forEach( function( node ) {
|
|
47
|
+
var nodeEl = tree.querySelector( '[data-node='+node+']' )
|
|
48
|
+
// Use cookies to expand.
|
|
49
|
+
if ( nodeEl && data[node] == 'true' ) nodeEl.setAttribute( 'aria-expanded', data[node] )
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function setup() {
|
|
56
|
+
Event.ready( function() {
|
|
57
|
+
|
|
58
|
+
// The first child of a node is the trigger
|
|
59
|
+
Event.on( document, 'click', '[aria-expanded] > *:first-child', click )
|
|
60
|
+
|
|
61
|
+
// Set states according to cookies
|
|
62
|
+
//restoreNav()
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
setup: setup
|
|
68
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Add dataset support to elements
|
|
3
|
+
* No globals, no overriding prototype with non-standard methods,
|
|
4
|
+
* handles CamelCase properly, attempts to use standard
|
|
5
|
+
* Object.defineProperty() (and Function bind()) methods,
|
|
6
|
+
* falls back to native implementation when existing
|
|
7
|
+
* Inspired by http://code.eligrey.com/html5/dataset/
|
|
8
|
+
* (via https://github.com/adalgiso/html5-dataset/blob/master/html5-dataset.js )
|
|
9
|
+
* Depends on Function.bind and Object.defineProperty/Object.getOwnPropertyDescriptor (shims below)
|
|
10
|
+
* Licensed under the X11/MIT License
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// Inspired by https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
|
|
14
|
+
if (!Function.prototype.bind) {
|
|
15
|
+
Function.prototype.bind = function (oThis) {
|
|
16
|
+
'use strict';
|
|
17
|
+
if (typeof this !== "function") {
|
|
18
|
+
// closest thing possible to the ECMAScript 5 internal IsCallable function
|
|
19
|
+
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
var aArgs = Array.prototype.slice.call(arguments, 1),
|
|
23
|
+
fToBind = this,
|
|
24
|
+
FNOP = function () {},
|
|
25
|
+
fBound = function () {
|
|
26
|
+
return fToBind.apply(
|
|
27
|
+
this instanceof FNOP && oThis ? this : oThis,
|
|
28
|
+
aArgs.concat(Array.prototype.slice.call(arguments))
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
FNOP.prototype = this.prototype;
|
|
33
|
+
fBound.prototype = new FNOP();
|
|
34
|
+
|
|
35
|
+
return fBound;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
* Xccessors Standard: Cross-browser ECMAScript 5 accessors
|
|
41
|
+
* http://purl.eligrey.com/github/Xccessors
|
|
42
|
+
*
|
|
43
|
+
* 2010-06-21
|
|
44
|
+
*
|
|
45
|
+
* By Eli Grey, http://eligrey.com
|
|
46
|
+
*
|
|
47
|
+
* A shim that partially implements Object.defineProperty,
|
|
48
|
+
* Object.getOwnPropertyDescriptor, and Object.defineProperties in browsers that have
|
|
49
|
+
* legacy __(define|lookup)[GS]etter__ support.
|
|
50
|
+
*
|
|
51
|
+
* Licensed under the X11/MIT License
|
|
52
|
+
* See LICENSE.md
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
// Removed a few JSLint options as Notepad++ JSLint validator complaining and
|
|
56
|
+
// made comply with JSLint; also moved 'use strict' inside function
|
|
57
|
+
/*jslint white: true, undef: true, plusplus: true,
|
|
58
|
+
bitwise: true, regexp: true, newcap: true, maxlen: 90 */
|
|
59
|
+
|
|
60
|
+
/*! @source http://purl.eligrey.com/github/Xccessors/blob/master/xccessors-standard.js*/
|
|
61
|
+
|
|
62
|
+
(function () {
|
|
63
|
+
'use strict';
|
|
64
|
+
var ObjectProto = Object.prototype,
|
|
65
|
+
defineGetter = ObjectProto.__defineGetter__,
|
|
66
|
+
defineSetter = ObjectProto.__defineSetter__,
|
|
67
|
+
lookupGetter = ObjectProto.__lookupGetter__,
|
|
68
|
+
lookupSetter = ObjectProto.__lookupSetter__,
|
|
69
|
+
hasOwnProp = ObjectProto.hasOwnProperty;
|
|
70
|
+
|
|
71
|
+
if (defineGetter && defineSetter && lookupGetter && lookupSetter) {
|
|
72
|
+
|
|
73
|
+
if (!Object.defineProperty) {
|
|
74
|
+
Object.defineProperty = function (obj, prop, descriptor) {
|
|
75
|
+
if (arguments.length < 3) { // all arguments required
|
|
76
|
+
throw new TypeError("Arguments not optional");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
prop += ""; // convert prop to string
|
|
80
|
+
|
|
81
|
+
if (hasOwnProp.call(descriptor, "value")) {
|
|
82
|
+
if (!lookupGetter.call(obj, prop) && !lookupSetter.call(obj, prop)) {
|
|
83
|
+
// data property defined and no pre-existing accessors
|
|
84
|
+
obj[prop] = descriptor.value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if ((hasOwnProp.call(descriptor, "get") ||
|
|
88
|
+
hasOwnProp.call(descriptor, "set")))
|
|
89
|
+
{
|
|
90
|
+
// descriptor has a value prop but accessor already exists
|
|
91
|
+
throw new TypeError("Cannot specify an accessor and a value");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// can't switch off these features in ECMAScript 3
|
|
96
|
+
// so throw a TypeError if any are false
|
|
97
|
+
if (!(descriptor.writable && descriptor.enumerable &&
|
|
98
|
+
descriptor.configurable))
|
|
99
|
+
{
|
|
100
|
+
throw new TypeError(
|
|
101
|
+
"This implementation of Object.defineProperty does not support" +
|
|
102
|
+
" false for configurable, enumerable, or writable."
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (descriptor.get) {
|
|
107
|
+
defineGetter.call(obj, prop, descriptor.get);
|
|
108
|
+
}
|
|
109
|
+
if (descriptor.set) {
|
|
110
|
+
defineSetter.call(obj, prop, descriptor.set);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return obj;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!Object.getOwnPropertyDescriptor) {
|
|
118
|
+
Object.getOwnPropertyDescriptor = function (obj, prop) {
|
|
119
|
+
if (arguments.length < 2) { // all arguments required
|
|
120
|
+
throw new TypeError("Arguments not optional.");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
prop += ""; // convert prop to string
|
|
124
|
+
|
|
125
|
+
var descriptor = {
|
|
126
|
+
configurable: true,
|
|
127
|
+
enumerable : true,
|
|
128
|
+
writable : true
|
|
129
|
+
},
|
|
130
|
+
getter = lookupGetter.call(obj, prop),
|
|
131
|
+
setter = lookupSetter.call(obj, prop);
|
|
132
|
+
|
|
133
|
+
if (!hasOwnProp.call(obj, prop)) {
|
|
134
|
+
// property doesn't exist or is inherited
|
|
135
|
+
return descriptor;
|
|
136
|
+
}
|
|
137
|
+
if (!getter && !setter) { // not an accessor so return prop
|
|
138
|
+
descriptor.value = obj[prop];
|
|
139
|
+
return descriptor;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// there is an accessor, remove descriptor.writable;
|
|
143
|
+
// populate descriptor.get and descriptor.set (IE's behavior)
|
|
144
|
+
delete descriptor.writable;
|
|
145
|
+
descriptor.get = descriptor.set = undefined;
|
|
146
|
+
|
|
147
|
+
if (getter) {
|
|
148
|
+
descriptor.get = getter;
|
|
149
|
+
}
|
|
150
|
+
if (setter) {
|
|
151
|
+
descriptor.set = setter;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return descriptor;
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!Object.defineProperties) {
|
|
159
|
+
Object.defineProperties = function (obj, props) {
|
|
160
|
+
var prop;
|
|
161
|
+
for (prop in props) {
|
|
162
|
+
if (hasOwnProp.call(props, prop)) {
|
|
163
|
+
Object.defineProperty(obj, prop, props[prop]);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}());
|
|
170
|
+
|
|
171
|
+
// Begin dataset code
|
|
172
|
+
|
|
173
|
+
if (!document.documentElement.dataset &&
|
|
174
|
+
// FF is empty while IE gives empty object
|
|
175
|
+
(!Object.getOwnPropertyDescriptor(Element.prototype, 'dataset') ||
|
|
176
|
+
!Object.getOwnPropertyDescriptor(Element.prototype, 'dataset').get)
|
|
177
|
+
) {
|
|
178
|
+
var propDescriptor = {
|
|
179
|
+
enumerable: true,
|
|
180
|
+
get: function () {
|
|
181
|
+
'use strict';
|
|
182
|
+
var i,
|
|
183
|
+
that = this,
|
|
184
|
+
HTML5_DOMStringMap,
|
|
185
|
+
attrVal, attrName, propName,
|
|
186
|
+
attribute,
|
|
187
|
+
attributes = this.attributes,
|
|
188
|
+
attsLength = attributes.length,
|
|
189
|
+
toUpperCase = function (n0) {
|
|
190
|
+
return n0.charAt(1).toUpperCase();
|
|
191
|
+
},
|
|
192
|
+
getter = function () {
|
|
193
|
+
return this;
|
|
194
|
+
},
|
|
195
|
+
setter = function (attrName, value) {
|
|
196
|
+
return (typeof value !== 'undefined') ?
|
|
197
|
+
this.setAttribute(attrName, value) :
|
|
198
|
+
this.removeAttribute(attrName);
|
|
199
|
+
};
|
|
200
|
+
try { // Simulate DOMStringMap w/accessor support
|
|
201
|
+
// Test setting accessor on normal object
|
|
202
|
+
({}).__defineGetter__('test', function () {});
|
|
203
|
+
HTML5_DOMStringMap = {};
|
|
204
|
+
}
|
|
205
|
+
catch (e1) { // Use a DOM object for IE8
|
|
206
|
+
HTML5_DOMStringMap = document.createElement('div');
|
|
207
|
+
}
|
|
208
|
+
for (i = 0; i < attsLength; i++) {
|
|
209
|
+
attribute = attributes[i];
|
|
210
|
+
// Fix: This test really should allow any XML Name without
|
|
211
|
+
// colons (and non-uppercase for XHTML)
|
|
212
|
+
if (attribute && attribute.name &&
|
|
213
|
+
(/^data-\w[\w\-]*$/).test(attribute.name)) {
|
|
214
|
+
attrVal = attribute.value;
|
|
215
|
+
attrName = attribute.name;
|
|
216
|
+
// Change to CamelCase
|
|
217
|
+
propName = attrName.substr(5).replace(/-./g, toUpperCase);
|
|
218
|
+
try {
|
|
219
|
+
Object.defineProperty(HTML5_DOMStringMap, propName, {
|
|
220
|
+
enumerable: this.enumerable,
|
|
221
|
+
get: getter.bind(attrVal || ''),
|
|
222
|
+
set: setter.bind(that, attrName)
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
catch (e2) { // if accessors are not working
|
|
226
|
+
HTML5_DOMStringMap[propName] = attrVal;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return HTML5_DOMStringMap;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
try {
|
|
234
|
+
// FF enumerates over element's dataset, but not
|
|
235
|
+
// Element.prototype.dataset; IE9 iterates over both
|
|
236
|
+
Object.defineProperty(Element.prototype, 'dataset', propDescriptor);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
propDescriptor.enumerable = false; // IE8 does not allow setting to true
|
|
239
|
+
Object.defineProperty(Element.prototype, 'dataset', propDescriptor);
|
|
240
|
+
}
|
|
241
|
+
}
|