Files changed (20) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/spark/_stack.js +1 -0
  3. data/app/assets/javascripts/spark/components/nav/_tree.js +56 -30
  4. data/app/assets/stylesheets/spark/components/nav/tree/_group.scss +2 -2
  5. data/app/helpers/spark/menu_helper.rb +0 -1
  6. data/app/helpers/spark/nav_menu_helper.rb +1 -1
  7. data/lib/fleetio_spark/version.rb +1 -1
  8. data/public/code-0.2.27.js +0 -17648
  9. data/public/{code-0.2.28.js → code-0.2.29.js} +1 -1
  10. data/public/{code-0.2.28.js.gz → code-0.2.29.js.gz} +0 -0
  11. data/public/{code-0.2.28.js.map → code-0.2.29.js.map} +1 -1
  12. data/public/spark-0.2.27.js +0 -4591
  13. data/public/spark-0.2.28.js.gz +0 -0
  14. data/public/spark-0.2.28.js.map +0 -1
  15. data/public/{spark-0.2.28.css → spark-0.2.29.css} +1 -1
  16. data/public/{spark-0.2.28.css.gz → spark-0.2.29.css.gz} +0 -0
  17. data/public/{spark-0.2.28.js → spark-0.2.29.js} +2 -2
  18. data/public/spark-0.2.29.js.gz +0 -0
  19. data/public/spark-0.2.29.js.map +1 -0
  20. metadata +10 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
---
2
2
SHA256:
3
- metadata.gz: 6ae67716c57e2a7d14b83575192dbb948f5aee51a653a3ec07a79fa54ec1bd54
4
- data.tar.gz: b995d27caef6905dc0b8030d16097438ac1883118097f222d57f7a033d715c85
3
+ metadata.gz: 3640eeaf1e8c576f9ba70590de9dd65808b37b9222915ef949d3681cfc2df49b
4
+ data.tar.gz: b3845797d1b2a9dea6bebc9392a96e820cdb9d97473e49f428fa00c689f866ca
5
5
SHA512:
6
- metadata.gz: b593cd1e85c41b3ee0f4fa67154036c93419cc5e2c4d59fcdbbef22da2220c68738e665c94dd1b261b713b0186e6cd792d5f2970b5c57f3376464c356488cc2d
7
- data.tar.gz: 655489cb5b0716f7fb5debc574cb6a0efb816972dbc7e5a3b0b76621d08611c2284a9289fb505594b6200194ecb5d5b7657f1ce02ef3c5520ddc26130e6a1b6a
6
+ metadata.gz: 0dd3669666d16c9c9fd90c60c7ccd486ac6793645107d29d83ca8594aee1e8d687951fcf3b38348ea78ced5fd33b30d54fb8398c79cd49b68bc044f36f28ab6f
7
+ data.tar.gz: 1047c7d294fbe1b0e9c234cdef2bf6f6f3ef86111102eac9ef463de2cd1d00250578a9600374e5eb2d5beab22cd12316703c70a488b00de00df47b66deeecebe
data/app/assets/javascripts/spark/_stack.js CHANGED
@@ -246,6 +246,7 @@ function navClick(event) {
246
246
}
247
247
248
248
function navKey(event) {
249
+ // Find the active panel in the stack where the navigation event should be triggered.
249
250
var panel = event.currentTarget.closest('[data-stack="root"]').querySelector('[data-stack-index][aria-hidden="false"]')
250
251
if (!panel) { return }
251
252
data/app/assets/javascripts/spark/components/nav/_tree.js CHANGED
@@ -1,6 +1,6 @@
1
1
// Purpose: Toggles expansion of tree nav and stores cookies to retain state
2
2
//
3
- // Usage:
3
+ // For Cookies to be set:
4
4
// - Trees must have a [data-tree='tree-key']
5
5
// - Nodes are named by [data-node='node-name']
6
6
//
@@ -12,7 +12,7 @@ var toolbox = require('@spark-engine/toolbox'),
12
12
cookie = require('../../_cookie'),
13
13
Event = require('@spark-engine/event')
14
14
15
- function setCookie (node) {
15
+ function setCookie(node) {
16
16
if (node.dataset.node) {
17
17
var tree = node.closest('[data-tree]')
18
18
if (tree) {
@@ -23,30 +23,31 @@ function setCookie (node) {
23
23
}
24
24
}
25
25
26
- function click (event) {
26
+ function click(event) {
27
27
toggleNode(event.currentTarget)
28
28
}
29
29
30
+ // Expand or collapse the current tree node
30
31
function toggleNode(target) {
31
- parent = target.parentElement,
32
- expanded = parent.getAttribute('aria-expanded')
32
+ var parent = target.closest('[aria-expanded]'),
33
+ expanded = parent.getAttribute('aria-expanded') == 'true'
33
34
34
35
// Add a classname to indicate that it was manually triggered
35
36
// This allows for animating interactions, but not other attribute changes
36
37
parent.classList.add('triggered')
37
- toggleExpansion(parent, expanded != 'true')
38
+ toggleExpansion(parent, !expanded)
38
- select(target)
39
39
40
40
setCookie(parent)
41
41
}
42
42
43
+ // Set aria-expanded and toggle tabindex values based on expansion
43
44
function toggleExpansion(el, expanded) {
44
45
el.setAttribute('aria-expanded', expanded)
45
46
setupItemTabIndex(el)
46
47
}
47
48
48
49
// Sets tree nav state based off of cookies
49
- function restoreNav () {
50
+ function restoreNav() {
50
51
toolbox.each(document.querySelectorAll('[data-tree]'), function(tree) {
51
52
var key = tree.dataset.tree
52
53
if (key) {
@@ -65,90 +66,115 @@ function restoreNav () {
65
66
})
66
67
}
67
68
69
+ // Enables keyboard navigation of a nav tree
70
+ //
71
+ // `space` - toggles tree node triggers
72
+ // `right arrow` - opens nodes and navigates inward
73
+ // `left arrow` - closes nodes and navigates outward
74
+ // `up arrow` - moves to previous visible element
75
+ // `down arrow` - moves to next visible element
76
+ //
68
77
function navigateTree(event) {
69
78
var item = document.activeElement
70
79
if (!item) return
71
80
81
+ // Find the parent tree item
72
82
var tree = item.closest('[role="tree"]')
73
83
if (!tree) return
74
84
75
- var trigger = item.matches('.tree-trigger')
76
-
85
+ // Is the item a trigger which opens nodes?
86
+ if (item.matches('.tree-trigger')) {
77
- if (trigger) {
78
87
var expanded = item.parentElement.getAttribute('aria-expanded') != 'false'
79
88
89
+ // Space toggles node which trigger points to
80
90
if (Event.key.isPressed('space')) {
81
- toggleNode(item)
82
91
event.preventDefault()
92
+ return toggleNode(item)
83
93
}
84
94
95
+ // Expand or move to the first item in the node
85
96
if (Event.key.isPressed('right')) {
86
97
event.preventDefault()
87
- if (expanded) return select(getNextItem(tree, item))
98
+ if (expanded) return focus(getNextItem(tree, item))
88
99
else return toggleNode(item)
89
100
}
90
101
102
+ // Collapse or move up the parent node
91
103
if (Event.key.isPressed('left')) {
92
104
event.preventDefault()
93
105
if (expanded) return toggleNode(item)
94
- else return select(getUpwardItem(tree, item))
106
+ else return focus(getUpwardItem(tree, item))
95
107
}
96
108
}
97
109
110
+ // Move to next visible item in the tree
98
111
if (Event.key.isPressed('down')) {
99
112
event.preventDefault()
100
- select(getNextItem(tree, item))
113
+ focus(getNextItem(tree, item))
101
114
}
102
115
103
- if (Event.key.isPressed('left')) {
116
+ // Move to previous visible item in the tree
117
+ else if (Event.key.isPressed('up')) {
104
118
event.preventDefault()
105
- select(getUpwardItem(tree, item))
119
+ focus(getPreviousItem(tree, item))
106
120
}
107
121
108
- else if (Event.key.isPressed('up')) {
122
+ // Move outward in tree
123
+ else if (Event.key.isPressed('left')) {
109
124
event.preventDefault()
110
- select(getPreviousItem(tree, item))
125
+ focus(getUpwardItem(tree, item))
111
126
}
112
127
}
113
128
114
- function select(el) {
115
- if (!el) return
116
- el.focus()
129
+ // Focus on element (if able)
130
+ function focus(el) {
131
+ if (el) el.focus()
117
132
}
118
133
134
+ // Find next focusable item
119
135
function getNextItem(tree, item) {
120
- items = getSelectableItems(tree)
136
+ items = getFocusableItems(tree)
121
137
return items[ items.indexOf(item) + 1]
122
138
}
123
139
140
+ // Find previous focusable item
124
141
function getPreviousItem(tree, item) {
125
- items = getSelectableItems(tree)
142
+ items = getFocusableItems(tree)
126
143
return items[ items.indexOf(item) - 1]
127
144
}
128
145
146
+ // Walk up the tree to the tree trigger
129
147
function getUpwardItem(tree, item) {
130
148
var upward = item.parentElement.closest('[aria-expanded]')
131
149
if (upward) return upward.querySelector('.tree-trigger')
132
150
}
133
151
134
- function getSelectableItems(tree) {
135
- return Array.prototype.filter.call(tree.querySelectorAll('[tabindex]'), function(el) {
152
+ // Find all focusable items in a nav tree
153
+ function getFocusableItems(tree) {
154
+ // Filter out items in collapsed nodes
155
+ return Array.prototype.filter.call(tree.querySelectorAll('a, [tabindex]'), function(el) {
136
156
return !el.closest('[aria-expanded="false"] [role="group"]')
137
157
})
138
158
}
139
159
140
- // Remove hidden items from the tabindex
160
+ // Ensure hidden items are not focasable
141
161
function setupItemTabIndex(tree) {
142
- toolbox.each(tree.querySelectorAll('a'), function(el) {
162
+ toolbox.each(tree.querySelectorAll('a, [tabindex]'), function(el) {
143
163
if (el.closest('[aria-expanded="false"] [role="group"]')) {
144
164
el.setAttribute('tabindex', -1)
145
165
} else {
146
- el.setAttribute('tabindex', 0)
166
+ // Don't set a tabindex for anchor elements
167
+ // They already participate in tabindex and tabindex=0
168
+ // will change their click behavior
169
+ if (el.matches('a')) {
170
+ el.removeAttribute('tabindex')
171
+ } else {
172
+ el.setAttribute('tabindex', 0)
173
+ }
147
174
}
148
175
})
149
176
}
150
177
151
-
152
178
function setup() {
153
179
Event.ready(function() {
154
180
data/app/assets/stylesheets/spark/components/nav/tree/_group.scss CHANGED
@@ -1,6 +1,6 @@
1
1
[role=tree] {
2
- [role=group] {
3
- overflow: hidden;
2
+ [aria-expanded=false][role=group] {
3
+ overflow: hidden;
4
4
}
5
5
6
6
[role=treeitem][aria-expanded=false] > [role=group] {
data/app/helpers/spark/menu_helper.rb CHANGED
@@ -40,7 +40,6 @@ module Spark
40
40
options = add_class( options, config[:base_class] + "-item" )
41
41
42
42
options['role'] ||= 'menuitem'
43
- options['tabindex'] ||= 0
44
43
45
44
link_to( url, options, &content )
46
45
end
data/app/helpers/spark/nav_menu_helper.rb CHANGED
@@ -65,7 +65,7 @@ module Spark
65
65
options = add_class( options, classes )
66
66
67
67
content_tag( config[:item_tag], options ) do
68
- concat link_to( "#", class: config[:base_class] + '-item', tabindex: 0 ){
68
+ concat link_to("#", class: config[:base_class] + '-item'){
69
69
concat name.call
70
70
concat use_svg( 'chevron-down', class: 'expand-icon' )
71
71
}
data/lib/fleetio_spark/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
module FleetioSpark
2
- VERSION = "0.2.28"
2
+ VERSION = "0.2.29"
3
3
end
data/public/code-0.2.27.js DELETED
@@ -1,17648 +0,0 @@
1
- (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.spark = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2
- var Event = require('@spark-engine/event')
3
- var highlighter = require('@spark-engine/code-highlighter')
4
-
5
- require('codemirror/mode/htmlmixed/htmlmixed')
6
- require('codemirror/mode/slim/slim')
7
- require('codemirror/mode/javascript/javascript')
8
- require('codemirror/mode/css/css')
9
- require('codemirror/mode/sql/sql')
10
- require('codemirror/mode/php/php')
11
- require('codemirror/mode/ruby/ruby')
12
- require('codemirror/mode/shell/shell')
13
- require('codemirror/mode/go/go')
14
- require('codemirror/mode/python/python')
15
- require('codemirror/mode/yaml/yaml')
16
- require('codemirror/mode/clike/clike')
17
- require('codemirror/addon/runmode/runmode')
18
- require('codemirror/addon/edit/matchbrackets')
19
-
20
-
21
- Event.change(highlighter.highlight)
22
-
23
-
24
- },{"@spark-engine/code-highlighter":3,"@spark-engine/event":4,"codemirror/addon/edit/matchbrackets":20,"codemirror/addon/runmode/runmode":21,"codemirror/mode/clike/clike":23,"codemirror/mode/css/css":24,"codemirror/mode/go/go":25,"codemirror/mode/htmlmixed/htmlmixed":26,"codemirror/mode/javascript/javascript":27,"codemirror/mode/php/php":28,"codemirror/mode/python/python":29,"codemirror/mode/ruby/ruby":30,"codemirror/mode/shell/shell":31,"codemirror/mode/slim/slim":32,"codemirror/mode/sql/sql":33,"codemirror/mode/yaml/yaml":35}],2:[function(require,module,exports){
25
- /*!
26
- * Bean - copyright (c) Jacob Thornton 2011-2012
27
- * https://github.com/fat/bean
28
- * MIT license
29
- */
30
- (function (name, context, definition) {
31
- // Fallback for node
32
- if (typeof window === 'undefined') { return null; }
33
- if (typeof module != 'undefined' && module.exports) module.exports = definition(name, context)
34
- else if (typeof define == 'function' && define.amd) define(definition)
35
- else context[name] = definition(name, context)
36
- })('bean', this, function (name, context) {
37
- name = name || 'bean'
38
- context = context || this
39
-
40
- var win = window
41
- , old = context[name]
42
- , namespaceRegex = /[^\.]*(?=\..*)\.|.*/
43
- , nameRegex = /\..*/
44
- , addEvent = 'addEventListener'
45
- , removeEvent = 'removeEventListener'
46
- , doc = document || {}
47
- , root = doc.documentElement || {}
48
- , W3C_MODEL = root[addEvent]
49
- , eventSupport = W3C_MODEL ? addEvent : 'attachEvent'
50
- , ONE = {} // singleton for quick matching making add() do one()
51
-
52
- , slice = Array.prototype.slice
53
- , str2arr = function (s, d) { return s.split(d || ' ') }
54
- , isString = function (o) { return typeof o == 'string' }
55
- , isFunction = function (o) { return typeof o == 'function' }
56
- , isObject = function (o) { return typeof o == 'object' }
57
-
58
- // Try to build an options object. If any key in `maybeOptions`
59
- // matches a key in `defaults`, it will be copied into a clone
60
- // of `defaults`, thus overriding the default.
61
- , buildOptions = function (originalDefaults, maybeOptions) {
62
- var defaults = {}
63
-
64
- for (var key in originalDefaults) {
65
- if (originalDefaults.hasOwnProperty(key)) {
66
- defaults[key] = originalDefaults[key];
67
- }
68
- }
69
-
70
- if (!isObject(maybeOptions)) {
71
- return defaults;
72
- }
73
-
74
- for (key in defaults) {
75
- if (defaults.hasOwnProperty(key) && maybeOptions.hasOwnProperty(key)) {
76
- defaults[key] = maybeOptions[key]
77
- }
78
- }
79
-
80
- return defaults
81
- }
82
-
83
- // events that we consider to be 'native', anything not in this list will
84
- // be treated as a custom event
85
- , standardNativeEvents =
86
- 'click dblclick mouseup mousedown contextmenu ' + // mouse buttons
87
- 'mousewheel mousemultiwheel DOMMouseScroll ' + // mouse wheel
88
- 'mouseover mouseout mousemove selectstart selectend ' + // mouse movement
89
- 'keydown keypress keyup ' + // keyboard
90
- 'orientationchange ' + // mobile
91
- 'focus blur change reset select submit ' + // form elements
92
- 'load unload beforeunload resize move DOMContentLoaded ' + // window
93
- 'readystatechange message ' + // window
94
- 'error abort scroll ' // misc
95
- // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event
96
- // that doesn't actually exist, so make sure we only do these on newer browsers
97
- , w3cNativeEvents =
98
- 'show ' + // mouse buttons
99
- 'input invalid ' + // form elements
100
- 'touchstart touchmove touchend touchcancel ' + // touch
101
- 'gesturestart gesturechange gestureend ' + // gesture
102
- 'textinput ' + // TextEvent
103
- 'readystatechange pageshow pagehide popstate ' + // window
104
- 'hashchange offline online ' + // window
105
- 'afterprint beforeprint ' + // printing
106
- 'dragstart dragenter dragover dragleave drag drop dragend ' + // dnd
107
- 'loadstart progress suspend emptied stalled loadmetadata ' + // media
108
- 'loadeddata canplay canplaythrough playing waiting seeking ' + // media
109
- 'seeked ended durationchange timeupdate play pause ratechange ' + // media
110
- 'volumechange cuechange ' + // media
111
- 'checking noupdate downloading cached updateready obsolete ' // appcache
112
-
113
- // convert to a hash for quick lookups
114
- , nativeEvents = (function (hash, events, i) {
115
- for (i = 0; i < events.length; i++) events[i] && (hash[events[i]] = 1)
116
- return hash
117
- }({}, str2arr(standardNativeEvents + (W3C_MODEL ? w3cNativeEvents : ''))))
118
-
119
- // custom events are events that we *fake*, they are not provided natively but
120
- // we can use native events to generate them
121
- , customEvents = (function () {
122
- var isAncestor = 'compareDocumentPosition' in root
123
- ? function (element, container) {
124
- return container.compareDocumentPosition && (container.compareDocumentPosition(element) & 16) === 16
125
- }
126
- : 'contains' in root
127
- ? function (element, container) {
128
- container = container.nodeType === 9 || container === window ? root : container
129
- return container !== element && container.contains(element)
130
- }
131
- : function (element, container) {
132
- while (element = element.parentNode) if (element === container) return 1
133
- return 0
134
- }
135
- , check = function (event) {
136
- var related = event.relatedTarget
137
- return !related
138
- ? related == null
139
- : (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString())
140
- && !isAncestor(related, this))
141
- }
142
-
143
- return {
144
- mouseenter: { base: 'mouseover', condition: check }
145
- , mouseleave: { base: 'mouseout', condition: check }
146
- , mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' }
147
- }
148
- }())
149
-
150
- // we provide a consistent Event object across browsers by taking the actual DOM
151
- // event object and generating a new one from its properties.
152
- , Event = (function () {
153
- // a whitelist of properties (for different event types) tells us what to check for and copy
154
- var commonProps = str2arr('altKey attrChange attrName bubbles cancelable ctrlKey currentTarget ' +
155
- 'detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey ' +
156
- 'srcElement target timeStamp type view which propertyName path')
157
- , mouseProps = commonProps.concat(str2arr('button buttons clientX clientY dataTransfer ' +
158
- 'fromElement offsetX offsetY pageX pageY screenX screenY toElement movementX movementY region'))
159
- , mouseWheelProps = mouseProps.concat(str2arr('wheelDelta wheelDeltaX wheelDeltaY wheelDeltaZ ' +
160
- 'axis')) // 'axis' is FF specific
161
- , keyProps = commonProps.concat(str2arr('char charCode key keyCode keyIdentifier ' +
162
- 'keyLocation location isComposing code'))
163
- , textProps = commonProps.concat(str2arr('data'))
164
- , touchProps = commonProps.concat(str2arr('touches targetTouches changedTouches scale rotation'))
165
- , messageProps = commonProps.concat(str2arr('data origin source'))
166
- , stateProps = commonProps.concat(str2arr('state'))
167
- , overOutRegex = /over|out/
168
- // some event types need special handling and some need special properties, do that all here
169
- , typeFixers = [
170
- { // key events
171
- reg: /key/i
172
- , fix: function (event, newEvent) {
173
- newEvent.keyCode = event.keyCode || event.which
174
- return keyProps
175
- }
176
- }
177
- , { // mouse events
178
- reg: /click|mouse(?!(.*wheel|scroll))|menu|drag|drop/i
179
- , fix: function (event, newEvent, type) {
180
- newEvent.rightClick = event.which === 3 || event.button === 2
181
- newEvent.pos = { x: 0, y: 0 }
182
- if (event.pageX || event.pageY) {
183
- newEvent.clientX = event.pageX
184
- newEvent.clientY = event.pageY
185
- } else if (event.clientX || event.clientY) {
186
- newEvent.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft
187
- newEvent.clientY = event.clientY + doc.body.scrollTop + root.scrollTop
188
- }
189
- if (overOutRegex.test(type)) {
190
- newEvent.relatedTarget = event.relatedTarget
191
- || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']
192
- }
193
- return mouseProps
194
- }
195
- }
196
- , { // mouse wheel events
197
- reg: /mouse.*(wheel|scroll)/i
198
- , fix: function () { return mouseWheelProps }
199
- }
200
- , { // TextEvent
201
- reg: /^text/i
202
- , fix: function () { return textProps }
203
- }
204
- , { // touch and gesture events
205
- reg: /^touch|^gesture/i
206
- , fix: function () { return touchProps }
207
- }
208
- , { // message events
209
- reg: /^message#x2F;i
210
- , fix: function () { return messageProps }
211
- }
212
- , { // popstate events
213
- reg: /^popstate#x2F;i
214
- , fix: function () { return stateProps }
215
- }
216
- , { // everything else
217
- reg: /.*/
218
- , fix: function () { return commonProps }
219
- }
220
- ]
221
- , typeFixerMap = {} // used to map event types to fixer functions (above), a basic cache mechanism
222
-
223
- , Event = function (event, element, isNative) {
224
- if (!arguments.length) return
225
- event = event || ((element.ownerDocument || element.document || element).parentWindow || win).event
226
- this.originalEvent = event
227
- this.isNative = isNative
228
- this.isBean = true
229
-
230
- if (!event) return
231
-
232
- var type = event.type
233
- , target = event.target || event.srcElement
234
- , i, l, p, props, fixer
235
-
236
- this.target = target && target.nodeType === 3 ? target.parentNode : target
237
-
238
- if (isNative) { // we only need basic augmentation on custom events, the rest expensive & pointless
239
- fixer = typeFixerMap[type]
240
- if (!fixer) { // haven't encountered this event type before, map a fixer function for it
241
- for (i = 0, l = typeFixers.length; i < l; i++) {
242
- if (typeFixers[i].reg.test(type)) { // guaranteed to match at least one, last is .*
243
- typeFixerMap[type] = fixer = typeFixers[i].fix
244
- break
245
- }
246
- }
247
- }
248
-
249
- props = fixer(event, this, type)
250
- for (i = props.length; i--;) {
251
- if (!((p = props[i]) in this) && p in event) this[p] = event[p]
252
- }
253
- }
254
- }
255
-
256
- // preventDefault() and stopPropagation() are a consistent interface to those functions
257
- // on the DOM, stop() is an alias for both of them together
258
- Event.prototype.preventDefault = function () {
259
- if (this.originalEvent.preventDefault) this.originalEvent.preventDefault()
260
- else this.originalEvent.returnValue = false
261
- }
262
- Event.prototype.stopPropagation = function () {
263
- if (this.originalEvent.stopPropagation) this.originalEvent.stopPropagation()
264
- else this.originalEvent.cancelBubble = true
265
- }
266
- Event.prototype.stop = function () {
267
- this.preventDefault()
268
- this.stopPropagation()
269
- this.stopped = true
270
- }
271
- // stopImmediatePropagation() has to be handled internally because we manage the event list for
272
- // each element
273
- // note that originalElement may be a Bean#Event object in some situations
274
- Event.prototype.stopImmediatePropagation = function () {
275
- if (this.originalEvent.stopImmediatePropagation) this.originalEvent.stopImmediatePropagation()
276
- this.isImmediatePropagationStopped = function () { return true }
277
- }
278
- Event.prototype.isImmediatePropagationStopped = function () {
279
- return this.originalEvent.isImmediatePropagationStopped && this.originalEvent.isImmediatePropagationStopped()
280
- }
281
- Event.prototype.clone = function (currentTarget) {
282
- //TODO: this is ripe for optimisation, new events are *expensive*
283
- // improving this will speed up delegated events
284
- var ne = new Event(this, this.element, this.isNative)
285
- ne.currentTarget = currentTarget
286
- return ne
287
- }
288
-
289
- return Event
290
- }())
291
-
292
- // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both
293
- , targetElement = function (element, isNative) {
294
- return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element
295
- }
296
-
297
- /**
298
- * Bean maintains an internal registry for event listeners. We don't touch elements, objects
299
- * or functions to identify them, instead we store everything in the registry.
300
- * Each event listener has a RegEntry object, we have one 'registry' for the whole instance.
301
- */
302
- , RegEntry = (function () {
303
- // each handler is wrapped so we can handle delegation and custom events
304
- var wrappedHandler = function (element, fn, condition, args) {
305
- var call = function (event, eargs) {
306
- return fn.apply(element, args ? slice.call(eargs, event ? 0 : 1).concat(args) : eargs)
307
- }
308
- , findTarget = function (event, eventElement) {
309
- return fn.__beanDel ? fn.__beanDel.ft(event.target, element) : eventElement
310
- }
311
- , handler = condition
312
- ? function (event) {
313
- var target = findTarget(event, this) // deleated event
314
- if (condition.apply(target, arguments)) {
315
- if (event) event.currentTarget = target
316
- return call(event, arguments)
317
- }
318
- }
319
- : function (event) {
320
- if (fn.__beanDel) event = event.clone(findTarget(event)) // delegated event, fix the fix
321
- return call(event, arguments)
322
- }
323
- handler.__beanDel = fn.__beanDel
324
- return handler
325
- }
326
-
327
- , RegEntry = function (element, type, handler, original, namespaces, args, root) {
328
- var customType = customEvents[type]
329
- , isNative
330
-
331
- if (type == 'unload') {
332
- // self clean-up
333
- handler = once(removeListener, element, type, handler, original)
334
- }
335
-
336
- if (customType) {
337
- if (customType.condition) {
338
- handler = wrappedHandler(element, handler, customType.condition, args)
339
- }
340
- type = customType.base || type
341
- }
342
-
343
- this.isNative = isNative = nativeEvents[type] && !!element[eventSupport]
344
- this.customType = !W3C_MODEL && !isNative && type
345
- this.element = element
346
- this.type = type
347
- this.original = original
348
- this.namespaces = namespaces
349
- this.eventType = W3C_MODEL || isNative ? type : 'propertychange'
350
- this.target = targetElement(element, isNative)
351
- this[eventSupport] = !!this.target[eventSupport]
352
- this.root = root
353
- this.handler = wrappedHandler(element, handler, null, args)
354
- }
355
-
356
- // given a list of namespaces, is our entry in any of them?
357
- RegEntry.prototype.inNamespaces = function (checkNamespaces) {
358
- var i, j, c = 0
359
- if (!checkNamespaces) return true
360
- if (!this.namespaces) return false
361
- for (i = checkNamespaces.length; i--;) {
362
- for (j = this.namespaces.length; j--;) {
363
- if (checkNamespaces[i] == this.namespaces[j]) c++
364
- }
365
- }
366
- return checkNamespaces.length === c
367
- }
368
-
369
- // match by element, original fn (opt), handler fn (opt)
370
- RegEntry.prototype.matches = function (checkElement, checkOriginal, checkHandler) {
371
- return this.element === checkElement &&
372
- (!checkOriginal || this.original === checkOriginal) &&
373
- (!checkHandler || this.handler === checkHandler)
374
- }
375
-
376
- return RegEntry
377
- }())
378
-
379
- , registry = (function () {
380
- // our map stores arrays by event type, just because it's better than storing
381
- // everything in a single array.
382
- // uses '#x27; as a prefix for the keys for safety and 'r' as a special prefix for
383
- // rootListeners so we can look them up fast
384
- var map = {}
385
-
386
- // generic functional search of our registry for matching listeners,
387
- // `fn` returns false to break out of the loop
388
- , forAll = function (element, type, original, handler, root, fn) {
389
- var pfx = root ? 'r' : '#x27;
390
- if (!type || type == '*') {
391
- // search the whole registry
392
- for (var t in map) {
393
- if (t.charAt(0) == pfx) {
394
- forAll(element, t.substr(1), original, handler, root, fn)
395
- }
396
- }
397
- } else {
398
- var i = 0, l, list = map[pfx + type], all = element == '*'
399
- if (!list) return
400
- for (l = list.length; i < l; i++) {
401
- if ((all || list[i].matches(element, original, handler)) && !fn(list[i], list, i, type)) return
402
- }
403
- }
404
- }
405
-
406
- , has = function (element, type, original, root) {
407
- // we're not using forAll here simply because it's a bit slower and this
408
- // needs to be fast
409
- var i, list = map[(root ? 'r' : '#x27;) + type]
410
- if (list) {
411
- for (i = list.length; i--;) {
412
- if (!list[i].root && list[i].matches(element, original, null)) return true
413
- }
414
- }
415
- return false
416
- }
417
-
418
- , get = function (element, type, original, root) {
419
- var entries = []
420
- forAll(element, type, original, null, root, function (entry) {
421
- return entries.push(entry)
422
- })
423
- return entries
424
- }
425
-
426
- , put = function (entry) {
427
- var has = !entry.root && !this.has(entry.element, entry.type, null, false)
428
- , key = (entry.root ? 'r' : '#x27;) + entry.type
429
- ;(map[key] || (map[key] = [])).push(entry)
430
- return has
431
- }
432
-
433
- , del = function (entry) {
434
- forAll(entry.element, entry.type, null, entry.handler, entry.root, function (entry, list, i) {
435
- list.splice(i, 1)
436
- entry.removed = true
437
- if (list.length === 0) delete map[(entry.root ? 'r' : '#x27;) + entry.type]
438
- return false
439
- })
440
- }
441
-
442
- // dump all entries, used for onunload
443
- , entries = function () {
444
- var t, entries = []
445
- for (t in map) {
446
- if (t.charAt(0) == '#x27;) entries = entries.concat(map[t])
447
- }
448
- return entries
449
- }
450
-
451
- return { has: has, get: get, put: put, del: del, entries: entries }
452
- }())
453
-
454
- // we need a selector engine for delegated events, use querySelectorAll if it exists
455
- // but for older browsers we need Qwery, Sizzle or similar
456
- , selectorEngine
457
- , setSelectorEngine = function (e) {
458
- if (!arguments.length) {
459
- selectorEngine = doc.querySelectorAll
460
- ? function (s, r) {
461
- return r.querySelectorAll(s)
462
- }
463
- : function () {
464
- throw new Error('Bean: No selector engine installed') // eeek
465
- }
466
- } else {
467
- selectorEngine = e
468
- }
469
- }
470
-
471
- // we attach this listener to each DOM event that we need to listen to, only once
472
- // per event type per DOM element
473
- , rootListener = function (event, type) {
474
- if (!W3C_MODEL && type && event && event.propertyName != '_on' + type) return
475
-
476
- var listeners = registry.get(this, type || event.type, null, false)
477
- , l = listeners.length
478
- , i = 0
479
-
480
- event = new Event(event, this, true)
481
- if (type) event.type = type
482
-
483
- // iterate through all handlers registered for this type, calling them unless they have
484
- // been removed by a previous handler or stopImmediatePropagation() has been called
485
- for (; i < l && !event.isImmediatePropagationStopped(); i++) {
486
- if (!listeners[i].removed) listeners[i].handler.call(this, event)
487
- }
488
- }
489
-
490
- // add and remove listeners to DOM elements
491
- , listener = W3C_MODEL
492
- ? function (element, type, add, custom, useCapture) {
493
- // new browsers
494
- element[add ? addEvent : removeEvent](type, rootListener, useCapture)
495
- }
496
- : function (element, type, add, custom /*, useCapture */) {
497
- // IE8 and below, use attachEvent/detachEvent and we have to piggy-back propertychange events
498
- // to simulate event bubbling etc.
499
- var entry
500
- if (add) {
501
- registry.put(entry = new RegEntry(
502
- element
503
- , custom || type
504
- , function (event) { // handler
505
- rootListener.call(element, event, custom)
506
- }
507
- , rootListener
508
- , null
509
- , null
510
- , true // is root
511
- ))
512
- if (custom && element['_on' + custom] == null) element['_on' + custom] = 0
513
- entry.target.attachEvent('on' + entry.eventType, entry.handler)
514
- } else {
515
- entry = registry.get(element, custom || type, rootListener, true)[0]
516
- if (entry) {
517
- entry.target.detachEvent('on' + entry.eventType, entry.handler)
518
- registry.del(entry)
519
- }
520
- }
521
- }
522
-
523
- , once = function (rm, element, type, fn, originalFn) {
524
- // wrap the handler in a handler that does a remove as well
525
- return function () {
526
- fn.apply(this, arguments)
527
- rm(element, type, originalFn)
528
- }
529
- }
530
-
531
- , removeListener = function (element, orgType, handler, namespaces, useCapture) {
532
- var type = orgType && orgType.replace(nameRegex, '')
533
- , handlers = registry.get(element, type, null, false)
534
- , removed = {}
535
- , i, l
536
-
537
- for (i = 0, l = handlers.length; i < l; i++) {
538
- if ((!handler || handlers[i].original === handler) && handlers[i].inNamespaces(namespaces)) {
539
- // TODO: this is problematic, we have a registry.get() and registry.del() that
540
- // both do registry searches so we waste cycles doing this. Needs to be rolled into
541
- // a single registry.forAll(fn) that removes while finding, but the catch is that
542
- // we'll be splicing the arrays that we're iterating over. Needs extra tests to
543
- // make sure we don't screw it up. @rvagg
544
- registry.del(handlers[i])
545
- if (!removed[handlers[i].eventType] && handlers[i][eventSupport])
546
- removed[handlers[i].eventType] = { t: handlers[i].eventType, c: handlers[i].type }
547
- }
548
- }
549
- // check each type/element for removed listeners and remove the rootListener where it's no longer needed
550
- for (i in removed) {
551
- if (!registry.has(element, removed[i].t, null, false)) {
552
- // last listener of this type, remove the rootListener
553
- listener(element, removed[i].t, false, removed[i].c, useCapture)
554
- }
555
- }
556
- }
557
-
558
- // set up a delegate helper using the given selector, wrap the handler function
559
- , delegate = function (selector, fn) {
560
- //TODO: findTarget (therefore $) is called twice, once for match and once for
561
- // setting e.currentTarget, fix this so it's only needed once
562
- var findTarget = function (target, root) {
563
- var i, array = isString(selector) ? selectorEngine(selector, root) : selector
564
- for (; target && target !== root; target = target.parentNode) {
565
- for (i = array.length; i--;) {
566
- if (array[i] === target) return target
567
- }
568
- }
569
- }
570
- , handler = function (e) {
571
- var match = findTarget(e.target, this)
572
- if (match) fn.apply(match, arguments)
573
- }
574
-
575
- // __beanDel isn't pleasant but it's a private function, not exposed outside of Bean
576
- handler.__beanDel = {
577
- ft : findTarget // attach it here for customEvents to use too
578
- , selector : selector
579
- }
580
- return handler
581
- }
582
-
583
- , fireListener = W3C_MODEL ? function (isNative, type, element) {
584
- // modern browsers, do a proper dispatchEvent()
585
- var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents')
586
- evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1)
587
- element.dispatchEvent(evt)
588
- } : function (isNative, type, element) {
589
- // old browser use onpropertychange, just increment a custom property to trigger the event
590
- element = targetElement(element, isNative)
591
- isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++
592
- }
593
-
594
- /**
595
- * Public API: off(), on(), add(), (remove()), one(), fire(), clone()
596
- */
597
-
598
- /**
599
- * off(element[, eventType(s)[, handler ], options])
600
- */
601
- , off = function (element, typeSpec, fn) {
602
- var isTypeStr = isString(typeSpec),
603
- defaultOpts = {
604
- useCapture: false
605
- }
606
- , opts = buildOptions(defaultOpts, arguments[arguments.length - 1])
607
- , k, type, namespaces, i
608
-
609
- if (isTypeStr && typeSpec.indexOf(' ') > 0) {
610
- // off(el, 't1 t2 t3', fn) or off(el, 't1 t2 t3')
611
- typeSpec = str2arr(typeSpec)
612
- for (i = typeSpec.length; i--;)
613
- off(element, typeSpec[i], fn)
614
- return element
615
- }
616
-
617
- type = isTypeStr && typeSpec.replace(nameRegex, '')
618
- if (type && customEvents[type]) type = customEvents[type].base
619
-
620
- if (!typeSpec || isTypeStr) {
621
- // off(el) or off(el, t1.ns) or off(el, .ns) or off(el, .ns1.ns2.ns3)
622
- if (namespaces = isTypeStr && typeSpec.replace(namespaceRegex, '')) namespaces = str2arr(namespaces, '.')
623
- removeListener(element, type, fn, namespaces, opts.useCapture)
624
- } else if (isFunction(typeSpec)) {
625
- // off(el, fn)
626
- removeListener(element, null, typeSpec, null, opts.useCapture)
627
- } else {
628
- // off(el, { t1: fn1, t2, fn2 })
629
- for (k in typeSpec) {
630
- if (typeSpec.hasOwnProperty(k)) off(element, k, typeSpec[k])
631
- }
632
- }
633
-
634
- return element
635
- }
636
-
637
- /**
638
- * on(element, eventType(s)[, selector], handler[, args ], [options])
639
- */
640
- , on = function(element, events, selector, fn) {
641
- var defaultOpts = {
642
- useCapture: false
643
- },
644
- originalFn, type, types, i, args, entry, first, opts
645
-
646
- //TODO: the undefined check means you can't pass an 'args' argument, fix this perhaps?
647
- if (selector === undefined && typeof events == 'object') {
648
- //TODO: this can't handle delegated events
649
- for (type in events) {
650
- if (events.hasOwnProperty(type)) {
651
- on.call(this, element, type, events[type])
652
- }
653
- }
654
- return
655
- }
656
-
657
- if (!isFunction(selector)) {
658
- // delegated event
659
- originalFn = fn
660
- args = slice.call(arguments, 4)
661
- fn = delegate(selector, originalFn, selectorEngine)
662
- } else {
663
- args = slice.call(arguments, 3)
664
- fn = originalFn = selector
665
- }
666
-
667
- opts = buildOptions(defaultOpts, args[args.length - 1])
668
- types = str2arr(events)
669
-
670
- // special case for one(), wrap in a self-removing handler
671
- if (this === ONE) {
672
- fn = once(off, element, events, fn, originalFn)
673
- }
674
-
675
- for (i = types.length; i--;) {
676
- // add new handler to the registry and check if it's the first for this element/type
677
- first = registry.put(entry = new RegEntry(
678
- element
679
- , types[i].replace(nameRegex, '') // event type
680
- , fn
681
- , originalFn
682
- , str2arr(types[i].replace(namespaceRegex, ''), '.') // namespaces
683
- , args
684
- , false // not root
685
- ))
686
- if (entry[eventSupport] && first) {
687
- // first event of this type on this element, add root listener
688
- listener(element, entry.eventType, true, entry.customType, opts.useCapture)
689
- }
690
- }
691
-
692
- return element
693
- }
694
-
695
- /**
696
- * add(element[, selector], eventType(s), handler[, args ])
697
- *
698
- * Deprecated: kept (for now) for backward-compatibility
699
- */
700
- , add = function (element, events, fn, delfn, options) {
701
- return on.apply(
702
- null
703
- , !isString(fn)
704
- ? slice.call(arguments)
705
- : [ element, fn, events, delfn ].concat(arguments.length > 3 ? slice.call(arguments, 4) : [])
706
- )
707
- }
708
-
709
- /**
710
- * one(element, eventType(s)[, selector], handler[, args ])
711
- */
712
- , one = function () {
713
- return on.apply(ONE, arguments)
714
- }
715
-
716
- /**
717
- * fire(element, eventType(s)[, args ])
718
- *
719
- * The optional 'args' argument must be an array, if no 'args' argument is provided
720
- * then we can use the browser's DOM event system, otherwise we trigger handlers manually
721
- */
722
- , fire = function (element, type, args) {
723
- var types = str2arr(type)
724
- , i, j, l, names, handlers
725
-
726
- for (i = types.length; i--;) {
727
- type = types[i].replace(nameRegex, '')
728
- if (names = types[i].replace(namespaceRegex, '')) names = str2arr(names, '.')
729
- if (!names && !args && element[eventSupport]) {
730
- fireListener(nativeEvents[type], type, element)
731
- } else {
732
- // non-native event, either because of a namespace, arguments or a non DOM element
733
- // iterate over all listeners and manually 'fire'
734
- handlers = registry.get(element, type, null, false)
735
- args = [false].concat(args)
736
- for (j = 0, l = handlers.length; j < l; j++) {
737
- if (handlers[j].inNamespaces(names)) {
738
- handlers[j].handler.apply(element, args)
739
- }
740
- }
741
- }
742
- }
743
- return element
744
- }
745
-
746
- /**
747
- * clone(dstElement, srcElement[, eventType ])
748
- *
749
- * TODO: perhaps for consistency we should allow the same flexibility in type specifiers?
750
- */
751
- , clone = function (element, from, type) {
752
- var handlers = registry.get(from, type, null, false)
753
- , l = handlers.length
754
- , i = 0
755
- , args, beanDel
756
-
757
- for (; i < l; i++) {
758
- if (handlers[i].original) {
759
- args = [ element, handlers[i].type ]
760
- if (beanDel = handlers[i].handler.__beanDel) args.push(beanDel.selector)
761
- args.push(handlers[i].original)
762
- on.apply(null, args)
763
- }
764
- }
765
- return element
766
- }
767
-
768
- , bean = {
769
- 'on' : on
770
- , 'add' : add
771
- , 'one' : one
772
- , 'off' : off
773
- , 'remove' : off
774
- , 'clone' : clone
775
- , 'fire' : fire
776
- , 'Event' : Event
777
- , 'setSelectorEngine' : setSelectorEngine
778
- , 'noConflict' : function () {
779
- context[name] = old
780
- return this
781
- }
782
- }
783
-
784
- // for IE, clean up on unload to avoid leaks
785
- if (win.attachEvent) {
786
- var cleanup = function () {
787
- var i, entries = registry.entries()
788
- for (i in entries) {
789
- if (entries[i].type && entries[i].type !== 'unload') off(entries[i].element, entries[i].type)
790
- }
791
- win.detachEvent('onunload', cleanup)
792
- win.CollectGarbage && win.CollectGarbage()
793
- }
794
- win.attachEvent('onunload', cleanup)
795
- }
796
-
797
- // initialize selector engine to internal default (qSA or throw Error)
798
- setSelectorEngine()
799
-
800
- return bean
801
- });
802
-
803
- },{}],3:[function(require,module,exports){
804
- var CodeMirror = require('codemirror')
805
- require( 'codemirror/addon/runmode/runmode' )
806
-
807
- // Use CodeMirror to render static code higlighting
808
- //
809
- // Example:
810
- //
811
- // <pre data-lang="ruby">
812
- // puts @awesome if true
813
- // </pre>
814
- //
815
-
816
-
817
- var aliases = {
818
- 'html' : 'text/html',
819
- 'slim' : 'text/slim',
820
- 'js' : 'text/javascript',
821
- 'json' : 'application/json',
822
- 'sass' : 'text/x-sass',
823
- 'scss' : 'text/x-scss',
824
- 'bash' : 'text/x-sh',
825
- 'sh' : 'text/x-sh'
826
- }
827
-
828
- // Process code through CodeMirror which injects highlighted code into element
829
- function process(code, lang, el) {
830
- if (!lang) return
831
- var options = {'json': lang == 'json'}
832
- CodeMirror.runMode(code, getAlias(lang), el, options)
833
- }
834
-
835
- function highlight(el) {
836
- var lang = el.dataset.lang || 'plain'
837
- el.classList.add('highlighted', 'lang-'+lang)
838
- process(el.textContent.trim(), lang, el)
839
- el.innerHTML = "<code class='highlighted-code static-code cm-s-default'>" + el.innerHTML + "</code>"
840
- }
841
-
842
- function highlightAll(selector) {
843
- selector = selector || '[data-lang]:not(.highlighted)'
844
- Array.prototype.forEach.call(document.querySelectorAll(selector), highlight)
845
- }
846
-
847
- function aliasLang(newAliases) {
848
- for (var key in newAliases) {
849
- aliases[key] = newAliases[key]
850
- }
851
- }
852
-
853
- function getAlias(lang) {
854
- return(aliases[lang] || lang)
855
- }
856
-
857
- module.exports = {
858
- aliasLang: aliasLang,
859
- highlight: highlight,
860
- highlightAll: highlightAll
861
- }
862
-
863
- },{"codemirror":22,"codemirror/addon/runmode/runmode":21}],4:[function(require,module,exports){
864
- require( './lib/shims/custom-event' )
865
-
866
- var bean = require( '@spark-engine/bean' ),
867
- key = require( 'keymaster' ),
868
- afterAnimation = require( './lib/after-animation' ),
869
- page = require( './lib/page' ),
870
- tap = require( './lib/tap-events' ),
871
- debounce = require( './lib/debounce' ),
872
- throttle = require( './lib/throttle' ),
873
- delay = require( './lib/delay' ),
874
- repeat = require( './lib/repeat' ),
875
- bubbleFormEvents = require( './lib/bubble-form-events' ),
876
- submit = require( './lib/submit' ),
877
- scroll = require( './lib/scroll' ),
878
- resize = require( './lib/resize' ),
879
- callbackManager = require( './lib/callback-manager' ),
880
- eventManager = require( './lib/event-manager' ),
881
- media = require( './lib/media' ),
882
-
883
- slice = Array.prototype.slice,
884
- formBubbling = false,
885
- watchAnimation = true
886
-
887
- module.exports = {
888
-
889
- // DOM events
890
- on: bean.on,
891
- off: bean.off,
892
- one: bean.one,
893
- fire: bean.fire,
894
- clone: bean.clone,
895
- ready: page.ready,
896
- change: page.change,
897
- afterAnimation: afterAnimation,
898
- watchAnimation: watchAnimation,
899
-
900
- // Media query events
901
- media: media,
902
-
903
- // Keyboard events
904
- key: key,
905
- keyOn: key,
906
- keyOff: key.unbind,
907
- keyOne: keyOne,
908
-
909
- // Timing utilities
910
- debounce: debounce,
911
- throttle: throttle,
912
- delay: delay,
913
- repeat: repeat,
914
-
915
- // Optimized Event Managers
916
- scroll: scroll,
917
- resize: resize,
918
- eventManager: eventManager,
919
-
920
- callbackManager: callbackManager,
921
- callback: callbackManager.callback,
922
-
923
- // Bubbling fix
924
- bubbleFormEvents: bubbleFormEvents,
925
-
926
- submit: submit
927
- }
928
-
929
- page.ready( function() {
930
- if ( watchAnimation ) afterAnimation.watch()
931
- })
932
-
933
- // Add support for unbinding a key event after it is called
934
- //
935
- function keyOne ( keys, scope, fn ) {
936
-
937
- if ( typeof scope == 'function' ) {
938
- fn = scope
939
- scope = 'all'
940
- }
941
-
942
- key( keys, scope, function( event ) {
943
- key.unbind( keys, scope )
944
- fn( event )
945
- })
946
- }
947
-
948
- },{"./lib/after-animation":5,"./lib/bubble-form-events":6,"./lib/callback-manager":7,"./lib/debounce":8,"./lib/delay":9,"./lib/event-manager":10,"./lib/media":11,"./lib/page":12,"./lib/repeat":13,"./lib/resize":14,"./lib/scroll":15,"./lib/shims/custom-event":16,"./lib/submit":17,"./lib/tap-events":18,"./lib/throttle":19,"@spark-engine/bean":2,"keymaster":36}],5:[function(require,module,exports){
949
- var Event = require( '@spark-engine/bean' ),
950
- delay = require( './delay' )
951
-
952
- function animationDuration( el ) {
953
- return window.getComputedStyle( el ).getPropertyValue( 'animation-duration' )
954
- }
955
-
956
- // Watches all document animation and adds data attributes to elements when they begin
957
- // This enables animationEnd to watch animations which haven't begun
958
- function watchAnimation() {
959
- Event.on( document, 'animationstart', function( event ) {
960
- event.target.dataset.isAnimating = true
961
- })
962
- Event.on( document, 'animationend', function( event ) {
963
- event.target.removeAttribute('data-is-animating')
964
- })
965
- }
966
-
967
- // This requires trackElementAnimation to be enabled
968
- function afterAnimation( el, callback, startTimeout ) {
969
- // Animation has already begun
970
- if ( el.dataset.isAnimating || el.querySelector( '[data-is-animating]' ) ) {
971
-
972
- // Watch for end
973
- Event.one( el, 'animationend', callback )
974
-
975
- // Animation has not yet begun so…
976
- } else {
977
-
978
- // startTimeout is meant to ensure that a callback is fired even if
979
- // an animation event, or in the case that an animation event is never triggered
980
- // this might happen if a user wants to fire a callack after an element animates
981
- // or fire the callback anyway if the element doesn't have an animation.
982
- if ( startTimeout ) {
983
-
984
- // Set a default timeout (allowing startTimeout == true or a specified number of milisecons)
985
- var time = ((typeof startTimeout == "number") ? startTimeout : 32) // 32ms: ~ two frames of animation grace period
986
-
987
- var delayedEvent = delay( function() {
988
- // Stop watching for animation to start
989
- // Why? - If the animation starts later, the callback will fire twice
990
- Event.off( el, 'animationstart', watchEndEvent )
991
- callback()
992
- }, time )
993
- }
994
-
995
- // Next:
996
- // Register a function to attach callback to animationEnd event
997
- function watchEndEvent () {
998
- if ( startTimeout ) delayedEvent.stop() // cancel delayed fire
999
- Event.one( el, 'animationend', callback ) // watch for animation to finish
1000
- }
1001
-
1002
- // Finally, when the animation does start, watch for its end
1003
- Event.one( el, 'animationstart', watchEndEvent )
1004
- }
1005
- }
1006
-
1007
- afterAnimation.watch = watchAnimation
1008
-
1009
- module.exports = afterAnimation
1010
-
1011
- },{"./delay":9,"@spark-engine/bean":2}],6:[function(require,module,exports){
1012
- var Event = require( '@spark-engine/bean' ),
1013
- page = require( './page' ),
1014
- formEls;
1015
-
1016
- var formBubbling = false
1017
-
1018
- var fireBubble = function ( event ) {
1019
- if ( event.detail && event.detail.triggered ) { return false }
1020
-
1021
- var ev = new CustomEvent( event.type, { bubbles: true, cancelable: true, detail: { triggered: true } } )
1022
-
1023
- // Stop only 'submit' events. Stopping blur or foucs events seems to break FireFox input interactions.
1024
- if ( event.type == 'submit' ) event.stopImmediatePropagation()
1025
-
1026
- event.target.dispatchEvent( ev )
1027
-
1028
- // Prevent default on original event if custom event is prevented
1029
- if ( ev.defaultPrevented ) event.preventDefault()
1030
- }
1031
-
1032
- // Simplify setting the event type based on the element
1033
- var eventType = function ( el ) {
1034
- return ( el.tagName == 'FORM' ) ? 'submit' : 'focus blur'
1035
- }
1036
-
1037
- // Add event listeners
1038
- var bubbleOn = function ( el ) {
1039
- Event.on( el, eventType( el ), fireBubble )
1040
- }
1041
-
1042
- // Remove event listeners
1043
- var bubbleOff = function ( el ) {
1044
- Event.off( el, eventType( el ), fireBubble )
1045
- }
1046
-
1047
- // Add/Remove event listeners
1048
- var bubbleFormEvents = function () {
1049
- if ( formBubbling ) { return }
1050
- page.change( function() {
1051
-
1052
- // Remove listeners from previous page
1053
- if ( formEls ) Array.prototype.forEach.call( formEls, bubbleOff )
1054
-
1055
- // Add new listeners to this page
1056
- formEls = document.querySelectorAll( 'form, input' )
1057
-
1058
- Array.prototype.forEach.call( formEls, bubbleOn )
1059
- })
1060
-
1061
- var formBubbling = true
1062
- }
1063
-
1064
- module.exports = bubbleFormEvents
1065
-
1066
- },{"./page":12,"@spark-engine/bean":2}],7:[function(require,module,exports){
1067
- var Manager = {
1068
- new: function() {
1069
- var manager = {
1070
-
1071
- callbacks: [],
1072
-
1073
- add: function( fn ) {
1074
- var cb = Manager.callback.new( fn )
1075
- manager.callbacks.push( cb )
1076
- return cb
1077
- },
1078
-
1079
- stop: function() {
1080
- manager.callbacks.forEach( function( cb ) { cb.stop() } )
1081
- },
1082
-
1083
- start: function() {
1084
- manager.callbacks.forEach( function( cb ) { cb.start() } )
1085
- },
1086
-
1087
- toggle: function( bool ) {
1088
- manager.callbacks.forEach( function( cb ) { cb.toggle( bool ) } )
1089
- },
1090
-
1091
- remove: function() {
1092
- manager.callbacks = []
1093
- },
1094
-
1095
- fire: function() {
1096
- var args = Array.prototype.slice.call( arguments )
1097
- manager.callbacks.forEach( function( fn ) { fn.apply( this, args ) } )
1098
- }
1099
- }
1100
-
1101
- return manager
1102
- },
1103
-
1104
- callback: {
1105
- new: function( fn ) {
1106
- var cb = function() {
1107
- if ( cb.enabled ) { fn.apply( fn, arguments ) }
1108
- }
1109
-
1110
- cb.stop = function() { cb.enabled = false }
1111
- cb.start = function() { cb.enabled = true }
1112
- cb.toggle = function( bool ) {
1113
- cb.enabled = ( 0 in arguments ) ? bool : !cb.enabled
1114
- }
1115
- cb.enabled = true
1116
-
1117
- return cb
1118
- }
1119
- }
1120
- }
1121
-
1122
- module.exports = Manager
1123
-
1124
- },{}],8:[function(require,module,exports){
1125
- var now = function() {
1126
- return Date.now()
1127
- }
1128
-
1129
- var pickFunction = function() {
1130
- var found
1131
- Array.prototype.forEach.call( arguments, function( candidate ) {
1132
- if ( typeof( candidate ) == 'function' && !found ) { found = candidate }
1133
- })
1134
-
1135
- return found
1136
- }
1137
-
1138
- var debounce = function( fn, wait, options ) {
1139
-
1140
- // Allow options passed as the first argument
1141
- if ( typeof( fn ) == 'object' ) { options = fn }
1142
-
1143
- // Options won't be null
1144
- else { options = options || {} }
1145
-
1146
- wait = options.wait || wait || 0
1147
-
1148
- var max = options.max || false,
1149
- leading = ( ( 'leading' in options ) ? options.leading : false ),
1150
- trailing = ( ( 'trailing' in options ) ? options.trailing : true ),
1151
-
1152
- // Grab functions from options or default to first argument
1153
- leadingFn = pickFunction( options.leading, options.trailing, options.callback, fn ),
1154
- trailingFn = pickFunction( options.trailing, options.leading, options.callback, fn ),
1155
-
1156
- // State tracking vars
1157
- args, // Track arguments passed to debounced callback
1158
- queued = false, // Has a callback been added to the animation loop?
1159
- handle = {}, // Object for tracking functions and callbacks
1160
- lastCalled = 0, // Keep a timer for debouncing
1161
- lastInvoked = 0, // Keep a timer for max
1162
- leadingBlocked = false; // Track leading, throttling subsequent leading calls
1163
-
1164
- // Queue the function with requestAnimationFrame
1165
- var invoke = function( callType ) {
1166
-
1167
- lastCalled = now()
1168
- lastInvoked = now()
1169
- queued = false
1170
- leadingBlocked = true
1171
-
1172
- if ( callType === 'leading' ) {
1173
- leadingFn.apply( leadingFn, args ) }
1174
- else {
1175
- trailingFn.apply( trailingFn, args ) }
1176
-
1177
- }
1178
-
1179
- // Load the loop into the animation queue
1180
- var addToQueue = function () {
1181
-
1182
- if ( !queued ) {
1183
- queued = true
1184
- handle.value = requestAnimationFrame( loop ) // Add to browser's animation queue
1185
- }
1186
-
1187
- }
1188
-
1189
- // Remove from animation queue and reset debounce
1190
- var removeFromQueue = function() {
1191
-
1192
- if ( "value" in handle ) {
1193
- cancelAnimationFrame( handle.value )
1194
- queued = false
1195
- lastCalled = 0
1196
- lastInvoked = 0
1197
- leadingBlocked = false
1198
- }
1199
-
1200
- }
1201
-
1202
- // prevent infinite debouncing ( if options.max is set )
1203
- var maxPassed = function() {
1204
- return ( max && now() - lastInvoked >= max )
1205
- }
1206
-
1207
- var waitReached = function() {
1208
- return ( now() - lastCalled ) >= wait
1209
- }
1210
-
1211
- // This gets loaded into the animation queue and determines whether to ivoke the debounced function
1212
- var loop = function () {
1213
-
1214
- // Loop was executed so it's no longer in the animation queue
1215
- queued = false
1216
-
1217
- if ( leading && !leadingBlocked ) {
1218
- invoke( 'leading' )
1219
- }
1220
-
1221
- // If function has been called to frequently to execute
1222
- else if ( maxPassed() ) {
1223
-
1224
- if ( leading ) { invoke( 'leading' ) }
1225
- else { invoke( 'trailing' ) }
1226
-
1227
- }
1228
-
1229
- // If function hasn't been called since last wait
1230
- else if ( waitReached() ) {
1231
-
1232
- // If trailing it's safe to invoke
1233
- if ( trailing ) { invoke( 'trailing' ) }
1234
-
1235
- // If leading, it's safe to remove block
1236
- if ( leading ) { leadingBlocked = false }
1237
-
1238
- } else {
1239
- addToQueue()
1240
- }
1241
-
1242
- }
1243
-
1244
- // A wrapper function for queueing up function calls
1245
- //
1246
- var debounced = function() {
1247
- lastCalled = now()
1248
- args = arguments
1249
- addToQueue()
1250
- }
1251
-
1252
- debounced.stop = removeFromQueue
1253
-
1254
- return debounced
1255
- }
1256
-
1257
- module.exports = debounce
1258
-
1259
- },{}],9:[function(require,module,exports){
1260
- var now = function() {
1261
- return Date.now()
1262
- }
1263
-
1264
- var delay = function ( fn, wait ) {
1265
-
1266
- var argsStart = ( wait != null ) ? 2 : 1;
1267
- var handle = {}
1268
-
1269
- handle.args = Array.prototype.slice.call( arguments, argsStart )
1270
- handle.wait = wait || 0
1271
- handle.start = now()
1272
-
1273
- handle.stop = function () {
1274
- if ( "value" in handle ) {
1275
- cancelAnimationFrame( handle.value );
1276
- }
1277
- }
1278
-
1279
- handle.loop = function () {
1280
-
1281
- // If wait limit has been reached
1282
- if ( now() - handle.start >= handle.wait ) {
1283
- fn.apply( fn, handle.args )
1284
-
1285
- // If repeat is set and is not 0
1286
- if ( !!handle.repeat ) {
1287
- handle.repeat = handle.repeat - 1
1288
- handle.start = now()
1289
- queueDelay( handle )
1290
- } else if ( handle.repeat === 0 && handle.complete ) {
1291
- handle.complete()
1292
- }
1293
-
1294
- } else {
1295
- queueDelay( handle )
1296
- }
1297
-
1298
- }
1299
-
1300
-
1301
- return queueDelay( handle )
1302
- }
1303
-
1304
- var queueDelay = function ( handle ) {
1305
- handle.value = requestAnimationFrame( handle.loop )
1306
- return handle
1307
- }
1308
-
1309
- module.exports = delay
1310
-
1311
- },{}],10:[function(require,module,exports){
1312
- var Event = require( '@spark-engine/bean' )
1313
- var Page = require( './page' )
1314
- var callbackManager = require( './callback-manager' )
1315
- var throttle = require( './throttle' )
1316
- var debounce = require( './debounce' )
1317
-
1318
- var eventManager = {
1319
- new: function( name, options ) {
1320
-
1321
- options = options || {}
1322
- var target = options.target || window
1323
- var delay = options.delay || 150
1324
- var optimize = options.throttle || true
1325
-
1326
- // Create a new callback manager
1327
- var manager = {
1328
- run: callbackManager.new(),
1329
- start: callbackManager.new(),
1330
- end: callbackManager.new()
1331
- }
1332
-
1333
- var running = manager.run.fire
1334
-
1335
- // run callbacks when event happens (at paint-ready frames)
1336
- if (optimize) running = throttle( running )
1337
-
1338
- // fire callbacks when event starts (at paint-ready frames)
1339
- var started = debounce({ leading: manager.start.fire, trailing: false, wait: delay })
1340
-
1341
- // fire callbacks when event starts (at paint-ready frames)
1342
- var ended = debounce( manager.end.fire, delay )
1343
-
1344
- // Public API
1345
- var run = function ( fn ) { return manager.run.add( fn ) }
1346
- run.start = function ( fn ) { return manager.start.add( fn ) }
1347
- run.end = function ( fn ) { return manager.end.add( fn ) }
1348
-
1349
- Page.ready(function(){
1350
- if ( typeof target === "string" ) target = document.querySelector(target)
1351
-
1352
- if ( target ) {
1353
- // These functions use throttle and debounce to only trigger on optimzied intervals and at start and end
1354
- Event.on( target, name, function(event) {
1355
- started(event)
1356
- running(event)
1357
- ended(event)
1358
- })
1359
- }
1360
- })
1361
-
1362
- return run
1363
- }
1364
- }
1365
-
1366
- module.exports = eventManager
1367
-
1368
- },{"./callback-manager":7,"./debounce":8,"./page":12,"./throttle":19,"@spark-engine/bean":2}],11:[function(require,module,exports){
1369
- // This simplifies common uses for window.matchMedia
1370
- // namely, adding listeners for width and height queries
1371
-
1372
- function parseQuery( query, dimension ) {
1373
- var result = {}
1374
-
1375
- if ( typeof( query ) === 'string' ) { return query }
1376
-
1377
- result.min = size( query.min, 'min-' + dimension )
1378
- result.max = size( query.max, 'max-' + dimension )
1379
-
1380
- if ( result.min && result.max )
1381
- result.query = result.min + ' and ' + result.max
1382
-
1383
- return result.query || result.min || result.max
1384
- }
1385
-
1386
- function size( num, limit ) {
1387
- return ( num ) ? '('+limit+': ' + toPx( num ) + ')' : null
1388
- }
1389
-
1390
- function toPx( width ) {
1391
- if ( typeof( width ) === 'number' ) { return width + 'px'}
1392
- return width
1393
- }
1394
-
1395
- var media = {
1396
-
1397
- width: function( query, fn ) {
1398
- return media.listen( parseQuery( query, 'width' ), fn )
1399
- },
1400
-
1401
- minWidth: function( size, fn ) { return media.width( { min: size }, fn ) },
1402
- maxWidth: function( size, fn ) { return media.width( { max: size }, fn ) },
1403
-
1404
- height: function( query, fn ) {
1405
- return media.listen( parseQuery( query, 'height' ), fn )
1406
- },
1407
-
1408
- minHeight: function( size, fn ) { return media.height( { min: size }, fn ) },
1409
- maxHeight: function( size, fn ) { return media.height( { max: size }, fn ) },
1410
-
1411
- listen: function( query, fn ) {
1412
- var match = window.matchMedia( query )
1413
-
1414
- if ( fn ) {
1415
- fn( match )
1416
- match.addListener( fn )
1417
- }
1418
-
1419
- return match
1420
- }
1421
-
1422
- }
1423
-
1424
-
1425
- module.exports = media
1426
-
1427
- },{}],12:[function(require,module,exports){
1428
- var Event = require( '@spark-engine/bean' )
1429
- var callbackManager = require( './callback-manager' )
1430
-
1431
- // Create a new page event manager
1432
- var manager = {
1433
- ready: callbackManager.new(),
1434
- change: callbackManager.new(),
1435
- readyAlready: false,
1436
- changed: false,
1437
- }
1438
-
1439
- manager.ready.add( function(){
1440
- manager.readyAlready = true
1441
- })
1442
-
1443
- manager.ready.add( function(){
1444
- if ( !window.Turbolinks && !manager.changed ) {
1445
- manager.changed = true
1446
- manager.change.fire()
1447
- }
1448
- })
1449
-
1450
- var ready = function ( fn ) {
1451
- if ( manager.readyAlready ) { fn() }
1452
- return manager.ready.add( fn ) }
1453
-
1454
- var change = function( fn ) {
1455
- if ( manager.changed ) { fn() }
1456
- return manager.change.add( fn ) }
1457
-
1458
- // Make it easy to trigger ready callbacks
1459
- ready.fire = function () {
1460
- manager.ready.fire()
1461
- // Be sure ready can only be fired once
1462
- manager.ready.stop() }
1463
-
1464
- // Make it easy to trigger change callbacks
1465
- change.fire = function () {
1466
- manager.change.fire() }
1467
-
1468
- Event.on( document, 'DOMContentLoaded', ready.fire )
1469
- Event.on( document, 'page:change turbolinks:load', change.fire ) // Support custom and rails turbolinks page load events
1470
-
1471
- module.exports = {
1472
- ready: ready,
1473
- change: change
1474
- }
1475
-
1476
- },{"./callback-manager":7,"@spark-engine/bean":2}],13:[function(require,module,exports){
1477
- var delay = require( './delay' )
1478
-
1479
- var repeat = function( fn, wait, limit ) {
1480
-
1481
- var argsStart = 1,
1482
- handle = delay ( fn, wait );
1483
-
1484
- if ( limit != null ) { argsStart = 3 }
1485
- else if ( wait != null ) { argsStart = 2 }
1486
-
1487
- // Enable repeat ( -1 will repeat forever )
1488
- handle.repeat = limit || -1
1489
- handle.args = Array.prototype.slice.call( arguments, argsStart )
1490
- handle.stop = handle.cancel
1491
-
1492
- return handle
1493
- }
1494
-
1495
- module.exports = repeat
1496
-
1497
- },{"./delay":9}],14:[function(require,module,exports){
1498
- var manager = require( './event-manager' )
1499
- var resize = manager.new( 'resize' )
1500
-
1501
- // Pause animations during resizing for better performance
1502
- resize.disableAnimation = function() {
1503
- var style = '<style id="fullstop">.no-animation *, .no-animation *:after, .no-animation *:before {\
1504
- transition: none !important; animation: none !important\
1505
- }</style>'
1506
-
1507
- // Inject style for easy classname manipulation
1508
- if ( !document.querySelector('style#fullstop') ) {
1509
- document.head.insertAdjacentHTML('beforeend', style)
1510
- }
1511
-
1512
- resize.start( function() { document.body.classList.add( 'no-animation' ) } )
1513
- resize.end( function() { document.body.classList.remove( 'no-animation' ) } )
1514
- }
1515
-
1516
- module.exports = resize
1517
-
1518
- },{"./event-manager":10}],15:[function(require,module,exports){
1519
- var manager = require( './event-manager' )
1520
- var scroll = manager.new( 'scroll' )
1521
-
1522
- scroll.disablePointer = function() {
1523
-
1524
- // Disable pointer interaction
1525
- scroll.start( function() {
1526
- document.documentElement.style.pointerEvents = 'none'
1527
- })
1528
-
1529
- // Enable pointer interaction
1530
- scroll.end( function() {
1531
- document.documentElement.style.pointerEvents = ''
1532
- })
1533
- }
1534
-
1535
- module.exports = scroll
1536
-
1537
- },{"./event-manager":10}],16:[function(require,module,exports){
1538
- // Custom Event Polyfill
1539
- (function () {
1540
-
1541
- if ( typeof window.CustomEvent === "function" ) return false;
1542
-
1543
- function CustomEvent ( event, params ) {
1544
- params = params || { bubbles: false, cancelable: false, detail: undefined };
1545
- var evt = document.createEvent( 'CustomEvent' );
1546
- evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
1547
- return evt;
1548
- }
1549
-
1550
- CustomEvent.prototype = window.Event.prototype;
1551
-
1552
- window.CustomEvent = CustomEvent;
1553
- })()
1554
-
1555
- },{}],17:[function(require,module,exports){
1556
- // Manually trigger a cancelable form submit event.
1557
- function submit( form ) {
1558
- if ( !form.tagName || form.tagName != 'FORM' ) {
1559
- return console.error( 'Trigger this event on a form element' )
1560
- }
1561
-
1562
- var ev = new CustomEvent( 'submit', { bubbles: true, cancelable: true, detail: { triggered: true } } )
1563
- form.dispatchEvent( ev )
1564
-
1565
- // Submit form unless event default is prevented
1566
- if ( !ev.defaultPrevented ) form.submit()
1567
- }
1568
-
1569
- module.exports = submit
1570
-
1571
- },{}],18:[function(require,module,exports){
1572
- var endEvents = [
1573
- 'touchend'
1574
- ]
1575
-
1576
- module.exports = Tap
1577
-
1578
- // default tap timeout in ms
1579
- Tap.timeout = 200
1580
-
1581
- function Tap(callback, options) {
1582
- options = options || {}
1583
- // if the user holds his/her finger down for more than 200ms,
1584
- // then it's not really considered a tap.
1585
- // however, you can make this configurable.
1586
- var timeout = options.timeout || Tap.timeout
1587
-
1588
- // to keep track of the original listener
1589
- listener.handler = callback
1590
-
1591
- return listener
1592
-
1593
- // el.addEventListener('touchstart', listener)
1594
- function listener(e1) {
1595
- // tap should only happen with a single finger
1596
- if (!e1.touches || e1.touches.length > 1) return
1597
-
1598
- var el = e1.target
1599
- var context = this
1600
- var args = arguments;
1601
-
1602
- var timeout_id = setTimeout(cleanup, timeout)
1603
-
1604
- el.addEventListener('touchmove', cleanup)
1605
-
1606
- endEvents.forEach(function (event) {
1607
- el.addEventListener(event, done)
1608
- })
1609
-
1610
- function done(e2) {
1611
- // since touchstart is added on the same tick
1612
- // and because of bubbling,
1613
- // it'll execute this on the same touchstart.
1614
- // this filters out the same touchstart event.
1615
- if (e1 === e2) return
1616
-
1617
- cleanup()
1618
-
1619
- // already handled
1620
- if (e2.defaultPrevented) return
1621
-
1622
- // overwrite these functions so that they all to both start and events.
1623
- var preventDefault = e1.preventDefault
1624
- var stopPropagation = e1.stopPropagation
1625
-
1626
- e1.stopPropagation = function () {
1627
- stopPropagation.call(e1)
1628
- stopPropagation.call(e2)
1629
- }
1630
-
1631
- e1.preventDefault = function () {
1632
- preventDefault.call(e1)
1633
- preventDefault.call(e2)
1634
- }
1635
-
1636
- // calls the handler with the `end` event,
1637
- // but i don't think it matters.
1638
- callback.apply(context, args)
1639
- }
1640
-
1641
- // cleanup end events
1642
- // to cancel the tap, just run this early
1643
- function cleanup(e2) {
1644
- // if it's the same event as the origin,
1645
- // then don't actually cleanup.
1646
- // hit issues with this - don't remember
1647
- if (e1 === e2) return
1648
-
1649
- clearTimeout(timeout_id)
1650
-
1651
- el.removeEventListener('touchmove', cleanup)
1652
-
1653
- endEvents.forEach(function (event) {
1654
- el.removeEventListener(event, done)
1655
- })
1656
- }
1657
- }
1658
- }
1659
-
1660
- },{}],19:[function(require,module,exports){
1661
- var debounce = require( './debounce' )
1662
-
1663
- var throttle = function( fn, wait, options ) {
1664
-
1665
- if ( typeof( fn ) == 'object' ) { options = fn; fn = undefined }
1666
- else { options = options || {} }
1667
-
1668
- options.wait = options.wait || wait || 0
1669
- options.max = options.max || options.wait
1670
- options.callback = options.callback || fn
1671
- options.leading = true
1672
- options.trailing = true
1673
-
1674
- return debounce(options)
1675
- }
1676
-
1677
-
1678
- module.exports = throttle
1679
-
1680
- },{"./debounce":8}],20:[function(require,module,exports){
1681
- // CodeMirror, copyright (c) by Marijn Haverbeke and others
1682
- // Distributed under an MIT license: https://codemirror.net/LICENSE
1683
-
1684
- (function(mod) {
1685
- if (typeof exports == "object" && typeof module == "object") // CommonJS
1686
- mod(require("../../lib/codemirror"));
1687
- else if (typeof define == "function" && define.amd) // AMD
1688
- define(["../../lib/codemirror"], mod);
1689
- else // Plain browser env
1690
- mod(CodeMirror);
1691
- })(function(CodeMirror) {
1692
- var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
1693
- (document.documentMode == null || document.documentMode < 8);
1694
-
1695
- var Pos = CodeMirror.Pos;
1696
-
1697
- var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"};
1698
-
1699
- function bracketRegex(config) {
1700
- return config && config.bracketRegex || /[(){}[\]]/
1701
- }
1702
-
1703
- function findMatchingBracket(cm, where, config) {
1704
- var line = cm.getLineHandle(where.line), pos = where.ch - 1;
1705
- var afterCursor = config && config.afterCursor
1706
- if (afterCursor == null)
1707
- afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)
1708
- var re = bracketRegex(config)
1709
-
1710
- // A cursor is defined as between two characters, but in in vim command mode
1711
- // (i.e. not insert mode), the cursor is visually represented as a
1712
- // highlighted box on top of the 2nd character. Otherwise, we allow matches
1713
- // from before or after the cursor.
1714
- var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) ||
1715
- re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)];
1716
- if (!match) return null;
1717
- var dir = match.charAt(1) == ">" ? 1 : -1;
1718
- if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;
1719
- var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
1720
-
1721
- var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
1722
- if (found == null) return null;
1723
- return {from: Pos(where.line, pos), to: found && found.pos,
1724
- match: found && found.ch == match.charAt(0), forward: dir > 0};
1725
- }
1726
-
1727
- // bracketRegex is used to specify which type of bracket to scan
1728
- // should be a regexp, e.g. /[[\]]/
1729
- //
1730
- // Note: If "where" is on an open bracket, then this bracket is ignored.
1731
- //
1732
- // Returns false when no bracket was found, null when it reached
1733
- // maxScanLines and gave up
1734
- function scanForBracket(cm, where, dir, style, config) {
1735
- var maxScanLen = (config && config.maxScanLineLength) || 10000;
1736
- var maxScanLines = (config && config.maxScanLines) || 1000;
1737
-
1738
- var stack = [];
1739
- var re = bracketRegex(config)
1740
- var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
1741
- : Math.max(cm.firstLine() - 1, where.line - maxScanLines);
1742
- for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
1743
- var line = cm.getLine(lineNo);
1744
- if (!line) continue;
1745
- var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
1746
- if (line.length > maxScanLen) continue;
1747
- if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
1748
- for (; pos != end; pos += dir) {
1749
- var ch = line.charAt(pos);
1750
- if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
1751
- var match = matching[ch];
1752
- if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
1753
- else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
1754
- else stack.pop();
1755
- }
1756
- }
1757
- }
1758
- return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
1759
- }
1760
-
1761
- function matchBrackets(cm, autoclear, config) {
1762
- // Disable brace matching in long lines, since it'll cause hugely slow updates
1763
- var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
1764
- var marks = [], ranges = cm.listSelections();
1765
- for (var i = 0; i < ranges.length; i++) {
1766
- var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);
1767
- if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
1768
- var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
1769
- marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
1770
- if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
1771
- marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
1772
- }
1773
- }
1774
-
1775
- if (marks.length) {
1776
- // Kludge to work around the IE bug from issue #1193, where text
1777
- // input stops going to the textare whever this fires.
1778
- if (ie_lt8 && cm.state.focused) cm.focus();
1779
-
1780
- var clear = function() {
1781
- cm.operation(function() {
1782
- for (var i = 0; i < marks.length; i++) marks[i].clear();
1783
- });
1784
- };
1785
- if (autoclear) setTimeout(clear, 800);
1786
- else return clear;
1787
- }
1788
- }
1789
-
1790
- function doMatchBrackets(cm) {
1791
- cm.operation(function() {
1792
- if (cm.state.matchBrackets.currentlyHighlighted) {
1793
- cm.state.matchBrackets.currentlyHighlighted();
1794
- cm.state.matchBrackets.currentlyHighlighted = null;
1795
- }
1796
- cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
1797
- });
1798
- }
1799
-
1800
- CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
1801
- if (old && old != CodeMirror.Init) {
1802
- cm.off("cursorActivity", doMatchBrackets);
1803
- if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
1804
- cm.state.matchBrackets.currentlyHighlighted();
1805
- cm.state.matchBrackets.currentlyHighlighted = null;
1806
- }
1807
- }
1808
- if (val) {
1809
- cm.state.matchBrackets = typeof val == "object" ? val : {};
1810
- cm.on("cursorActivity", doMatchBrackets);
1811
- }
1812
- });
1813
-
1814
- CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
1815
- CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){
1816
- // Backwards-compatibility kludge
1817
- if (oldConfig || typeof config == "boolean") {
1818
- if (!oldConfig) {
1819
- config = config ? {strict: true} : null
1820
- } else {
1821
- oldConfig.strict = config
1822
- config = oldConfig
1823
- }
1824
- }
1825
- return findMatchingBracket(this, pos, config)
1826
- });
1827
- CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
1828
- return scanForBracket(this, pos, dir, style, config);
1829
- });
1830
- });
1831
-
1832
- },{"../../lib/codemirror":22}],21:[function(require,module,exports){
1833
- // CodeMirror, copyright (c) by Marijn Haverbeke and others
1834
- // Distributed under an MIT license: https://codemirror.net/LICENSE
1835
-
1836
- (function(mod) {
1837
- if (typeof exports == "object" && typeof module == "object") // CommonJS
1838
- mod(require("../../lib/codemirror"));
1839
- else if (typeof define == "function" && define.amd) // AMD
1840
- define(["../../lib/codemirror"], mod);
1841
- else // Plain browser env
1842
- mod(CodeMirror);
1843
- })(function(CodeMirror) {
1844
- "use strict";
1845
-
1846
- CodeMirror.runMode = function(string, modespec, callback, options) {
1847
- var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
1848
- var ie = /MSIE \d/.test(navigator.userAgent);
1849
- var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
1850
-
1851
- if (callback.appendChild) {
1852
- var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
1853
- var node = callback, col = 0;
1854
- node.innerHTML = "";
1855
- callback = function(text, style) {
1856
- if (text == "\n") {
1857
- // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
1858
- // Emitting a carriage return makes everything ok.
1859
- node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
1860
- col = 0;
1861
- return;
1862
- }
1863
- var content = "";
1864
- // replace tabs
1865
- for (var pos = 0;;) {
1866
- var idx = text.indexOf("\t", pos);
1867
- if (idx == -1) {
1868
- content += text.slice(pos);
1869
- col += text.length - pos;
1870
- break;
1871
- } else {
1872
- col += idx - pos;
1873
- content += text.slice(pos, idx);
1874
- var size = tabSize - col % tabSize;
1875
- col += size;
1876
- for (var i = 0; i < size; ++i) content += " ";
1877
- pos = idx + 1;
1878
- }
1879
- }
1880
-
1881
- if (style) {
1882
- var sp = node.appendChild(document.createElement("span"));
1883
- sp.className = "cm-" + style.replace(/ +/g, " cm-");
1884
- sp.appendChild(document.createTextNode(content));
1885
- } else {
1886
- node.appendChild(document.createTextNode(content));
1887
- }
1888
- };
1889
- }
1890
-
1891
- var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
1892
- for (var i = 0, e = lines.length; i < e; ++i) {
1893
- if (i) callback("\n");
1894
- var stream = new CodeMirror.StringStream(lines[i]);
1895
- if (!stream.string && mode.blankLine) mode.blankLine(state);
1896
- while (!stream.eol()) {
1897
- var style = mode.token(stream, state);
1898
- callback(stream.current(), style, i, stream.start, state);
1899
- stream.start = stream.pos;
1900
- }
1901
- }
1902
- };
1903
-
1904
- });
1905
-
1906
- },{"../../lib/codemirror":22}],22:[function(require,module,exports){
1907
- // CodeMirror, copyright (c) by Marijn Haverbeke and others
1908
- // Distributed under an MIT license: https://codemirror.net/LICENSE
1909
-
1910
- // This is CodeMirror (https://codemirror.net), a code editor
1911
- // implemented in JavaScript on top of the browser's DOM.
1912
- //
1913
- // You can find some technical background for some of the code below
1914
- // at http://marijnhaverbeke.nl/blog/#cm-internals .
1915
-
1916
- (function (global, factory) {
1917
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
1918
- typeof define === 'function' && define.amd ? define(factory) :
1919
- (global.CodeMirror = factory());
1920
- }(this, (function () { 'use strict';
1921
-
1922
- // Kludges for bugs and behavior differences that can't be feature
1923
- // detected are enabled based on userAgent etc sniffing.
1924
- var userAgent = navigator.userAgent;
1925
- var platform = navigator.platform;
1926
-
1927
- var gecko = /gecko\/\d/i.test(userAgent);
1928
- var ie_upto10 = /MSIE \d/.test(userAgent);
1929
- var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
1930
- var edge = /Edge\/(\d+)/.exec(userAgent);
1931
- var ie = ie_upto10 || ie_11up || edge;
1932
- var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
1933
- var webkit = !edge && /WebKit\//.test(userAgent);
1934
- var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
1935
- var chrome = !edge && /Chrome\//.test(userAgent);
1936
- var presto = /Opera\//.test(userAgent);
1937
- var safari = /Apple Computer/.test(navigator.vendor);
1938
- var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
1939
- var phantom = /PhantomJS/.test(userAgent);
1940
-
1941
- var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
1942
- var android = /Android/.test(userAgent);
1943
- // This is woefully incomplete. Suggestions for alternative methods welcome.
1944
- var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
1945
- var mac = ios || /Mac/.test(platform);
1946
- var chromeOS = /\bCrOS\b/.test(userAgent);
1947
- var windows = /win/i.test(platform);
1948
-
1949
- var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
1950
- if (presto_version) { presto_version = Number(presto_version[1]); }
1951
- if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
1952
- // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
1953
- var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
1954
- var captureRightClick = gecko || (ie && ie_version >= 9);
1955
-
1956
- function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
1957
-
1958
- var rmClass = function(node, cls) {
1959
- var current = node.className;
1960
- var match = classTest(cls).exec(current);
1961
- if (match) {
1962
- var after = current.slice(match.index + match[0].length);
1963
- node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
1964
- }
1965
- };
1966
-
1967
- function removeChildren(e) {
1968
- for (var count = e.childNodes.length; count > 0; --count)
1969
- { e.removeChild(e.firstChild); }
1970
- return e
1971
- }
1972
-
1973
- function removeChildrenAndAdd(parent, e) {
1974
- return removeChildren(parent).appendChild(e)
1975
- }
1976
-
1977
- function elt(tag, content, className, style) {
1978
- var e = document.createElement(tag);
1979
- if (className) { e.className = className; }
1980
- if (style) { e.style.cssText = style; }
1981
- if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
1982
- else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
1983
- return e
1984
- }
1985
- // wrapper for elt, which removes the elt from the accessibility tree
1986
- function eltP(tag, content, className, style) {
1987
- var e = elt(tag, content, className, style);
1988
- e.setAttribute("role", "presentation");
1989
- return e
1990
- }
1991
-
1992
- var range;
1993
- if (document.createRange) { range = function(node, start, end, endNode) {
1994
- var r = document.createRange();
1995
- r.setEnd(endNode || node, end);
1996
- r.setStart(node, start);
1997
- return r
1998
- }; }
1999
- else { range = function(node, start, end) {
2000
- var r = document.body.createTextRange();
2001
- try { r.moveToElementText(node.parentNode); }
2002
- catch(e) { return r }
2003
- r.collapse(true);
2004
- r.moveEnd("character", end);
2005
- r.moveStart("character", start);
2006
- return r
2007
- }; }
2008
-
2009
- function contains(parent, child) {
2010
- if (child.nodeType == 3) // Android browser always returns false when child is a textnode
2011
- { child = child.parentNode; }
2012
- if (parent.contains)
2013
- { return parent.contains(child) }
2014
- do {
2015
- if (child.nodeType == 11) { child = child.host; }
2016
- if (child == parent) { return true }
2017
- } while (child = child.parentNode)
2018
- }
2019
-
2020
- function activeElt() {
2021
- // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
2022
- // IE < 10 will throw when accessed while the page is loading or in an iframe.
2023
- // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
2024
- var activeElement;
2025
- try {
2026
- activeElement = document.activeElement;
2027
- } catch(e) {
2028
- activeElement = document.body || null;
2029
- }
2030
- while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
2031
- { activeElement = activeElement.shadowRoot.activeElement; }
2032
- return activeElement
2033
- }
2034
-
2035
- function addClass(node, cls) {
2036
- var current = node.className;
2037
- if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
2038
- }
2039
- function joinClasses(a, b) {
2040
- var as = a.split(" ");
2041
- for (var i = 0; i < as.length; i++)
2042
- { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
2043
- return b
2044
- }
2045
-
2046
- var selectInput = function(node) { node.select(); };
2047
- if (ios) // Mobile Safari apparently has a bug where select() is broken.
2048
- { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
2049
- else if (ie) // Suppress mysterious IE10 errors
2050
- { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
2051
-
2052
- function bind(f) {
2053
- var args = Array.prototype.slice.call(arguments, 1);
2054
- return function(){return f.apply(null, args)}
2055
- }
2056
-
2057
- function copyObj(obj, target, overwrite) {
2058
- if (!target) { target = {}; }
2059
- for (var prop in obj)
2060
- { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
2061
- { target[prop] = obj[prop]; } }
2062
- return target
2063
- }
2064
-
2065
- // Counts the column offset in a string, taking tabs into account.
2066
- // Used mostly to find indentation.
2067
- function countColumn(string, end, tabSize, startIndex, startValue) {
2068
- if (end == null) {
2069
- end = string.search(/[^\s\u00a0]/);
2070
- if (end == -1) { end = string.length; }
2071
- }
2072
- for (var i = startIndex || 0, n = startValue || 0;;) {
2073
- var nextTab = string.indexOf("\t", i);
2074
- if (nextTab < 0 || nextTab >= end)
2075
- { return n + (end - i) }
2076
- n += nextTab - i;
2077
- n += tabSize - (n % tabSize);
2078
- i = nextTab + 1;
2079
- }
2080
- }
2081
-
2082
- var Delayed = function() {this.id = null;};
2083
- Delayed.prototype.set = function (ms, f) {
2084
- clearTimeout(this.id);
2085
- this.id = setTimeout(f, ms);
2086
- };
2087
-
2088
- function indexOf(array, elt) {
2089
- for (var i = 0; i < array.length; ++i)
2090
- { if (array[i] == elt) { return i } }
2091
- return -1
2092
- }
2093
-
2094
- // Number of pixels added to scroller and sizer to hide scrollbar
2095
- var scrollerGap = 30;
2096
-
2097
- // Returned or thrown by various protocols to signal 'I'm not
2098
- // handling this'.
2099
- var Pass = {toString: function(){return "CodeMirror.Pass"}};
2100
-
2101
- // Reused option objects for setSelection & friends
2102
- var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
2103
-
2104
- // The inverse of countColumn -- find the offset that corresponds to
2105
- // a particular column.
2106
- function findColumn(string, goal, tabSize) {
2107
- for (var pos = 0, col = 0;;) {
2108
- var nextTab = string.indexOf("\t", pos);
2109
- if (nextTab == -1) { nextTab = string.length; }
2110
- var skipped = nextTab - pos;
2111
- if (nextTab == string.length || col + skipped >= goal)
2112
- { return pos + Math.min(skipped, goal - col) }
2113
- col += nextTab - pos;
2114
- col += tabSize - (col % tabSize);
2115
- pos = nextTab + 1;
2116
- if (col >= goal) { return pos }
2117
- }
2118
- }
2119
-
2120
- var spaceStrs = [""];
2121
- function spaceStr(n) {
2122
- while (spaceStrs.length <= n)
2123
- { spaceStrs.push(lst(spaceStrs) + " "); }
2124
- return spaceStrs[n]
2125
- }
2126
-
2127
- function lst(arr) { return arr[arr.length-1] }
2128
-
2129
- function map(array, f) {
2130
- var out = [];
2131
- for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
2132
- return out
2133
- }
2134
-
2135
- function insertSorted(array, value, score) {
2136
- var pos = 0, priority = score(value);
2137
- while (pos < array.length && score(array[pos]) <= priority) { pos++; }
2138
- array.splice(pos, 0, value);
2139
- }
2140
-
2141
- function nothing() {}
2142
-
2143
- function createObj(base, props) {
2144
- var inst;
2145
- if (Object.create) {
2146
- inst = Object.create(base);
2147
- } else {
2148
- nothing.prototype = base;
2149
- inst = new nothing();
2150
- }
2151
- if (props) { copyObj(props, inst); }
2152
- return inst
2153
- }
2154
-
2155
- var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
2156
- function isWordCharBasic(ch) {
2157
- return /\w/.test(ch) || ch > "\x80" &&
2158
- (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
2159
- }
2160
- function isWordChar(ch, helper) {
2161
- if (!helper) { return isWordCharBasic(ch) }
2162
- if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
2163
- return helper.test(ch)
2164
- }
2165
-
2166
- function isEmpty(obj) {
2167
- for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
2168
- return true
2169
- }
2170
-
2171
- // Extending unicode characters. A series of a non-extending char +
2172
- // any number of extending chars is treated as a single unit as far
2173
- // as editing and measuring is concerned. This is not fully correct,
2174
- // since some scripts/fonts/browsers also treat other configurations
2175
- // of code points as a group.
2176
- var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
2177
- function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
2178
-
2179
- // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
2180
- function skipExtendingChars(str, pos, dir) {
2181
- while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
2182
- return pos
2183
- }
2184
-
2185
- // Returns the value from the range [`from`; `to`] that satisfies
2186
- // `pred` and is closest to `from`. Assumes that at least `to`
2187
- // satisfies `pred`. Supports `from` being greater than `to`.
2188
- function findFirst(pred, from, to) {
2189
- // At any point we are certain `to` satisfies `pred`, don't know
2190
- // whether `from` does.
2191
- var dir = from > to ? -1 : 1;
2192
- for (;;) {
2193
- if (from == to) { return from }
2194
- var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
2195
- if (mid == from) { return pred(mid) ? from : to }
2196
- if (pred(mid)) { to = mid; }
2197
- else { from = mid + dir; }
2198
- }
2199
- }
2200
-
2201
- // BIDI HELPERS
2202
-
2203
- function iterateBidiSections(order, from, to, f) {
2204
- if (!order) { return f(from, to, "ltr", 0) }
2205
- var found = false;
2206
- for (var i = 0; i < order.length; ++i) {
2207
- var part = order[i];
2208
- if (part.from < to && part.to > from || from == to && part.to == from) {
2209
- f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
2210
- found = true;
2211
- }
2212
- }
2213
- if (!found) { f(from, to, "ltr"); }
2214
- }
2215
-
2216
- var bidiOther = null;
2217
- function getBidiPartAt(order, ch, sticky) {
2218
- var found;
2219
- bidiOther = null;
2220
- for (var i = 0; i < order.length; ++i) {
2221
- var cur = order[i];
2222
- if (cur.from < ch && cur.to > ch) { return i }
2223
- if (cur.to == ch) {
2224
- if (cur.from != cur.to && sticky == "before") { found = i; }
2225
- else { bidiOther = i; }
2226
- }
2227
- if (cur.from == ch) {
2228
- if (cur.from != cur.to && sticky != "before") { found = i; }
2229
- else { bidiOther = i; }
2230
- }
2231
- }
2232
- return found != null ? found : bidiOther
2233
- }
2234
-
2235
- // Bidirectional ordering algorithm
2236
- // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
2237
- // that this (partially) implements.
2238
-
2239
- // One-char codes used for character types:
2240
- // L (L): Left-to-Right
2241
- // R (R): Right-to-Left
2242
- // r (AL): Right-to-Left Arabic
2243
- // 1 (EN): European Number
2244
- // + (ES): European Number Separator
2245
- // % (ET): European Number Terminator
2246
- // n (AN): Arabic Number
2247
- // , (CS): Common Number Separator
2248
- // m (NSM): Non-Spacing Mark
2249
- // b (BN): Boundary Neutral
2250
- // s (B): Paragraph Separator
2251
- // t (S): Segment Separator
2252
- // w (WS): Whitespace
2253
- // N (ON): Other Neutrals
2254
-
2255
- // Returns null if characters are ordered as they appear
2256
- // (left-to-right), or an array of sections ({from, to, level}
2257
- // objects) in the order in which they occur visually.
2258
- var bidiOrdering = (function() {
2259
- // Character types for codepoints 0 to 0xff
2260
- var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
2261
- // Character types for codepoints 0x600 to 0x6f9
2262
- var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
2263
- function charType(code) {
2264
- if (code <= 0xf7) { return lowTypes.charAt(code) }
2265
- else if (0x590 <= code && code <= 0x5f4) { return "R" }
2266
- else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
2267
- else if (0x6ee <= code && code <= 0x8ac) { return "r" }
2268
- else if (0x2000 <= code && code <= 0x200b) { return "w" }
2269
- else if (code == 0x200c) { return "b" }
2270
- else { return "L" }
2271
- }
2272
-
2273
- var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
2274
- var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
2275
-
2276
- function BidiSpan(level, from, to) {
2277
- this.level = level;
2278
- this.from = from; this.to = to;
2279
- }
2280
-
2281
- return function(str, direction) {
2282
- var outerType = direction == "ltr" ? "L" : "R";
2283
-
2284
- if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
2285
- var len = str.length, types = [];
2286
- for (var i = 0; i < len; ++i)
2287
- { types.push(charType(str.charCodeAt(i))); }
2288
-
2289
- // W1. Examine each non-spacing mark (NSM) in the level run, and
2290
- // change the type of the NSM to the type of the previous
2291
- // character. If the NSM is at the start of the level run, it will
2292
- // get the type of sor.
2293
- for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
2294
- var type = types[i$1];
2295
- if (type == "m") { types[i$1] = prev; }
2296
- else { prev = type; }
2297
- }
2298
-
2299
- // W2. Search backwards from each instance of a European number
2300
- // until the first strong type (R, L, AL, or sor) is found. If an
2301
- // AL is found, change the type of the European number to Arabic
2302
- // number.
2303
- // W3. Change all ALs to R.
2304
- for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
2305
- var type$1 = types[i$2];
2306
- if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
2307
- else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
2308
- }
2309
-
2310
- // W4. A single European separator between two European numbers
2311
- // changes to a European number. A single common separator between
2312
- // two numbers of the same type changes to that type.
2313
- for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
2314
- var type$2 = types[i$3];
2315
- if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
2316
- else if (type$2 == "," && prev$1 == types[i$3+1] &&
2317
- (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
2318
- prev$1 = type$2;
2319
- }
2320
-
2321
- // W5. A sequence of European terminators adjacent to European
2322
- // numbers changes to all European numbers.
2323
- // W6. Otherwise, separators and terminators change to Other
2324
- // Neutral.
2325
- for (var i$4 = 0; i$4 < len; ++i$4) {
2326
- var type$3 = types[i$4];
2327
- if (type$3 == ",") { types[i$4] = "N"; }
2328
- else if (type$3 == "%") {
2329
- var end = (void 0);
2330
- for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
2331
- var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
2332
- for (var j = i$4; j < end; ++j) { types[j] = replace; }
2333
- i$4 = end - 1;
2334
- }
2335
- }
2336
-
2337
- // W7. Search backwards from each instance of a European number
2338
- // until the first strong type (R, L, or sor) is found. If an L is
2339
- // found, then change the type of the European number to L.
2340
- for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
2341
- var type$4 = types[i$5];
2342
- if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
2343
- else if (isStrong.test(type$4)) { cur$1 = type$4; }
2344
- }
2345
-
2346
- // N1. A sequence of neutrals takes the direction of the
2347
- // surrounding strong text if the text on both sides has the same
2348
- // direction. European and Arabic numbers act as if they were R in
2349
- // terms of their influence on neutrals. Start-of-level-run (sor)
2350
- // and end-of-level-run (eor) are used at level run boundaries.
2351
- // N2. Any remaining neutrals take the embedding direction.
2352
- for (var i$6 = 0; i$6 < len; ++i$6) {
2353
- if (isNeutral.test(types[i$6])) {
2354
- var end$1 = (void 0);
2355
- for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
2356
- var before = (i$6 ? types[i$6-1] : outerType) == "L";
2357
- var after = (end$1 < len ? types[end$1] : outerType) == "L";
2358
- var replace$1 = before == after ? (before ? "L" : "R") : outerType;
2359
- for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
2360
- i$6 = end$1 - 1;
2361
- }
2362
- }
2363
-
2364
- // Here we depart from the documented algorithm, in order to avoid
2365
- // building up an actual levels array. Since there are only three
2366
- // levels (0, 1, 2) in an implementation that doesn't take
2367
- // explicit embedding into account, we can build up the order on
2368
- // the fly, without following the level-based algorithm.
2369
- var order = [], m;
2370
- for (var i$7 = 0; i$7 < len;) {
2371
- if (countsAsLeft.test(types[i$7])) {
2372
- var start = i$7;
2373
- for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
2374
- order.push(new BidiSpan(0, start, i$7));
2375
- } else {
2376
- var pos = i$7, at = order.length;
2377
- for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
2378
- for (var j$2 = pos; j$2 < i$7;) {
2379
- if (countsAsNum.test(types[j$2])) {
2380
- if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
2381
- var nstart = j$2;
2382
- for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
2383
- order.splice(at, 0, new BidiSpan(2, nstart, j$2));
2384
- pos = j$2;
2385
- } else { ++j$2; }
2386
- }
2387
- if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
2388
- }
2389
- }
2390
- if (direction == "ltr") {
2391
- if (order[0].level == 1 && (m = str.match(/^\s+/))) {
2392
- order[0].from = m[0].length;
2393
- order.unshift(new BidiSpan(0, 0, m[0].length));
2394
- }
2395
- if (lst(order).level == 1 && (m = str.match(/\s+#x2F;))) {
2396
- lst(order).to -= m[0].length;
2397
- order.push(new BidiSpan(0, len - m[0].length, len));
2398
- }
2399
- }
2400
-
2401
- return direction == "rtl" ? order.reverse() : order
2402
- }
2403
- })();
2404
-
2405
- // Get the bidi ordering for the given line (and cache it). Returns
2406
- // false for lines that are fully left-to-right, and an array of
2407
- // BidiSpan objects otherwise.
2408
- function getOrder(line, direction) {
2409
- var order = line.order;
2410
- if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
2411
- return order
2412
- }
2413
-
2414
- // EVENT HANDLING
2415
-
2416
- // Lightweight event framework. on/off also work on DOM nodes,
2417
- // registering native DOM handlers.
2418
-
2419
- var noHandlers = [];
2420
-
2421
- var on = function(emitter, type, f) {
2422
- if (emitter.addEventListener) {
2423
- emitter.addEventListener(type, f, false);
2424
- } else if (emitter.attachEvent) {
2425
- emitter.attachEvent("on" + type, f);
2426
- } else {
2427
- var map$1 = emitter._handlers || (emitter._handlers = {});
2428
- map$1[type] = (map$1[type] || noHandlers).concat(f);
2429
- }
2430
- };
2431
-
2432
- function getHandlers(emitter, type) {
2433
- return emitter._handlers && emitter._handlers[type] || noHandlers
2434
- }
2435
-
2436
- function off(emitter, type, f) {
2437
- if (emitter.removeEventListener) {
2438
- emitter.removeEventListener(type, f, false);
2439
- } else if (emitter.detachEvent) {
2440
- emitter.detachEvent("on" + type, f);
2441
- } else {
2442
- var map$1 = emitter._handlers, arr = map$1 && map$1[type];
2443
- if (arr) {
2444
- var index = indexOf(arr, f);
2445
- if (index > -1)
2446
- { map$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
2447
- }
2448
- }
2449
- }
2450
-
2451
- function signal(emitter, type /*, values...*/) {
2452
- var handlers = getHandlers(emitter, type);
2453
- if (!handlers.length) { return }
2454
- var args = Array.prototype.slice.call(arguments, 2);
2455
- for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
2456
- }
2457
-
2458
- // The DOM events that CodeMirror handles can be overridden by
2459
- // registering a (non-DOM) handler on the editor for the event name,
2460
- // and preventDefault-ing the event in that handler.
2461
- function signalDOMEvent(cm, e, override) {
2462
- if (typeof e == "string")
2463
- { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
2464
- signal(cm, override || e.type, cm, e);
2465
- return e_defaultPrevented(e) || e.codemirrorIgnore
2466
- }
2467
-
2468
- function signalCursorActivity(cm) {
2469
- var arr = cm._handlers && cm._handlers.cursorActivity;
2470
- if (!arr) { return }
2471
- var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
2472
- for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
2473
- { set.push(arr[i]); } }
2474
- }
2475
-
2476
- function hasHandler(emitter, type) {
2477
- return getHandlers(emitter, type).length > 0
2478
- }
2479
-
2480
- // Add on and off methods to a constructor's prototype, to make
2481
- // registering events on such objects more convenient.
2482
- function eventMixin(ctor) {
2483
- ctor.prototype.on = function(type, f) {on(this, type, f);};
2484
- ctor.prototype.off = function(type, f) {off(this, type, f);};
2485
- }
2486
-
2487
- // Due to the fact that we still support jurassic IE versions, some
2488
- // compatibility wrappers are needed.
2489
-
2490
- function e_preventDefault(e) {
2491
- if (e.preventDefault) { e.preventDefault(); }
2492
- else { e.returnValue = false; }
2493
- }
2494
- function e_stopPropagation(e) {
2495
- if (e.stopPropagation) { e.stopPropagation(); }
2496
- else { e.cancelBubble = true; }
2497
- }
2498
- function e_defaultPrevented(e) {
2499
- return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
2500
- }
2501
- function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
2502
-
2503
- function e_target(e) {return e.target || e.srcElement}
2504
- function e_button(e) {
2505
- var b = e.which;
2506
- if (b == null) {
2507
- if (e.button & 1) { b = 1; }
2508
- else if (e.button & 2) { b = 3; }
2509
- else if (e.button & 4) { b = 2; }
2510
- }
2511
- if (mac && e.ctrlKey && b == 1) { b = 3; }
2512
- return b
2513
- }
2514
-
2515
- // Detect drag-and-drop
2516
- var dragAndDrop = function() {
2517
- // There is *some* kind of drag-and-drop support in IE6-8, but I
2518
- // couldn't get it to work yet.
2519
- if (ie && ie_version < 9) { return false }
2520
- var div = elt('div');
2521
- return "draggable" in div || "dragDrop" in div
2522
- }();
2523
-
2524
- var zwspSupported;
2525
- function zeroWidthElement(measure) {
2526
- if (zwspSupported == null) {
2527
- var test = elt("span", "\u200b");
2528
- removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
2529
- if (measure.firstChild.offsetHeight != 0)
2530
- { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
2531
- }
2532
- var node = zwspSupported ? elt("span", "\u200b") :
2533
- elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
2534
- node.setAttribute("cm-text", "");
2535
- return node
2536
- }
2537
-
2538
- // Feature-detect IE's crummy client rect reporting for bidi text
2539