mithril-pipeline 0.2.5 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f6851f7c5e5d0d6077bebe49dd8c13a7404e698a
4
- data.tar.gz: 59f1ad0c6946910c6cff20d083fd67b394364f0c
3
+ metadata.gz: 65cd82dd7598ca756c7c52aeabcb50933c942c9a
4
+ data.tar.gz: a138c2d455bb1f5fd8427485d7c8bd25817e5f37
5
5
  SHA512:
6
- metadata.gz: e19e9aa1b22d71bab70aee72f53c4c27bace265d875a988d3bd730ca791c823190dc76d1774bcfa44ffde3df32efc1829670b78697176a9265f6d616cb658305
7
- data.tar.gz: 2ca106f3c3323e245081b88bed250f883917e8ab0ec071a5cc10f1f3bb4c57703f1d7687fbe6febe38ca90dc40331fd5de87b0a98464eb11b1107471a12921d6
6
+ metadata.gz: 25450375c87cdbd374e1a2b2df99116a9e200e03fec93e2bd2b500f5b0c28db4727d71720a3787ae9f8a47c43c7c61ab8e787411fe6635462e6e450930747bfd
7
+ data.tar.gz: 2d3b9fee0016c0baa613f192d42711ffdee30bca7e11ccbd7247cca0d876ac9c5443f8187f3c1cc30948d6278822a89ba2ddaa5e1f4f46e001bff8887877d5d8
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
3
  gemspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mithril-pipeline (0.2.5)
4
+ mithril-pipeline (1.0.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/README.md CHANGED
@@ -7,6 +7,7 @@ Add `gem "mithril-pipeline"` to your Gemfile.
7
7
  You can then add Mithril to your asset manifest files with
8
8
 
9
9
  `//= require mithril`
10
+ `//= require mithril_stream`
10
11
 
11
12
  ## Versioning
12
13
 
@@ -1,3 +1,3 @@
1
1
  module MithrilPipeline
2
- VERSION = '0.2.5'
2
+ VERSION = '1.0.1'
3
3
  end
@@ -1,2233 +1,1163 @@
1
- ;(function (global, factory) { // eslint-disable-line
2
- "use strict"
3
- /* eslint-disable no-undef */
4
- var m = factory(global)
5
- if (typeof module === "object" && module != null && module.exports) {
6
- module.exports = m
7
- } else if (typeof define === "function" && define.amd) {
8
- define(function () { return m })
9
- } else {
10
- global.m = m
11
- }
12
- /* eslint-enable no-undef */
13
- })(typeof window !== "undefined" ? window : this, function (global, undefined) { // eslint-disable-line
14
- "use strict"
15
-
16
- m.version = function () {
17
- return "v0.2.5"
18
- }
19
-
20
- var hasOwn = {}.hasOwnProperty
21
- var type = {}.toString
22
-
23
- function isFunction(object) {
24
- return typeof object === "function"
25
- }
26
-
27
- function isObject(object) {
28
- return type.call(object) === "[object Object]"
29
- }
30
-
31
- function isString(object) {
32
- return type.call(object) === "[object String]"
33
- }
34
-
35
- var isArray = Array.isArray || function (object) {
36
- return type.call(object) === "[object Array]"
37
- }
38
-
39
- function noop() {}
40
-
41
- var voidElements = {
42
- AREA: 1,
43
- BASE: 1,
44
- BR: 1,
45
- COL: 1,
46
- COMMAND: 1,
47
- EMBED: 1,
48
- HR: 1,
49
- IMG: 1,
50
- INPUT: 1,
51
- KEYGEN: 1,
52
- LINK: 1,
53
- META: 1,
54
- PARAM: 1,
55
- SOURCE: 1,
56
- TRACK: 1,
57
- WBR: 1
58
- }
59
-
60
- // caching commonly used variables
61
- var $document, $location, $requestAnimationFrame, $cancelAnimationFrame
62
-
63
- // self invoking function needed because of the way mocks work
64
- function initialize(mock) {
65
- $document = mock.document
66
- $location = mock.location
67
- $cancelAnimationFrame = mock.cancelAnimationFrame || mock.clearTimeout
68
- $requestAnimationFrame = mock.requestAnimationFrame || mock.setTimeout
69
- }
70
-
71
- // testing API
72
- m.deps = function (mock) {
73
- initialize(global = mock || window)
74
- return global
75
- }
76
-
77
- m.deps(global)
78
-
79
- /**
80
- * @typedef {String} Tag
81
- * A string that looks like -> div.classname#id[param=one][param2=two]
82
- * Which describes a DOM node
83
- */
84
-
85
- function parseTagAttrs(cell, tag) {
86
- var classes = []
87
- var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g
88
- var match
89
-
90
- while ((match = parser.exec(tag))) {
91
- if (match[1] === "" && match[2]) {
92
- cell.tag = match[2]
93
- } else if (match[1] === "#") {
94
- cell.attrs.id = match[2]
95
- } else if (match[1] === ".") {
96
- classes.push(match[2])
97
- } else if (match[3][0] === "[") {
98
- var pair = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/.exec(match[3])
99
- cell.attrs[pair[1]] = pair[3] || ""
100
- }
101
- }
102
-
103
- return classes
104
- }
105
-
106
- function getVirtualChildren(args, hasAttrs) {
107
- var children = hasAttrs ? args.slice(1) : args
108
-
109
- if (children.length === 1 && isArray(children[0])) {
110
- return children[0]
111
- } else {
112
- return children
113
- }
114
- }
115
-
116
- function assignAttrs(target, attrs, classes) {
117
- var classAttr = "class" in attrs ? "class" : "className"
118
-
119
- for (var attrName in attrs) {
120
- if (hasOwn.call(attrs, attrName)) {
121
- if (attrName === classAttr &&
122
- attrs[attrName] != null &&
123
- attrs[attrName] !== "") {
124
- classes.push(attrs[attrName])
125
- // create key in correct iteration order
126
- target[attrName] = ""
127
- } else {
128
- target[attrName] = attrs[attrName]
129
- }
130
- }
131
- }
132
-
133
- if (classes.length) target[classAttr] = classes.join(" ")
134
- }
135
-
136
- /**
137
- *
138
- * @param {Tag} The DOM node tag
139
- * @param {Object=[]} optional key-value pairs to be mapped to DOM attrs
140
- * @param {...mNode=[]} Zero or more Mithril child nodes. Can be an array,
141
- * or splat (optional)
142
- */
143
- function m(tag, pairs) {
144
- var args = []
145
-
146
- for (var i = 1, length = arguments.length; i < length; i++) {
147
- args[i - 1] = arguments[i]
148
- }
149
-
150
- if (isObject(tag)) return parameterize(tag, args)
151
-
152
- if (!isString(tag)) {
153
- throw new Error("selector in m(selector, attrs, children) should " +
154
- "be a string")
155
- }
156
-
157
- var hasAttrs = pairs != null && isObject(pairs) &&
158
- !("tag" in pairs || "view" in pairs || "subtree" in pairs)
159
-
160
- var attrs = hasAttrs ? pairs : {}
161
- var cell = {
162
- tag: "div",
163
- attrs: {},
164
- children: getVirtualChildren(args, hasAttrs)
165
- }
166
-
167
- assignAttrs(cell.attrs, attrs, parseTagAttrs(cell, tag))
168
- return cell
169
- }
170
-
171
- function forEach(list, f) {
172
- for (var i = 0; i < list.length && !f(list[i], i++);) {
173
- // function called in condition
174
- }
175
- }
176
-
177
- function forKeys(list, f) {
178
- forEach(list, function (attrs, i) {
179
- return (attrs = attrs && attrs.attrs) &&
180
- attrs.key != null &&
181
- f(attrs, i)
182
- })
183
- }
184
- // This function was causing deopts in Chrome.
185
- function dataToString(data) {
186
- // data.toString() might throw or return null if data is the return
187
- // value of Console.log in some versions of Firefox (behavior depends on
188
- // version)
189
- try {
190
- if (data != null && data.toString() != null) return data
191
- } catch (e) {
192
- // silently ignore errors
193
- }
194
- return ""
195
- }
196
-
197
- // This function was causing deopts in Chrome.
198
- function injectTextNode(parentElement, first, index, data) {
199
- try {
200
- insertNode(parentElement, first, index)
201
- first.nodeValue = data
202
- } catch (e) {
203
- // IE erroneously throws error when appending an empty text node
204
- // after a null
205
- }
206
- }
207
-
208
- function flatten(list) {
209
- // recursively flatten array
210
- for (var i = 0; i < list.length; i++) {
211
- if (isArray(list[i])) {
212
- list = list.concat.apply([], list)
213
- // check current index again and flatten until there are no more
214
- // nested arrays at that index
215
- i--
216
- }
217
- }
218
- return list
219
- }
220
-
221
- function insertNode(parentElement, node, index) {
222
- parentElement.insertBefore(node,
223
- parentElement.childNodes[index] || null)
224
- }
225
-
226
- var DELETION = 1
227
- var INSERTION = 2
228
- var MOVE = 3
229
-
230
- function handleKeysDiffer(data, existing, cached, parentElement) {
231
- forKeys(data, function (key, i) {
232
- existing[key = key.key] = existing[key] ? {
233
- action: MOVE,
234
- index: i,
235
- from: existing[key].index,
236
- element: cached.nodes[existing[key].index] ||
237
- $document.createElement("div")
238
- } : {action: INSERTION, index: i}
239
- })
240
-
241
- var actions = []
242
- for (var prop in existing) {
243
- if (hasOwn.call(existing, prop)) {
244
- actions.push(existing[prop])
245
- }
246
- }
247
-
248
- var changes = actions.sort(sortChanges)
249
- var newCached = new Array(cached.length)
250
-
251
- newCached.nodes = cached.nodes.slice()
252
-
253
- forEach(changes, function (change) {
254
- var index = change.index
255
- if (change.action === DELETION) {
256
- clear(cached[index].nodes, cached[index])
257
- newCached.splice(index, 1)
258
- }
259
- if (change.action === INSERTION) {
260
- var dummy = $document.createElement("div")
261
- dummy.key = data[index].attrs.key
262
- insertNode(parentElement, dummy, index)
263
- newCached.splice(index, 0, {
264
- attrs: {key: data[index].attrs.key},
265
- nodes: [dummy]
266
- })
267
- newCached.nodes[index] = dummy
268
- }
269
-
270
- if (change.action === MOVE) {
271
- var changeElement = change.element
272
- var maybeChanged = parentElement.childNodes[index]
273
- if (maybeChanged !== changeElement && changeElement !== null) {
274
- parentElement.insertBefore(changeElement,
275
- maybeChanged || null)
276
- }
277
- newCached[index] = cached[change.from]
278
- newCached.nodes[index] = changeElement
279
- }
280
- })
281
-
282
- return newCached
283
- }
284
-
285
- function diffKeys(data, cached, existing, parentElement) {
286
- var keysDiffer = data.length !== cached.length
287
-
288
- if (!keysDiffer) {
289
- forKeys(data, function (attrs, i) {
290
- var cachedCell = cached[i]
291
- return keysDiffer = cachedCell &&
292
- cachedCell.attrs &&
293
- cachedCell.attrs.key !== attrs.key
294
- })
295
- }
296
-
297
- if (keysDiffer) {
298
- return handleKeysDiffer(data, existing, cached, parentElement)
299
- } else {
300
- return cached
301
- }
302
- }
303
-
304
- function diffArray(data, cached, nodes) {
305
- // diff the array itself
306
-
307
- // update the list of DOM nodes by collecting the nodes from each item
308
- forEach(data, function (_, i) {
309
- if (cached[i] != null) nodes.push.apply(nodes, cached[i].nodes)
310
- })
311
- // remove items from the end of the array if the new array is shorter
312
- // than the old one. if errors ever happen here, the issue is most
313
- // likely a bug in the construction of the `cached` data structure
314
- // somewhere earlier in the program
315
- forEach(cached.nodes, function (node, i) {
316
- if (node.parentNode != null && nodes.indexOf(node) < 0) {
317
- clear([node], [cached[i]])
318
- }
319
- })
320
-
321
- if (data.length < cached.length) cached.length = data.length
322
- cached.nodes = nodes
323
- }
324
-
325
- function buildArrayKeys(data) {
326
- var guid = 0
327
- forKeys(data, function () {
328
- forEach(data, function (attrs) {
329
- if ((attrs = attrs && attrs.attrs) && attrs.key == null) {
330
- attrs.key = "__mithril__" + guid++
331
- }
332
- })
333
- return 1
334
- })
335
- }
336
-
337
- function isDifferentEnough(data, cached, dataAttrKeys) {
338
- if (data.tag !== cached.tag) return true
339
-
340
- if (dataAttrKeys.sort().join() !==
341
- Object.keys(cached.attrs).sort().join()) {
342
- return true
343
- }
344
-
345
- if (data.attrs.id !== cached.attrs.id) {
346
- return true
347
- }
348
-
349
- if (data.attrs.key !== cached.attrs.key) {
350
- return true
351
- }
352
-
353
- if (m.redraw.strategy() === "all") {
354
- return !cached.configContext || cached.configContext.retain !== true
355
- }
356
-
357
- if (m.redraw.strategy() === "diff") {
358
- return cached.configContext && cached.configContext.retain === false
359
- }
360
-
361
- return false
362
- }
363
-
364
- function maybeRecreateObject(data, cached, dataAttrKeys) {
365
- // if an element is different enough from the one in cache, recreate it
366
- if (isDifferentEnough(data, cached, dataAttrKeys)) {
367
- if (cached.nodes.length) clear(cached.nodes)
368
-
369
- if (cached.configContext &&
370
- isFunction(cached.configContext.onunload)) {
371
- cached.configContext.onunload()
372
- }
373
-
374
- if (cached.controllers) {
375
- forEach(cached.controllers, function (controller) {
376
- if (controller.onunload) {
377
- controller.onunload({preventDefault: noop})
378
- }
379
- })
380
- }
381
- }
382
- }
383
-
384
- function getObjectNamespace(data, namespace) {
385
- if (data.attrs.xmlns) return data.attrs.xmlns
386
- if (data.tag === "svg") return "http://www.w3.org/2000/svg"
387
- if (data.tag === "math") return "http://www.w3.org/1998/Math/MathML"
388
- return namespace
389
- }
390
-
391
- var pendingRequests = 0
392
- m.startComputation = function () { pendingRequests++ }
393
- m.endComputation = function () {
394
- if (pendingRequests > 1) {
395
- pendingRequests--
396
- } else {
397
- pendingRequests = 0
398
- m.redraw()
399
- }
400
- }
401
-
402
- function unloadCachedControllers(cached, views, controllers) {
403
- if (controllers.length) {
404
- cached.views = views
405
- cached.controllers = controllers
406
- forEach(controllers, function (controller) {
407
- if (controller.onunload && controller.onunload.$old) {
408
- controller.onunload = controller.onunload.$old
409
- }
410
-
411
- if (pendingRequests && controller.onunload) {
412
- var onunload = controller.onunload
413
- controller.onunload = noop
414
- controller.onunload.$old = onunload
415
- }
416
- })
417
- }
418
- }
419
-
420
- function scheduleConfigsToBeCalled(configs, data, node, isNew, cached) {
421
- // schedule configs to be called. They are called after `build` finishes
422
- // running
423
- if (isFunction(data.attrs.config)) {
424
- var context = cached.configContext = cached.configContext || {}
425
-
426
- // bind
427
- configs.push(function () {
428
- return data.attrs.config.call(data, node, !isNew, context,
429
- cached)
430
- })
431
- }
432
- }
433
-
434
- function buildUpdatedNode(
435
- cached,
436
- data,
437
- editable,
438
- hasKeys,
439
- namespace,
440
- views,
441
- configs,
442
- controllers
443
- ) {
444
- var node = cached.nodes[0]
445
-
446
- if (hasKeys) {
447
- setAttributes(node, data.tag, data.attrs, cached.attrs, namespace)
448
- }
449
-
450
- cached.children = build(
451
- node,
452
- data.tag,
453
- undefined,
454
- undefined,
455
- data.children,
456
- cached.children,
457
- false,
458
- 0,
459
- data.attrs.contenteditable ? node : editable,
460
- namespace,
461
- configs
462
- )
463
-
464
- cached.nodes.intact = true
465
-
466
- if (controllers.length) {
467
- cached.views = views
468
- cached.controllers = controllers
469
- }
470
-
471
- return node
472
- }
473
-
474
- function handleNonexistentNodes(data, parentElement, index) {
475
- var nodes
476
- if (data.$trusted) {
477
- nodes = injectHTML(parentElement, index, data)
478
- } else {
479
- nodes = [$document.createTextNode(data)]
480
- if (!(parentElement.nodeName in voidElements)) {
481
- insertNode(parentElement, nodes[0], index)
482
- }
483
- }
484
-
485
- var cached
486
-
487
- if (typeof data === "string" ||
488
- typeof data === "number" ||
489
- typeof data === "boolean") {
490
- cached = new data.constructor(data)
491
- } else {
492
- cached = data
493
- }
494
-
495
- cached.nodes = nodes
496
- return cached
497
- }
498
-
499
- function reattachNodes(
500
- data,
501
- cached,
502
- parentElement,
503
- editable,
504
- index,
505
- parentTag
506
- ) {
507
- var nodes = cached.nodes
508
- if (!editable || editable !== $document.activeElement) {
509
- if (data.$trusted) {
510
- clear(nodes, cached)
511
- nodes = injectHTML(parentElement, index, data)
512
- } else if (parentTag === "textarea") {
513
- // <textarea> uses `value` instead of `nodeValue`.
514
- parentElement.value = data
515
- } else if (editable) {
516
- // contenteditable nodes use `innerHTML` instead of `nodeValue`.
517
- editable.innerHTML = data
518
- } else {
519
- // was a trusted string
520
- if (nodes[0].nodeType === 1 || nodes.length > 1 ||
521
- (nodes[0].nodeValue.trim &&
522
- !nodes[0].nodeValue.trim())) {
523
- clear(cached.nodes, cached)
524
- nodes = [$document.createTextNode(data)]
525
- }
526
-
527
- injectTextNode(parentElement, nodes[0], index, data)
528
- }
529
- }
530
- cached = new data.constructor(data)
531
- cached.nodes = nodes
532
- return cached
533
- }
534
-
535
- function handleTextNode(
536
- cached,
537
- data,
538
- index,
539
- parentElement,
540
- shouldReattach,
541
- editable,
542
- parentTag
543
- ) {
544
- if (!cached.nodes.length) {
545
- return handleNonexistentNodes(data, parentElement, index)
546
- } else if (cached.valueOf() !== data.valueOf() || shouldReattach) {
547
- return reattachNodes(data, cached, parentElement, editable, index,
548
- parentTag)
549
- } else {
550
- return (cached.nodes.intact = true, cached)
551
- }
552
- }
553
-
554
- function getSubArrayCount(item) {
555
- if (item.$trusted) {
556
- // fix offset of next element if item was a trusted string w/ more
557
- // than one html element
558
- // the first clause in the regexp matches elements
559
- // the second clause (after the pipe) matches text nodes
560
- var match = item.match(/<[^\/]|\>\s*[^<]/g)
561
- if (match != null) return match.length
562
- } else if (isArray(item)) {
563
- return item.length
564
- }
565
- return 1
566
- }
567
-
568
- function buildArray(
569
- data,
570
- cached,
571
- parentElement,
572
- index,
573
- parentTag,
574
- shouldReattach,
575
- editable,
576
- namespace,
577
- configs
578
- ) {
579
- data = flatten(data)
580
- var nodes = []
581
- var intact = cached.length === data.length
582
- var subArrayCount = 0
583
-
584
- // keys algorithm: sort elements without recreating them if keys are
585
- // present
586
- //
587
- // 1) create a map of all existing keys, and mark all for deletion
588
- // 2) add new keys to map and mark them for addition
589
- // 3) if key exists in new list, change action from deletion to a move
590
- // 4) for each key, handle its corresponding action as marked in
591
- // previous steps
592
-
593
- var existing = {}
594
- var shouldMaintainIdentities = false
595
-
596
- forKeys(cached, function (attrs, i) {
597
- shouldMaintainIdentities = true
598
- existing[cached[i].attrs.key] = {action: DELETION, index: i}
599
- })
600
-
601
- buildArrayKeys(data)
602
- if (shouldMaintainIdentities) {
603
- cached = diffKeys(data, cached, existing, parentElement)
604
- }
605
- // end key algorithm
606
-
607
- var cacheCount = 0
608
- // faster explicitly written
609
- for (var i = 0, len = data.length; i < len; i++) {
610
- // diff each item in the array
611
- var item = build(
612
- parentElement,
613
- parentTag,
614
- cached,
615
- index,
616
- data[i],
617
- cached[cacheCount],
618
- shouldReattach,
619
- index + subArrayCount || subArrayCount,
620
- editable,
621
- namespace,
622
- configs)
623
-
624
- if (item !== undefined) {
625
- intact = intact && item.nodes.intact
626
- subArrayCount += getSubArrayCount(item)
627
- cached[cacheCount++] = item
628
- }
629
- }
630
-
631
- if (!intact) diffArray(data, cached, nodes)
632
- return cached
633
- }
634
-
635
- function makeCache(data, cached, index, parentIndex, parentCache) {
636
- if (cached != null) {
637
- if (type.call(cached) === type.call(data)) return cached
638
-
639
- if (parentCache && parentCache.nodes) {
640
- var offset = index - parentIndex
641
- var end = offset + (isArray(data) ? data : cached.nodes).length
642
- clear(
643
- parentCache.nodes.slice(offset, end),
644
- parentCache.slice(offset, end))
645
- } else if (cached.nodes) {
646
- clear(cached.nodes, cached)
647
- }
648
- }
649
-
650
- cached = new data.constructor()
651
- // if constructor creates a virtual dom element, use a blank object as
652
- // the base cached node instead of copying the virtual el (#277)
653
- if (cached.tag) cached = {}
654
- cached.nodes = []
655
- return cached
656
- }
657
-
658
- function constructNode(data, namespace) {
659
- if (data.attrs.is) {
660
- if (namespace == null) {
661
- return $document.createElement(data.tag, data.attrs.is)
662
- } else {
663
- return $document.createElementNS(namespace, data.tag,
664
- data.attrs.is)
665
- }
666
- } else if (namespace == null) {
667
- return $document.createElement(data.tag)
668
- } else {
669
- return $document.createElementNS(namespace, data.tag)
670
- }
671
- }
672
-
673
- function constructAttrs(data, node, namespace, hasKeys) {
674
- if (hasKeys) {
675
- return setAttributes(node, data.tag, data.attrs, {}, namespace)
676
- } else {
677
- return data.attrs
678
- }
679
- }
680
-
681
- function constructChildren(
682
- data,
683
- node,
684
- cached,
685
- editable,
686
- namespace,
687
- configs
688
- ) {
689
- if (data.children != null && data.children.length > 0) {
690
- return build(
691
- node,
692
- data.tag,
693
- undefined,
694
- undefined,
695
- data.children,
696
- cached.children,
697
- true,
698
- 0,
699
- data.attrs.contenteditable ? node : editable,
700
- namespace,
701
- configs)
702
- } else {
703
- return data.children
704
- }
705
- }
706
-
707
- function reconstructCached(
708
- data,
709
- attrs,
710
- children,
711
- node,
712
- namespace,
713
- views,
714
- controllers
715
- ) {
716
- var cached = {
717
- tag: data.tag,
718
- attrs: attrs,
719
- children: children,
720
- nodes: [node]
721
- }
722
-
723
- unloadCachedControllers(cached, views, controllers)
724
-
725
- if (cached.children && !cached.children.nodes) {
726
- cached.children.nodes = []
727
- }
728
-
729
- // edge case: setting value on <select> doesn't work before children
730
- // exist, so set it again after children have been created
731
- if (data.tag === "select" && "value" in data.attrs) {
732
- setAttributes(node, data.tag, {value: data.attrs.value}, {},
733
- namespace)
734
- }
735
-
736
- return cached
737
- }
738
-
739
- function getController(views, view, cachedControllers, controller) {
740
- var controllerIndex
741
-
742
- if (m.redraw.strategy() === "diff" && views) {
743
- controllerIndex = views.indexOf(view)
744
- } else {
745
- controllerIndex = -1
746
- }
747
-
748
- if (controllerIndex > -1) {
749
- return cachedControllers[controllerIndex]
750
- } else if (isFunction(controller)) {
751
- return new controller()
752
- } else {
753
- return {}
754
- }
755
- }
756
-
757
- var unloaders = []
758
-
759
- function updateLists(views, controllers, view, controller) {
760
- if (controller.onunload != null &&
761
- unloaders.map(function (u) { return u.handler })
762
- .indexOf(controller.onunload) < 0) {
763
- unloaders.push({
764
- controller: controller,
765
- handler: controller.onunload
766
- })
767
- }
768
-
769
- views.push(view)
770
- controllers.push(controller)
771
- }
772
-
773
- var forcing = false
774
- function checkView(
775
- data,
776
- view,
777
- cached,
778
- cachedControllers,
779
- controllers,
780
- views
781
- ) {
782
- var controller = getController(
783
- cached.views,
784
- view,
785
- cachedControllers,
786
- data.controller)
787
-
788
- var key = data && data.attrs && data.attrs.key
789
-
790
- if (pendingRequests === 0 ||
791
- forcing ||
792
- cachedControllers &&
793
- cachedControllers.indexOf(controller) > -1) {
794
- data = data.view(controller)
795
- } else {
796
- data = {tag: "placeholder"}
797
- }
798
-
799
- if (data.subtree === "retain") return data
800
- data.attrs = data.attrs || {}
801
- data.attrs.key = key
802
- updateLists(views, controllers, view, controller)
803
- return data
804
- }
805
-
806
- function markViews(data, cached, views, controllers) {
807
- var cachedControllers = cached && cached.controllers
808
-
809
- while (data.view != null) {
810
- data = checkView(
811
- data,
812
- data.view.$original || data.view,
813
- cached,
814
- cachedControllers,
815
- controllers,
816
- views)
817
- }
818
-
819
- return data
820
- }
821
-
822
- function buildObject( // eslint-disable-line max-statements
823
- data,
824
- cached,
825
- editable,
826
- parentElement,
827
- index,
828
- shouldReattach,
829
- namespace,
830
- configs
831
- ) {
832
- var views = []
833
- var controllers = []
834
-
835
- data = markViews(data, cached, views, controllers)
836
-
837
- if (data.subtree === "retain") return cached
838
-
839
- if (!data.tag && controllers.length) {
840
- throw new Error("Component template must return a virtual " +
841
- "element, not an array, string, etc.")
842
- }
843
-
844
- data.attrs = data.attrs || {}
845
- cached.attrs = cached.attrs || {}
846
-
847
- var dataAttrKeys = Object.keys(data.attrs)
848
- var hasKeys = dataAttrKeys.length > ("key" in data.attrs ? 1 : 0)
849
-
850
- maybeRecreateObject(data, cached, dataAttrKeys)
851
-
852
- if (!isString(data.tag)) return
853
-
854
- var isNew = cached.nodes.length === 0
855
-
856
- namespace = getObjectNamespace(data, namespace)
857
-
858
- var node
859
- if (isNew) {
860
- node = constructNode(data, namespace)
861
- // set attributes first, then create children
862
- var attrs = constructAttrs(data, node, namespace, hasKeys)
863
-
864
- // add the node to its parent before attaching children to it
865
- insertNode(parentElement, node, index)
866
-
867
- var children = constructChildren(data, node, cached, editable,
868
- namespace, configs)
869
-
870
- cached = reconstructCached(
871
- data,
872
- attrs,
873
- children,
874
- node,
875
- namespace,
876
- views,
877
- controllers)
878
- } else {
879
- node = buildUpdatedNode(
880
- cached,
881
- data,
882
- editable,
883
- hasKeys,
884
- namespace,
885
- views,
886
- configs,
887
- controllers)
888
- }
889
-
890
- if (!isNew && shouldReattach === true && node != null) {
891
- insertNode(parentElement, node, index)
892
- }
893
-
894
- // The configs are called after `build` finishes running
895
- scheduleConfigsToBeCalled(configs, data, node, isNew, cached)
896
-
897
- return cached
898
- }
899
-
900
- function build(
901
- parentElement,
902
- parentTag,
903
- parentCache,
904
- parentIndex,
905
- data,
906
- cached,
907
- shouldReattach,
908
- index,
909
- editable,
910
- namespace,
911
- configs
912
- ) {
913
- /*
914
- * `build` is a recursive function that manages creation/diffing/removal
915
- * of DOM elements based on comparison between `data` and `cached` the
916
- * diff algorithm can be summarized as this:
917
- *
918
- * 1 - compare `data` and `cached`
919
- * 2 - if they are different, copy `data` to `cached` and update the DOM
920
- * based on what the difference is
921
- * 3 - recursively apply this algorithm for every array and for the
922
- * children of every virtual element
923
- *
924
- * The `cached` data structure is essentially the same as the previous
925
- * redraw's `data` data structure, with a few additions:
926
- * - `cached` always has a property called `nodes`, which is a list of
927
- * DOM elements that correspond to the data represented by the
928
- * respective virtual element
929
- * - in order to support attaching `nodes` as a property of `cached`,
930
- * `cached` is *always* a non-primitive object, i.e. if the data was
931
- * a string, then cached is a String instance. If data was `null` or
932
- * `undefined`, cached is `new String("")`
933
- * - `cached also has a `configContext` property, which is the state
934
- * storage object exposed by config(element, isInitialized, context)
935
- * - when `cached` is an Object, it represents a virtual element; when
936
- * it's an Array, it represents a list of elements; when it's a
937
- * String, Number or Boolean, it represents a text node
938
- *
939
- * `parentElement` is a DOM element used for W3C DOM API calls
940
- * `parentTag` is only used for handling a corner case for textarea
941
- * values
942
- * `parentCache` is used to remove nodes in some multi-node cases
943
- * `parentIndex` and `index` are used to figure out the offset of nodes.
944
- * They're artifacts from before arrays started being flattened and are
945
- * likely refactorable
946
- * `data` and `cached` are, respectively, the new and old nodes being
947
- * diffed
948
- * `shouldReattach` is a flag indicating whether a parent node was
949
- * recreated (if so, and if this node is reused, then this node must
950
- * reattach itself to the new parent)
951
- * `editable` is a flag that indicates whether an ancestor is
952
- * contenteditable
953
- * `namespace` indicates the closest HTML namespace as it cascades down
954
- * from an ancestor
955
- * `configs` is a list of config functions to run after the topmost
956
- * `build` call finishes running
957
- *
958
- * there's logic that relies on the assumption that null and undefined
959
- * data are equivalent to empty strings
960
- * - this prevents lifecycle surprises from procedural helpers that mix
961
- * implicit and explicit return statements (e.g.
962
- * function foo() {if (cond) return m("div")}
963
- * - it simplifies diffing code
964
- */
965
- data = dataToString(data)
966
- if (data.subtree === "retain") return cached
967
- cached = makeCache(data, cached, index, parentIndex, parentCache)
968
-
969
- if (isArray(data)) {
970
- return buildArray(
971
- data,
972
- cached,
973
- parentElement,
974
- index,
975
- parentTag,
976
- shouldReattach,
977
- editable,
978
- namespace,
979
- configs)
980
- } else if (data != null && isObject(data)) {
981
- return buildObject(
982
- data,
983
- cached,
984
- editable,
985
- parentElement,
986
- index,
987
- shouldReattach,
988
- namespace,
989
- configs)
990
- } else if (!isFunction(data)) {
991
- return handleTextNode(
992
- cached,
993
- data,
994
- index,
995
- parentElement,
996
- shouldReattach,
997
- editable,
998
- parentTag)
999
- } else {
1000
- return cached
1001
- }
1002
- }
1003
-
1004
- function sortChanges(a, b) {
1005
- return a.action - b.action || a.index - b.index
1006
- }
1007
-
1008
- function copyStyleAttrs(node, dataAttr, cachedAttr) {
1009
- for (var rule in dataAttr) {
1010
- if (hasOwn.call(dataAttr, rule)) {
1011
- if (cachedAttr == null || cachedAttr[rule] !== dataAttr[rule]) {
1012
- node.style[rule] = dataAttr[rule]
1013
- }
1014
- }
1015
- }
1016
-
1017
- for (rule in cachedAttr) {
1018
- if (hasOwn.call(cachedAttr, rule)) {
1019
- if (!hasOwn.call(dataAttr, rule)) node.style[rule] = ""
1020
- }
1021
- }
1022
- }
1023
-
1024
- var shouldUseSetAttribute = {
1025
- list: 1,
1026
- style: 1,
1027
- form: 1,
1028
- type: 1,
1029
- width: 1,
1030
- height: 1
1031
- }
1032
-
1033
- function setSingleAttr(
1034
- node,
1035
- attrName,
1036
- dataAttr,
1037
- cachedAttr,
1038
- tag,
1039
- namespace
1040
- ) {
1041
- if (attrName === "config" || attrName === "key") {
1042
- // `config` isn't a real attribute, so ignore it
1043
- return true
1044
- } else if (isFunction(dataAttr) && attrName.slice(0, 2) === "on") {
1045
- // hook event handlers to the auto-redrawing system
1046
- node[attrName] = autoredraw(dataAttr, node)
1047
- } else if (attrName === "style" && dataAttr != null &&
1048
- isObject(dataAttr)) {
1049
- // handle `style: {...}`
1050
- copyStyleAttrs(node, dataAttr, cachedAttr)
1051
- } else if (namespace != null) {
1052
- // handle SVG
1053
- if (attrName === "href") {
1054
- node.setAttributeNS("http://www.w3.org/1999/xlink",
1055
- "href", dataAttr)
1056
- } else {
1057
- node.setAttribute(
1058
- attrName === "className" ? "class" : attrName,
1059
- dataAttr)
1060
- }
1061
- } else if (attrName in node && !shouldUseSetAttribute[attrName]) {
1062
- // handle cases that are properties (but ignore cases where we
1063
- // should use setAttribute instead)
1064
- //
1065
- // - list and form are typically used as strings, but are DOM
1066
- // element references in js
1067
- //
1068
- // - when using CSS selectors (e.g. `m("[style='']")`), style is
1069
- // used as a string, but it's an object in js
1070
- //
1071
- // #348 don't set the value if not needed - otherwise, cursor
1072
- // placement breaks in Chrome
1073
- try {
1074
- if (tag !== "input" || node[attrName] !== dataAttr) {
1075
- node[attrName] = dataAttr
1076
- }
1077
- } catch (e) {
1078
- node.setAttribute(attrName, dataAttr)
1079
- }
1080
- }
1081
- else node.setAttribute(attrName, dataAttr)
1082
- }
1083
-
1084
- function trySetAttr(
1085
- node,
1086
- attrName,
1087
- dataAttr,
1088
- cachedAttr,
1089
- cachedAttrs,
1090
- tag,
1091
- namespace
1092
- ) {
1093
- if (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr) || ($document.activeElement === node)) {
1094
- cachedAttrs[attrName] = dataAttr
1095
- try {
1096
- return setSingleAttr(
1097
- node,
1098
- attrName,
1099
- dataAttr,
1100
- cachedAttr,
1101
- tag,
1102
- namespace)
1103
- } catch (e) {
1104
- // swallow IE's invalid argument errors to mimic HTML's
1105
- // fallback-to-doing-nothing-on-invalid-attributes behavior
1106
- if (e.message.indexOf("Invalid argument") < 0) throw e
1107
- }
1108
- } else if (attrName === "value" && tag === "input" &&
1109
- node.value !== dataAttr) {
1110
- // #348 dataAttr may not be a string, so use loose comparison
1111
- node.value = dataAttr
1112
- }
1113
- }
1114
-
1115
- function setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) {
1116
- for (var attrName in dataAttrs) {
1117
- if (hasOwn.call(dataAttrs, attrName)) {
1118
- if (trySetAttr(
1119
- node,
1120
- attrName,
1121
- dataAttrs[attrName],
1122
- cachedAttrs[attrName],
1123
- cachedAttrs,
1124
- tag,
1125
- namespace)) {
1126
- continue
1127
- }
1128
- }
1129
- }
1130
- return cachedAttrs
1131
- }
1132
-
1133
- function clear(nodes, cached) {
1134
- for (var i = nodes.length - 1; i > -1; i--) {
1135
- if (nodes[i] && nodes[i].parentNode) {
1136
- try {
1137
- nodes[i].parentNode.removeChild(nodes[i])
1138
- } catch (e) {
1139
- /* eslint-disable max-len */
1140
- // ignore if this fails due to order of events (see
1141
- // http://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node)
1142
- /* eslint-enable max-len */
1143
- }
1144
- cached = [].concat(cached)
1145
- if (cached[i]) unload(cached[i])
1146
- }
1147
- }
1148
- // release memory if nodes is an array. This check should fail if nodes
1149
- // is a NodeList (see loop above)
1150
- if (nodes.length) {
1151
- nodes.length = 0
1152
- }
1153
- }
1154
-
1155
- function unload(cached) {
1156
- if (cached.configContext && isFunction(cached.configContext.onunload)) {
1157
- cached.configContext.onunload()
1158
- cached.configContext.onunload = null
1159
- }
1160
- if (cached.controllers) {
1161
- forEach(cached.controllers, function (controller) {
1162
- if (isFunction(controller.onunload)) {
1163
- controller.onunload({preventDefault: noop})
1164
- }
1165
- })
1166
- }
1167
- if (cached.children) {
1168
- if (isArray(cached.children)) forEach(cached.children, unload)
1169
- else if (cached.children.tag) unload(cached.children)
1170
- }
1171
- }
1172
-
1173
- function appendTextFragment(parentElement, data) {
1174
- try {
1175
- parentElement.appendChild(
1176
- $document.createRange().createContextualFragment(data))
1177
- } catch (e) {
1178
- parentElement.insertAdjacentHTML("beforeend", data)
1179
- replaceScriptNodes(parentElement)
1180
- }
1181
- }
1182
-
1183
- // Replace script tags inside given DOM element with executable ones.
1184
- // Will also check children recursively and replace any found script
1185
- // tags in same manner.
1186
- function replaceScriptNodes(node) {
1187
- if (node.tagName === "SCRIPT") {
1188
- node.parentNode.replaceChild(buildExecutableNode(node), node)
1189
- } else {
1190
- var children = node.childNodes
1191
- if (children && children.length) {
1192
- for (var i = 0; i < children.length; i++) {
1193
- replaceScriptNodes(children[i])
1194
- }
1195
- }
1196
- }
1197
-
1198
- return node
1199
- }
1200
-
1201
- // Replace script element with one whose contents are executable.
1202
- function buildExecutableNode(node){
1203
- var scriptEl = document.createElement("script")
1204
- var attrs = node.attributes
1205
-
1206
- for (var i = 0; i < attrs.length; i++) {
1207
- scriptEl.setAttribute(attrs[i].name, attrs[i].value)
1208
- }
1209
-
1210
- scriptEl.text = node.innerHTML
1211
- return scriptEl
1212
- }
1213
-
1214
- function injectHTML(parentElement, index, data) {
1215
- var nextSibling = parentElement.childNodes[index]
1216
- if (nextSibling) {
1217
- var isElement = nextSibling.nodeType !== 1
1218
- var placeholder = $document.createElement("span")
1219
- if (isElement) {
1220
- parentElement.insertBefore(placeholder, nextSibling || null)
1221
- placeholder.insertAdjacentHTML("beforebegin", data)
1222
- parentElement.removeChild(placeholder)
1223
- } else {
1224
- nextSibling.insertAdjacentHTML("beforebegin", data)
1225
- }
1226
- } else {
1227
- appendTextFragment(parentElement, data)
1228
- }
1229
-
1230
- var nodes = []
1231
-
1232
- while (parentElement.childNodes[index] !== nextSibling) {
1233
- nodes.push(parentElement.childNodes[index])
1234
- index++
1235
- }
1236
-
1237
- return nodes
1238
- }
1239
-
1240
- function autoredraw(callback, object) {
1241
- return function (e) {
1242
- e = e || event
1243
- m.redraw.strategy("diff")
1244
- m.startComputation()
1245
- try {
1246
- return callback.call(object, e)
1247
- } finally {
1248
- endFirstComputation()
1249
- }
1250
- }
1251
- }
1252
-
1253
- var html
1254
- var documentNode = {
1255
- appendChild: function (node) {
1256
- if (html === undefined) html = $document.createElement("html")
1257
- if ($document.documentElement &&
1258
- $document.documentElement !== node) {
1259
- $document.replaceChild(node, $document.documentElement)
1260
- } else {
1261
- $document.appendChild(node)
1262
- }
1263
-
1264
- this.childNodes = $document.childNodes
1265
- },
1266
-
1267
- insertBefore: function (node) {
1268
- this.appendChild(node)
1269
- },
1270
-
1271
- childNodes: []
1272
- }
1273
-
1274
- var nodeCache = []
1275
- var cellCache = {}
1276
-
1277
- m.render = function (root, cell, forceRecreation) {
1278
- if (!root) {
1279
- throw new Error("Ensure the DOM element being passed to " +
1280
- "m.route/m.mount/m.render is not undefined.")
1281
- }
1282
- var configs = []
1283
- var id = getCellCacheKey(root)
1284
- var isDocumentRoot = root === $document
1285
- var node
1286
-
1287
- if (isDocumentRoot || root === $document.documentElement) {
1288
- node = documentNode
1289
- } else {
1290
- node = root
1291
- }
1292
-
1293
- if (isDocumentRoot && cell.tag !== "html") {
1294
- cell = {tag: "html", attrs: {}, children: cell}
1295
- }
1296
-
1297
- if (cellCache[id] === undefined) clear(node.childNodes)
1298
- if (forceRecreation === true) reset(root)
1299
-
1300
- cellCache[id] = build(
1301
- node,
1302
- null,
1303
- undefined,
1304
- undefined,
1305
- cell,
1306
- cellCache[id],
1307
- false,
1308
- 0,
1309
- null,
1310
- undefined,
1311
- configs)
1312
-
1313
- forEach(configs, function (config) { config() })
1314
- }
1315
-
1316
- function getCellCacheKey(element) {
1317
- var index = nodeCache.indexOf(element)
1318
- return index < 0 ? nodeCache.push(element) - 1 : index
1319
- }
1320
-
1321
- m.trust = function (value) {
1322
- value = new String(value) // eslint-disable-line no-new-wrappers
1323
- value.$trusted = true
1324
- return value
1325
- }
1326
-
1327
- function gettersetter(store) {
1328
- function prop() {
1329
- if (arguments.length) store = arguments[0]
1330
- return store
1331
- }
1332
-
1333
- prop.toJSON = function () {
1334
- return store
1335
- }
1336
-
1337
- return prop
1338
- }
1339
-
1340
- m.prop = function (store) {
1341
- if ((store != null && (isObject(store) || isFunction(store)) || ((typeof Promise !== "undefined") && (store instanceof Promise))) &&
1342
- isFunction(store.then)) {
1343
- return propify(store)
1344
- }
1345
-
1346
- return gettersetter(store)
1347
- }
1348
-
1349
- var roots = []
1350
- var components = []
1351
- var controllers = []
1352
- var lastRedrawId = null
1353
- var lastRedrawCallTime = 0
1354
- var computePreRedrawHook = null
1355
- var computePostRedrawHook = null
1356
- var topComponent
1357
- var FRAME_BUDGET = 16 // 60 frames per second = 1 call per 16 ms
1358
-
1359
- function parameterize(component, args) {
1360
- function controller() {
1361
- /* eslint-disable no-invalid-this */
1362
- return (component.controller || noop).apply(this, args) || this
1363
- /* eslint-enable no-invalid-this */
1364
- }
1365
-
1366
- if (component.controller) {
1367
- controller.prototype = component.controller.prototype
1368
- }
1369
-
1370
- function view(ctrl) {
1371
- var currentArgs = [ctrl].concat(args)
1372
- for (var i = 1; i < arguments.length; i++) {
1373
- currentArgs.push(arguments[i])
1374
- }
1375
-
1376
- return component.view.apply(component, currentArgs)
1377
- }
1378
-
1379
- view.$original = component.view
1380
- var output = {controller: controller, view: view}
1381
- if (args[0] && args[0].key != null) output.attrs = {key: args[0].key}
1382
- return output
1383
- }
1384
-
1385
- m.component = function (component) {
1386
- var args = new Array(arguments.length - 1)
1387
-
1388
- for (var i = 1; i < arguments.length; i++) {
1389
- args[i - 1] = arguments[i]
1390
- }
1391
-
1392
- return parameterize(component, args)
1393
- }
1394
-
1395
- function checkPrevented(component, root, index, isPrevented) {
1396
- if (!isPrevented) {
1397
- m.redraw.strategy("all")
1398
- m.startComputation()
1399
- roots[index] = root
1400
- var currentComponent
1401
-
1402
- if (component) {
1403
- currentComponent = topComponent = component
1404
- } else {
1405
- currentComponent = topComponent = component = {controller: noop}
1406
- }
1407
-
1408
- var controller = new (component.controller || noop)()
1409
-
1410
- // controllers may call m.mount recursively (via m.route redirects,
1411
- // for example)
1412
- // this conditional ensures only the last recursive m.mount call is
1413
- // applied
1414
- if (currentComponent === topComponent) {
1415
- controllers[index] = controller
1416
- components[index] = component
1417
- }
1418
- endFirstComputation()
1419
- if (component === null) {
1420
- removeRootElement(root, index)
1421
- }
1422
- return controllers[index]
1423
- } else if (component == null) {
1424
- removeRootElement(root, index)
1425
- }
1426
- }
1427
-
1428
- m.mount = m.module = function (root, component) {
1429
- if (!root) {
1430
- throw new Error("Please ensure the DOM element exists before " +
1431
- "rendering a template into it.")
1432
- }
1433
-
1434
- var index = roots.indexOf(root)
1435
- if (index < 0) index = roots.length
1436
-
1437
- var isPrevented = false
1438
- var event = {
1439
- preventDefault: function () {
1440
- isPrevented = true
1441
- computePreRedrawHook = computePostRedrawHook = null
1442
- }
1443
- }
1444
-
1445
- forEach(unloaders, function (unloader) {
1446
- unloader.handler.call(unloader.controller, event)
1447
- unloader.controller.onunload = null
1448
- })
1449
-
1450
- if (isPrevented) {
1451
- forEach(unloaders, function (unloader) {
1452
- unloader.controller.onunload = unloader.handler
1453
- })
1454
- } else {
1455
- unloaders = []
1456
- }
1457
-
1458
- if (controllers[index] && isFunction(controllers[index].onunload)) {
1459
- controllers[index].onunload(event)
1460
- }
1461
-
1462
- return checkPrevented(component, root, index, isPrevented)
1463
- }
1464
-
1465
- function removeRootElement(root, index) {
1466
- roots.splice(index, 1)
1467
- controllers.splice(index, 1)
1468
- components.splice(index, 1)
1469
- reset(root)
1470
- nodeCache.splice(getCellCacheKey(root), 1)
1471
- }
1472
-
1473
- var redrawing = false
1474
- m.redraw = function (force) {
1475
- if (redrawing) return
1476
- redrawing = true
1477
- if (force) forcing = true
1478
-
1479
- try {
1480
- // lastRedrawId is a positive number if a second redraw is requested
1481
- // before the next animation frame
1482
- // lastRedrawId is null if it's the first redraw and not an event
1483
- // handler
1484
- if (lastRedrawId && !force) {
1485
- // when setTimeout: only reschedule redraw if time between now
1486
- // and previous redraw is bigger than a frame, otherwise keep
1487
- // currently scheduled timeout
1488
- // when rAF: always reschedule redraw
1489
- if ($requestAnimationFrame === global.requestAnimationFrame ||
1490
- new Date() - lastRedrawCallTime > FRAME_BUDGET) {
1491
- if (lastRedrawId > 0) $cancelAnimationFrame(lastRedrawId)
1492
- lastRedrawId = $requestAnimationFrame(redraw, FRAME_BUDGET)
1493
- }
1494
- } else {
1495
- redraw()
1496
- lastRedrawId = $requestAnimationFrame(function () {
1497
- lastRedrawId = null
1498
- }, FRAME_BUDGET)
1499
- }
1500
- } finally {
1501
- redrawing = forcing = false
1502
- }
1503
- }
1504
-
1505
- m.redraw.strategy = m.prop()
1506
- function redraw() {
1507
- if (computePreRedrawHook) {
1508
- computePreRedrawHook()
1509
- computePreRedrawHook = null
1510
- }
1511
- forEach(roots, function (root, i) {
1512
- var component = components[i]
1513
- if (controllers[i]) {
1514
- var args = [controllers[i]]
1515
- m.render(root,
1516
- component.view ? component.view(controllers[i], args) : "")
1517
- }
1518
- })
1519
- // after rendering within a routed context, we need to scroll back to
1520
- // the top, and fetch the document title for history.pushState
1521
- if (computePostRedrawHook) {
1522
- computePostRedrawHook()
1523
- computePostRedrawHook = null
1524
- }
1525
- lastRedrawId = null
1526
- lastRedrawCallTime = new Date()
1527
- m.redraw.strategy("diff")
1528
- }
1529
-
1530
- function endFirstComputation() {
1531
- if (m.redraw.strategy() === "none") {
1532
- pendingRequests--
1533
- m.redraw.strategy("diff")
1534
- } else {
1535
- m.endComputation()
1536
- }
1537
- }
1538
-
1539
- m.withAttr = function (prop, withAttrCallback, callbackThis) {
1540
- return function (e) {
1541
- e = e || window.event
1542
- /* eslint-disable no-invalid-this */
1543
- var currentTarget = e.currentTarget || this
1544
- var _this = callbackThis || this
1545
- /* eslint-enable no-invalid-this */
1546
- var target = prop in currentTarget ?
1547
- currentTarget[prop] :
1548
- currentTarget.getAttribute(prop)
1549
- withAttrCallback.call(_this, target)
1550
- }
1551
- }
1552
-
1553
- // routing
1554
- var modes = {pathname: "", hash: "#", search: "?"}
1555
- var redirect = noop
1556
- var isDefaultRoute = false
1557
- var routeParams, currentRoute
1558
-
1559
- m.route = function (root, arg1, arg2, vdom) { // eslint-disable-line
1560
- // m.route()
1561
- if (arguments.length === 0) return currentRoute
1562
- // m.route(el, defaultRoute, routes)
1563
- if (arguments.length === 3 && isString(arg1)) {
1564
- redirect = function (source) {
1565
- var path = currentRoute = normalizeRoute(source)
1566
- if (!routeByValue(root, arg2, path)) {
1567
- if (isDefaultRoute) {
1568
- throw new Error("Ensure the default route matches " +
1569
- "one of the routes defined in m.route")
1570
- }
1571
-
1572
- isDefaultRoute = true
1573
- m.route(arg1, true)
1574
- isDefaultRoute = false
1575
- }
1576
- }
1577
-
1578
- var listener = m.route.mode === "hash" ?
1579
- "onhashchange" :
1580
- "onpopstate"
1581
-
1582
- global[listener] = function () {
1583
- var path = $location[m.route.mode]
1584
- if (m.route.mode === "pathname") path += $location.search
1585
- if (currentRoute !== normalizeRoute(path)) redirect(path)
1586
- }
1587
-
1588
- computePreRedrawHook = setScroll
1589
- global[listener]()
1590
-
1591
- return
1592
- }
1593
-
1594
- // config: m.route
1595
- if (root.addEventListener || root.attachEvent) {
1596
- var base = m.route.mode !== "pathname" ? $location.pathname : ""
1597
- root.href = base + modes[m.route.mode] + vdom.attrs.href
1598
- if (root.addEventListener) {
1599
- root.removeEventListener("click", routeUnobtrusive)
1600
- root.addEventListener("click", routeUnobtrusive)
1601
- } else {
1602
- root.detachEvent("onclick", routeUnobtrusive)
1603
- root.attachEvent("onclick", routeUnobtrusive)
1604
- }
1605
-
1606
- return
1607
- }
1608
- // m.route(route, params, shouldReplaceHistoryEntry)
1609
- if (isString(root)) {
1610
- var oldRoute = currentRoute
1611
- currentRoute = root
1612
-
1613
- var args = arg1 || {}
1614
- var queryIndex = currentRoute.indexOf("?")
1615
- var params
1616
-
1617
- if (queryIndex > -1) {
1618
- params = parseQueryString(currentRoute.slice(queryIndex + 1))
1619
- } else {
1620
- params = {}
1621
- }
1622
-
1623
- for (var i in args) {
1624
- if (hasOwn.call(args, i)) {
1625
- params[i] = args[i]
1626
- }
1627
- }
1628
-
1629
- var querystring = buildQueryString(params)
1630
- var currentPath
1631
-
1632
- if (queryIndex > -1) {
1633
- currentPath = currentRoute.slice(0, queryIndex)
1634
- } else {
1635
- currentPath = currentRoute
1636
- }
1637
-
1638
- if (querystring) {
1639
- currentRoute = currentPath +
1640
- (currentPath.indexOf("?") === -1 ? "?" : "&") +
1641
- querystring
1642
- }
1643
-
1644
- var replaceHistory =
1645
- (arguments.length === 3 ? arg2 : arg1) === true ||
1646
- oldRoute === root
1647
-
1648
- if (global.history.pushState) {
1649
- var method = replaceHistory ? "replaceState" : "pushState"
1650
- computePreRedrawHook = setScroll
1651
- computePostRedrawHook = function () {
1652
- try {
1653
- global.history[method](null, $document.title,
1654
- modes[m.route.mode] + currentRoute)
1655
- } catch (err) {
1656
- // In the event of a pushState or replaceState failure,
1657
- // fallback to a standard redirect. This is specifically
1658
- // to address a Safari security error when attempting to
1659
- // call pushState more than 100 times.
1660
- $location[m.route.mode] = currentRoute
1661
- }
1662
- }
1663
- redirect(modes[m.route.mode] + currentRoute)
1664
- } else {
1665
- $location[m.route.mode] = currentRoute
1666
- redirect(modes[m.route.mode] + currentRoute)
1667
- }
1668
- }
1669
- }
1670
-
1671
- m.route.param = function (key) {
1672
- if (!routeParams) {
1673
- throw new Error("You must call m.route(element, defaultRoute, " +
1674
- "routes) before calling m.route.param()")
1675
- }
1676
-
1677
- if (!key) {
1678
- return routeParams
1679
- }
1680
-
1681
- return routeParams[key]
1682
- }
1683
-
1684
- m.route.mode = "search"
1685
-
1686
- function normalizeRoute(route) {
1687
- return route.slice(modes[m.route.mode].length)
1688
- }
1689
-
1690
- function routeByValue(root, router, path) {
1691
- routeParams = {}
1692
-
1693
- var queryStart = path.indexOf("?")
1694
- if (queryStart !== -1) {
1695
- routeParams = parseQueryString(
1696
- path.substr(queryStart + 1, path.length))
1697
- path = path.substr(0, queryStart)
1698
- }
1699
-
1700
- // Get all routes and check if there's
1701
- // an exact match for the current path
1702
- var keys = Object.keys(router)
1703
- var index = keys.indexOf(path)
1704
-
1705
- if (index !== -1){
1706
- m.mount(root, router[keys [index]])
1707
- return true
1708
- }
1709
-
1710
- for (var route in router) {
1711
- if (hasOwn.call(router, route)) {
1712
- if (route === path) {
1713
- m.mount(root, router[route])
1714
- return true
1715
- }
1716
-
1717
- var matcher = new RegExp("^" + route
1718
- .replace(/:[^\/]+?\.{3}/g, "(.*?)")
1719
- .replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
1720
-
1721
- if (matcher.test(path)) {
1722
- /* eslint-disable no-loop-func */
1723
- path.replace(matcher, function () {
1724
- var keys = route.match(/:[^\/]+/g) || []
1725
- var values = [].slice.call(arguments, 1, -2)
1726
- forEach(keys, function (key, i) {
1727
- routeParams[key.replace(/:|\./g, "")] =
1728
- decodeURIComponent(values[i])
1729
- })
1730
- m.mount(root, router[route])
1731
- })
1732
- /* eslint-enable no-loop-func */
1733
- return true
1734
- }
1735
- }
1736
- }
1737
- }
1738
-
1739
- function routeUnobtrusive(e) {
1740
- e = e || event
1741
- if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return
1742
-
1743
- if (e.preventDefault) {
1744
- e.preventDefault()
1745
- } else {
1746
- e.returnValue = false
1747
- }
1748
-
1749
- var currentTarget = e.currentTarget || e.srcElement
1750
- var args
1751
-
1752
- if (m.route.mode === "pathname" && currentTarget.search) {
1753
- args = parseQueryString(currentTarget.search.slice(1))
1754
- } else {
1755
- args = {}
1756
- }
1757
-
1758
- while (currentTarget && !/a/i.test(currentTarget.nodeName)) {
1759
- currentTarget = currentTarget.parentNode
1760
- }
1761
-
1762
- // clear pendingRequests because we want an immediate route change
1763
- pendingRequests = 0
1764
- m.route(currentTarget[m.route.mode]
1765
- .slice(modes[m.route.mode].length), args)
1766
- }
1767
-
1768
- function setScroll() {
1769
- if (m.route.mode !== "hash" && $location.hash) {
1770
- $location.hash = $location.hash
1771
- } else {
1772
- global.scrollTo(0, 0)
1773
- }
1774
- }
1775
-
1776
- function buildQueryString(object, prefix) {
1777
- var duplicates = {}
1778
- var str = []
1779
-
1780
- for (var prop in object) {
1781
- if (hasOwn.call(object, prop)) {
1782
- var key = prefix ? prefix + "[" + prop + "]" : prop
1783
- var value = object[prop]
1784
-
1785
- if (value === null) {
1786
- str.push(encodeURIComponent(key))
1787
- } else if (isObject(value)) {
1788
- str.push(buildQueryString(value, key))
1789
- } else if (isArray(value)) {
1790
- var keys = []
1791
- duplicates[key] = duplicates[key] || {}
1792
- /* eslint-disable no-loop-func */
1793
- forEach(value, function (item) {
1794
- /* eslint-enable no-loop-func */
1795
- if (!duplicates[key][item]) {
1796
- duplicates[key][item] = true
1797
- keys.push(encodeURIComponent(key) + "=" +
1798
- encodeURIComponent(item))
1799
- }
1800
- })
1801
- str.push(keys.join("&"))
1802
- } else if (value !== undefined) {
1803
- str.push(encodeURIComponent(key) + "=" +
1804
- encodeURIComponent(value))
1805
- }
1806
- }
1807
- }
1808
-
1809
- return str.join("&")
1810
- }
1811
-
1812
- function parseQueryString(str) {
1813
- if (str === "" || str == null) return {}
1814
- if (str.charAt(0) === "?") str = str.slice(1)
1815
-
1816
- var pairs = str.split("&")
1817
- var params = {}
1818
-
1819
- forEach(pairs, function (string) {
1820
- var pair = string.split("=")
1821
- var key = decodeURIComponent(pair[0])
1822
- var value = pair.length === 2 ? decodeURIComponent(pair[1]) : null
1823
- if (params[key] != null) {
1824
- if (!isArray(params[key])) params[key] = [params[key]]
1825
- params[key].push(value)
1826
- }
1827
- else params[key] = value
1828
- })
1829
-
1830
- return params
1831
- }
1832
-
1833
- m.route.buildQueryString = buildQueryString
1834
- m.route.parseQueryString = parseQueryString
1835
-
1836
- function reset(root) {
1837
- var cacheKey = getCellCacheKey(root)
1838
- clear(root.childNodes, cellCache[cacheKey])
1839
- cellCache[cacheKey] = undefined
1840
- }
1841
-
1842
- m.deferred = function () {
1843
- var deferred = new Deferred()
1844
- deferred.promise = propify(deferred.promise)
1845
- return deferred
1846
- }
1847
-
1848
- function propify(promise, initialValue) {
1849
- var prop = m.prop(initialValue)
1850
- promise.then(prop)
1851
- prop.then = function (resolve, reject) {
1852
- return propify(promise.then(resolve, reject), initialValue)
1853
- }
1854
-
1855
- prop.catch = prop.then.bind(null, null)
1856
- return prop
1857
- }
1858
- // Promiz.mithril.js | Zolmeister | MIT
1859
- // a modified version of Promiz.js, which does not conform to Promises/A+
1860
- // for two reasons:
1861
- //
1862
- // 1) `then` callbacks are called synchronously (because setTimeout is too
1863
- // slow, and the setImmediate polyfill is too big
1864
- //
1865
- // 2) throwing subclasses of Error cause the error to be bubbled up instead
1866
- // of triggering rejection (because the spec does not account for the
1867
- // important use case of default browser error handling, i.e. message w/
1868
- // line number)
1869
-
1870
- var RESOLVING = 1
1871
- var REJECTING = 2
1872
- var RESOLVED = 3
1873
- var REJECTED = 4
1874
-
1875
- function Deferred(onSuccess, onFailure) {
1876
- var self = this
1877
- var state = 0
1878
- var promiseValue = 0
1879
- var next = []
1880
-
1881
- self.promise = {}
1882
-
1883
- self.resolve = function (value) {
1884
- if (!state) {
1885
- promiseValue = value
1886
- state = RESOLVING
1887
-
1888
- fire()
1889
- }
1890
-
1891
- return self
1892
- }
1893
-
1894
- self.reject = function (value) {
1895
- if (!state) {
1896
- promiseValue = value
1897
- state = REJECTING
1898
-
1899
- fire()
1900
- }
1901
-
1902
- return self
1903
- }
1904
-
1905
- self.promise.then = function (onSuccess, onFailure) {
1906
- var deferred = new Deferred(onSuccess, onFailure)
1907
-
1908
- if (state === RESOLVED) {
1909
- deferred.resolve(promiseValue)
1910
- } else if (state === REJECTED) {
1911
- deferred.reject(promiseValue)
1912
- } else {
1913
- next.push(deferred)
1914
- }
1915
-
1916
- return deferred.promise
1917
- }
1918
-
1919
- function finish(type) {
1920
- state = type || REJECTED
1921
- next.map(function (deferred) {
1922
- if (state === RESOLVED) {
1923
- deferred.resolve(promiseValue)
1924
- } else {
1925
- deferred.reject(promiseValue)
1926
- }
1927
- })
1928
- }
1929
-
1930
- function thennable(then, success, failure, notThennable) {
1931
- if (((promiseValue != null && isObject(promiseValue)) ||
1932
- isFunction(promiseValue)) && isFunction(then)) {
1933
- try {
1934
- // count protects against abuse calls from spec checker
1935
- var count = 0
1936
- then.call(promiseValue, function (value) {
1937
- if (count++) return
1938
- promiseValue = value
1939
- success()
1940
- }, function (value) {
1941
- if (count++) return
1942
- promiseValue = value
1943
- failure()
1944
- })
1945
- } catch (e) {
1946
- m.deferred.onerror(e)
1947
- promiseValue = e
1948
- failure()
1949
- }
1950
- } else {
1951
- notThennable()
1952
- }
1953
- }
1954
-
1955
- function fire() {
1956
- // check if it's a thenable
1957
- var then
1958
- try {
1959
- then = promiseValue && promiseValue.then
1960
- } catch (e) {
1961
- m.deferred.onerror(e)
1962
- promiseValue = e
1963
- state = REJECTING
1964
- return fire()
1965
- }
1966
-
1967
- if (state === REJECTING) {
1968
- m.deferred.onerror(promiseValue)
1969
- }
1970
-
1971
- thennable(then, function () {
1972
- state = RESOLVING
1973
- fire()
1974
- }, function () {
1975
- state = REJECTING
1976
- fire()
1977
- }, function () {
1978
- try {
1979
- if (state === RESOLVING && isFunction(onSuccess)) {
1980
- promiseValue = onSuccess(promiseValue)
1981
- } else if (state === REJECTING && isFunction(onFailure)) {
1982
- promiseValue = onFailure(promiseValue)
1983
- state = RESOLVING
1984
- }
1985
- } catch (e) {
1986
- m.deferred.onerror(e)
1987
- promiseValue = e
1988
- return finish()
1989
- }
1990
-
1991
- if (promiseValue === self) {
1992
- promiseValue = TypeError()
1993
- finish()
1994
- } else {
1995
- thennable(then, function () {
1996
- finish(RESOLVED)
1997
- }, finish, function () {
1998
- finish(state === RESOLVING && RESOLVED)
1999
- })
2000
- }
2001
- })
2002
- }
2003
- }
2004
-
2005
- m.deferred.onerror = function (e) {
2006
- if (type.call(e) === "[object Error]" &&
2007
- !/ Error/.test(e.constructor.toString())) {
2008
- pendingRequests = 0
2009
- throw e
2010
- }
2011
- }
2012
-
2013
- m.sync = function (args) {
2014
- var deferred = m.deferred()
2015
- var outstanding = args.length
2016
- var results = []
2017
- var method = "resolve"
2018
-
2019
- function synchronizer(pos, resolved) {
2020
- return function (value) {
2021
- results[pos] = value
2022
- if (!resolved) method = "reject"
2023
- if (--outstanding === 0) {
2024
- deferred.promise(results)
2025
- deferred[method](results)
2026
- }
2027
- return value
2028
- }
2029
- }
2030
-
2031
- if (args.length > 0) {
2032
- forEach(args, function (arg, i) {
2033
- arg.then(synchronizer(i, true), synchronizer(i, false))
2034
- })
2035
- } else {
2036
- deferred.resolve([])
2037
- }
2038
-
2039
- return deferred.promise
2040
- }
2041
-
2042
- function identity(value) { return value }
2043
-
2044
- function handleJsonp(options) {
2045
- var callbackKey = options.callbackName || "mithril_callback_" +
2046
- new Date().getTime() + "_" +
2047
- (Math.round(Math.random() * 1e16)).toString(36)
2048
-
2049
- var script = $document.createElement("script")
2050
-
2051
- global[callbackKey] = function (resp) {
2052
- script.parentNode.removeChild(script)
2053
- options.onload({
2054
- type: "load",
2055
- target: {
2056
- responseText: resp
2057
- }
2058
- })
2059
- global[callbackKey] = undefined
2060
- }
2061
-
2062
- script.onerror = function () {
2063
- script.parentNode.removeChild(script)
2064
-
2065
- options.onerror({
2066
- type: "error",
2067
- target: {
2068
- status: 500,
2069
- responseText: JSON.stringify({
2070
- error: "Error making jsonp request"
2071
- })
2072
- }
2073
- })
2074
- global[callbackKey] = undefined
2075
-
2076
- return false
2077
- }
2078
-
2079
- script.onload = function () {
2080
- return false
2081
- }
2082
-
2083
- script.src = options.url +
2084
- (options.url.indexOf("?") > 0 ? "&" : "?") +
2085
- (options.callbackKey ? options.callbackKey : "callback") +
2086
- "=" + callbackKey +
2087
- "&" + buildQueryString(options.data || {})
2088
-
2089
- $document.body.appendChild(script)
2090
- }
2091
-
2092
- function createXhr(options) {
2093
- var xhr = new global.XMLHttpRequest()
2094
- xhr.open(options.method, options.url, true, options.user,
2095
- options.password)
2096
-
2097
- xhr.onreadystatechange = function () {
2098
- if (xhr.readyState === 4) {
2099
- if (xhr.status >= 200 && xhr.status < 300) {
2100
- options.onload({type: "load", target: xhr})
2101
- } else {
2102
- options.onerror({type: "error", target: xhr})
2103
- }
2104
- }
2105
- }
2106
-
2107
- if (options.serialize === JSON.stringify &&
2108
- options.data &&
2109
- options.method !== "GET") {
2110
- xhr.setRequestHeader("Content-Type",
2111
- "application/json; charset=utf-8")
2112
- }
2113
-
2114
- if (options.deserialize === JSON.parse) {
2115
- xhr.setRequestHeader("Accept", "application/json, text/*")
2116
- }
2117
-
2118
- if (isFunction(options.config)) {
2119
- var maybeXhr = options.config(xhr, options)
2120
- if (maybeXhr != null) xhr = maybeXhr
2121
- }
2122
-
2123
- var data = options.method === "GET" || !options.data ? "" : options.data
2124
-
2125
- if (data && !isString(data) && data.constructor !== global.FormData) {
2126
- throw new Error("Request data should be either be a string or " +
2127
- "FormData. Check the `serialize` option in `m.request`")
2128
- }
2129
-
2130
- xhr.send(data)
2131
- return xhr
2132
- }
2133
-
2134
- function ajax(options) {
2135
- if (options.dataType && options.dataType.toLowerCase() === "jsonp") {
2136
- return handleJsonp(options)
2137
- } else {
2138
- return createXhr(options)
2139
- }
2140
- }
2141
-
2142
- function bindData(options, data, serialize) {
2143
- if (options.method === "GET" && options.dataType !== "jsonp") {
2144
- var prefix = options.url.indexOf("?") < 0 ? "?" : "&"
2145
- var querystring = buildQueryString(data)
2146
- options.url += (querystring ? prefix + querystring : "")
2147
- } else {
2148
- options.data = serialize(data)
2149
- }
2150
- }
2151
-
2152
- function parameterizeUrl(url, data) {
2153
- if (data) {
2154
- url = url.replace(/:[a-z]\w+/gi, function (token){
2155
- var key = token.slice(1)
2156
- var value = data[key] || token
2157
- delete data[key]
2158
- return value
2159
- })
2160
- }
2161
- return url
2162
- }
2163
-
2164
- m.request = function (options) {
2165
- if (options.background !== true) m.startComputation()
2166
- var deferred = new Deferred()
2167
- var isJSONP = options.dataType &&
2168
- options.dataType.toLowerCase() === "jsonp"
2169
-
2170
- var serialize, deserialize, extract
2171
-
2172
- if (isJSONP) {
2173
- serialize = options.serialize =
2174
- deserialize = options.deserialize = identity
2175
-
2176
- extract = function (jsonp) { return jsonp.responseText }
2177
- } else {
2178
- serialize = options.serialize = options.serialize || JSON.stringify
2179
-
2180
- deserialize = options.deserialize =
2181
- options.deserialize || JSON.parse
2182
- extract = options.extract || function (xhr) {
2183
- if (xhr.responseText.length || deserialize !== JSON.parse) {
2184
- return xhr.responseText
2185
- } else {
2186
- return null
2187
- }
2188
- }
2189
- }
2190
-
2191
- options.method = (options.method || "GET").toUpperCase()
2192
- options.url = parameterizeUrl(options.url, options.data)
2193
- bindData(options, options.data, serialize)
2194
- options.onload = options.onerror = function (ev) {
2195
- try {
2196
- ev = ev || event
2197
- var response = deserialize(extract(ev.target, options))
2198
- if (ev.type === "load") {
2199
- if (options.unwrapSuccess) {
2200
- response = options.unwrapSuccess(response, ev.target)
2201
- }
2202
-
2203
- if (isArray(response) && options.type) {
2204
- forEach(response, function (res, i) {
2205
- response[i] = new options.type(res)
2206
- })
2207
- } else if (options.type) {
2208
- response = new options.type(response)
2209
- }
2210
-
2211
- deferred.resolve(response)
2212
- } else {
2213
- if (options.unwrapError) {
2214
- response = options.unwrapError(response, ev.target)
2215
- }
2216
-
2217
- deferred.reject(response)
2218
- }
2219
- } catch (e) {
2220
- deferred.reject(e)
2221
- m.deferred.onerror(e)
2222
- } finally {
2223
- if (options.background !== true) m.endComputation()
2224
- }
2225
- }
2226
-
2227
- ajax(options)
2228
- deferred.promise = propify(deferred.promise, options.initialValue)
2229
- return deferred.promise
2230
- }
2231
-
2232
- return m
2233
- }); // eslint-disable-line
1
+ new function() {
2
+
3
+ function Vnode(tag, key, attrs0, children, text, dom) {
4
+ return {tag: tag, key: key, attrs: attrs0, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined, skip: false}
5
+ }
6
+ Vnode.normalize = function(node) {
7
+ if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined)
8
+ if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node === false ? "" : node, undefined, undefined)
9
+ return node
10
+ }
11
+ Vnode.normalizeChildren = function normalizeChildren(children) {
12
+ for (var i = 0; i < children.length; i++) {
13
+ children[i] = Vnode.normalize(children[i])
14
+ }
15
+ return children
16
+ }
17
+ var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g
18
+ var selectorCache = {}
19
+ function hyperscript(selector) {
20
+ if (selector == null || typeof selector !== "string" && typeof selector.view !== "function") {
21
+ throw Error("The selector must be either a string or a component.");
22
+ }
23
+ if (typeof selector === "string" && selectorCache[selector] === undefined) {
24
+ var match, tag, classes = [], attributes = {}
25
+ while (match = selectorParser.exec(selector)) {
26
+ var type = match[1], value = match[2]
27
+ if (type === "" && value !== "") tag = value
28
+ else if (type === "#") attributes.id = value
29
+ else if (type === ".") classes.push(value)
30
+ else if (match[3][0] === "[") {
31
+ var attrValue = match[6]
32
+ if (attrValue) attrValue = attrValue.replace(/\\(["'])/g, "$1").replace(/\\\\/g, "\\")
33
+ if (match[4] === "class") classes.push(attrValue)
34
+ else attributes[match[4]] = attrValue || true
35
+ }
36
+ }
37
+ if (classes.length > 0) attributes.className = classes.join(" ")
38
+ selectorCache[selector] = function(attrs, children) {
39
+ var hasAttrs = false, childList, text
40
+ var className = attrs.className || attrs.class
41
+ for (var key in attributes) attrs[key] = attributes[key]
42
+ if (className !== undefined) {
43
+ if (attrs.class !== undefined) {
44
+ attrs.class = undefined
45
+ attrs.className = className
46
+ }
47
+ if (attributes.className !== undefined) attrs.className = attributes.className + " " + className
48
+ }
49
+ for (var key in attrs) {
50
+ if (key !== "key") {
51
+ hasAttrs = true
52
+ break
53
+ }
54
+ }
55
+ if (Array.isArray(children) && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children
56
+ else childList = children
57
+ return Vnode(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined)
58
+ }
59
+ }
60
+ var attrs, children, childrenIndex
61
+ if (arguments[1] == null || typeof arguments[1] === "object" && arguments[1].tag === undefined && !Array.isArray(arguments[1])) {
62
+ attrs = arguments[1]
63
+ childrenIndex = 2
64
+ }
65
+ else childrenIndex = 1
66
+ if (arguments.length === childrenIndex + 1) {
67
+ children = Array.isArray(arguments[childrenIndex]) ? arguments[childrenIndex] : [arguments[childrenIndex]]
68
+ }
69
+ else {
70
+ children = []
71
+ for (var i = childrenIndex; i < arguments.length; i++) children.push(arguments[i])
72
+ }
73
+ if (typeof selector === "string") return selectorCache[selector](attrs || {}, Vnode.normalizeChildren(children))
74
+ return Vnode(selector, attrs && attrs.key, attrs || {}, Vnode.normalizeChildren(children), undefined, undefined)
75
+ }
76
+ hyperscript.trust = function(html) {
77
+ if (html == null) html = ""
78
+ return Vnode("<", undefined, undefined, html, undefined, undefined)
79
+ }
80
+ hyperscript.fragment = function(attrs1, children) {
81
+ return Vnode("[", attrs1.key, attrs1, Vnode.normalizeChildren(children), undefined, undefined)
82
+ }
83
+ var m = hyperscript
84
+ /** @constructor */
85
+ var PromisePolyfill = function(executor) {
86
+ if (!(this instanceof PromisePolyfill)) throw new Error("Promise must be called with `new`")
87
+ if (typeof executor !== "function") throw new TypeError("executor must be a function")
88
+ var self = this, resolvers = [], rejectors = [], resolveCurrent = handler(resolvers, true), rejectCurrent = handler(rejectors, false)
89
+ var instance = self._instance = {resolvers: resolvers, rejectors: rejectors}
90
+ var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout
91
+ function handler(list, shouldAbsorb) {
92
+ return function execute(value) {
93
+ var then
94
+ try {
95
+ if (shouldAbsorb && value != null && (typeof value === "object" || typeof value === "function") && typeof (then = value.then) === "function") {
96
+ if (value === self) throw new TypeError("Promise can't be resolved w/ itself")
97
+ executeOnce(then.bind(value))
98
+ }
99
+ else {
100
+ callAsync(function() {
101
+ if (!shouldAbsorb && list.length === 0) console.error("Possible unhandled promise rejection:", value)
102
+ for (var i = 0; i < list.length; i++) list[i](value)
103
+ resolvers.length = 0, rejectors.length = 0
104
+ instance.state = shouldAbsorb
105
+ instance.retry = function() {execute(value)}
106
+ })
107
+ }
108
+ }
109
+ catch (e) {
110
+ rejectCurrent(e)
111
+ }
112
+ }
113
+ }
114
+ function executeOnce(then) {
115
+ var runs = 0
116
+ function run(fn) {
117
+ return function(value) {
118
+ if (runs++ > 0) return
119
+ fn(value)
120
+ }
121
+ }
122
+ var onerror = run(rejectCurrent)
123
+ try {then(run(resolveCurrent), onerror)} catch (e) {onerror(e)}
124
+ }
125
+ executeOnce(executor)
126
+ }
127
+ PromisePolyfill.prototype.then = function(onFulfilled, onRejection) {
128
+ var self = this, instance = self._instance
129
+ function handle(callback, list, next, state) {
130
+ list.push(function(value) {
131
+ if (typeof callback !== "function") next(value)
132
+ else try {resolveNext(callback(value))} catch (e) {if (rejectNext) rejectNext(e)}
133
+ })
134
+ if (typeof instance.retry === "function" && state === instance.state) instance.retry()
135
+ }
136
+ var resolveNext, rejectNext
137
+ var promise = new PromisePolyfill(function(resolve, reject) {resolveNext = resolve, rejectNext = reject})
138
+ handle(onFulfilled, instance.resolvers, resolveNext, true), handle(onRejection, instance.rejectors, rejectNext, false)
139
+ return promise
140
+ }
141
+ PromisePolyfill.prototype.catch = function(onRejection) {
142
+ return this.then(null, onRejection)
143
+ }
144
+ PromisePolyfill.resolve = function(value) {
145
+ if (value instanceof PromisePolyfill) return value
146
+ return new PromisePolyfill(function(resolve) {resolve(value)})
147
+ }
148
+ PromisePolyfill.reject = function(value) {
149
+ return new PromisePolyfill(function(resolve, reject) {reject(value)})
150
+ }
151
+ PromisePolyfill.all = function(list) {
152
+ return new PromisePolyfill(function(resolve, reject) {
153
+ var total = list.length, count = 0, values = []
154
+ if (list.length === 0) resolve([])
155
+ else for (var i = 0; i < list.length; i++) {
156
+ (function(i) {
157
+ function consume(value) {
158
+ count++
159
+ values[i] = value
160
+ if (count === total) resolve(values)
161
+ }
162
+ if (list[i] != null && (typeof list[i] === "object" || typeof list[i] === "function") && typeof list[i].then === "function") {
163
+ list[i].then(consume, reject)
164
+ }
165
+ else consume(list[i])
166
+ })(i)
167
+ }
168
+ })
169
+ }
170
+ PromisePolyfill.race = function(list) {
171
+ return new PromisePolyfill(function(resolve, reject) {
172
+ for (var i = 0; i < list.length; i++) {
173
+ list[i].then(resolve, reject)
174
+ }
175
+ })
176
+ }
177
+ if (typeof window !== "undefined") {
178
+ if (typeof window.Promise === "undefined") window.Promise = PromisePolyfill
179
+ var PromisePolyfill = window.Promise
180
+ } else if (typeof global !== "undefined") {
181
+ if (typeof global.Promise === "undefined") global.Promise = PromisePolyfill
182
+ var PromisePolyfill = global.Promise
183
+ } else {
184
+ }
185
+ var buildQueryString = function(object) {
186
+ if (Object.prototype.toString.call(object) !== "[object Object]") return ""
187
+ var args = []
188
+ for (var key0 in object) {
189
+ destructure(key0, object[key0])
190
+ }
191
+ return args.join("&")
192
+ function destructure(key0, value) {
193
+ if (Array.isArray(value)) {
194
+ for (var i = 0; i < value.length; i++) {
195
+ destructure(key0 + "[" + i + "]", value[i])
196
+ }
197
+ }
198
+ else if (Object.prototype.toString.call(value) === "[object Object]") {
199
+ for (var i in value) {
200
+ destructure(key0 + "[" + i + "]", value[i])
201
+ }
202
+ }
203
+ else args.push(encodeURIComponent(key0) + (value != null && value !== "" ? "=" + encodeURIComponent(value) : ""))
204
+ }
205
+ }
206
+ var _8 = function($window, Promise) {
207
+ var callbackCount = 0
208
+ var oncompletion
209
+ function setCompletionCallback(callback) {oncompletion = callback}
210
+ function finalizer() {
211
+ var count = 0
212
+ function complete() {if (--count === 0 && typeof oncompletion === "function") oncompletion()}
213
+ return function finalize(promise0) {
214
+ var then0 = promise0.then
215
+ promise0.then = function() {
216
+ count++
217
+ var next = then0.apply(promise0, arguments)
218
+ next.then(complete, function(e) {
219
+ complete()
220
+ if (count === 0) throw e
221
+ })
222
+ return finalize(next)
223
+ }
224
+ return promise0
225
+ }
226
+ }
227
+ function normalize(args, extra) {
228
+ if (typeof args === "string") {
229
+ var url = args
230
+ args = extra || {}
231
+ if (args.url == null) args.url = url
232
+ }
233
+ return args
234
+ }
235
+ function request(args, extra) {
236
+ var finalize = finalizer()
237
+ args = normalize(args, extra)
238
+ var promise0 = new Promise(function(resolve, reject) {
239
+ if (args.method == null) args.method = "GET"
240
+ args.method = args.method.toUpperCase()
241
+ var useBody = typeof args.useBody === "boolean" ? args.useBody : args.method !== "GET" && args.method !== "TRACE"
242
+ if (typeof args.serialize !== "function") args.serialize = typeof FormData !== "undefined" && args.data instanceof FormData ? function(value) {return value} : JSON.stringify
243
+ if (typeof args.deserialize !== "function") args.deserialize = deserialize
244
+ if (typeof args.extract !== "function") args.extract = extract
245
+ args.url = interpolate(args.url, args.data)
246
+ if (useBody) args.data = args.serialize(args.data)
247
+ else args.url = assemble(args.url, args.data)
248
+ var xhr = new $window.XMLHttpRequest()
249
+ xhr.open(args.method, args.url, typeof args.async === "boolean" ? args.async : true, typeof args.user === "string" ? args.user : undefined, typeof args.password === "string" ? args.password : undefined)
250
+ if (args.serialize === JSON.stringify && useBody) {
251
+ xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8")
252
+ }
253
+ if (args.deserialize === deserialize) {
254
+ xhr.setRequestHeader("Accept", "application/json, text/*")
255
+ }
256
+ if (args.withCredentials) xhr.withCredentials = args.withCredentials
257
+ for (var key in args.headers) if ({}.hasOwnProperty.call(args.headers, key)) {
258
+ xhr.setRequestHeader(key, args.headers[key])
259
+ }
260
+ if (typeof args.config === "function") xhr = args.config(xhr, args) || xhr
261
+ xhr.onreadystatechange = function() {
262
+ // Don't throw errors on xhr.abort(). XMLHttpRequests ends up in a state of
263
+ // xhr.status == 0 and xhr.readyState == 4 if aborted after open, but before completion.
264
+ if (xhr.status && xhr.readyState === 4) {
265
+ try {
266
+ var response = (args.extract !== extract) ? args.extract(xhr, args) : args.deserialize(args.extract(xhr, args))
267
+ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
268
+ resolve(cast(args.type, response))
269
+ }
270
+ else {
271
+ var error = new Error(xhr.responseText)
272
+ for (var key in response) error[key] = response[key]
273
+ reject(error)
274
+ }
275
+ }
276
+ catch (e) {
277
+ reject(e)
278
+ }
279
+ }
280
+ }
281
+ if (useBody && (args.data != null)) xhr.send(args.data)
282
+ else xhr.send()
283
+ })
284
+ return args.background === true ? promise0 : finalize(promise0)
285
+ }
286
+ function jsonp(args, extra) {
287
+ var finalize = finalizer()
288
+ args = normalize(args, extra)
289
+ var promise0 = new Promise(function(resolve, reject) {
290
+ var callbackName = args.callbackName || "_mithril_" + Math.round(Math.random() * 1e16) + "_" + callbackCount++
291
+ var script = $window.document.createElement("script")
292
+ $window[callbackName] = function(data) {
293
+ script.parentNode.removeChild(script)
294
+ resolve(cast(args.type, data))
295
+ delete $window[callbackName]
296
+ }
297
+ script.onerror = function() {
298
+ script.parentNode.removeChild(script)
299
+ reject(new Error("JSONP request failed"))
300
+ delete $window[callbackName]
301
+ }
302
+ if (args.data == null) args.data = {}
303
+ args.url = interpolate(args.url, args.data)
304
+ args.data[args.callbackKey || "callback"] = callbackName
305
+ script.src = assemble(args.url, args.data)
306
+ $window.document.documentElement.appendChild(script)
307
+ })
308
+ return args.background === true? promise0 : finalize(promise0)
309
+ }
310
+ function interpolate(url, data) {
311
+ if (data == null) return url
312
+ var tokens = url.match(/:[^\/]+/gi) || []
313
+ for (var i = 0; i < tokens.length; i++) {
314
+ var key = tokens[i].slice(1)
315
+ if (data[key] != null) {
316
+ url = url.replace(tokens[i], data[key])
317
+ }
318
+ }
319
+ return url
320
+ }
321
+ function assemble(url, data) {
322
+ var querystring = buildQueryString(data)
323
+ if (querystring !== "") {
324
+ var prefix = url.indexOf("?") < 0 ? "?" : "&"
325
+ url += prefix + querystring
326
+ }
327
+ return url
328
+ }
329
+ function deserialize(data) {
330
+ try {return data !== "" ? JSON.parse(data) : null}
331
+ catch (e) {throw new Error(data)}
332
+ }
333
+ function extract(xhr) {return xhr.responseText}
334
+ function cast(type0, data) {
335
+ if (typeof type0 === "function") {
336
+ if (Array.isArray(data)) {
337
+ for (var i = 0; i < data.length; i++) {
338
+ data[i] = new type0(data[i])
339
+ }
340
+ }
341
+ else return new type0(data)
342
+ }
343
+ return data
344
+ }
345
+ return {request: request, jsonp: jsonp, setCompletionCallback: setCompletionCallback}
346
+ }
347
+ var requestService = _8(window, PromisePolyfill)
348
+ var coreRenderer = function($window) {
349
+ var $doc = $window.document
350
+ var $emptyFragment = $doc.createDocumentFragment()
351
+ var onevent
352
+ function setEventCallback(callback) {return onevent = callback}
353
+ //create
354
+ function createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) {
355
+ for (var i = start; i < end; i++) {
356
+ var vnode = vnodes[i]
357
+ if (vnode != null) {
358
+ createNode(parent, vnode, hooks, ns, nextSibling)
359
+ }
360
+ }
361
+ }
362
+ function createNode(parent, vnode, hooks, ns, nextSibling) {
363
+ var tag = vnode.tag
364
+ if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
365
+ if (typeof tag === "string") {
366
+ switch (tag) {
367
+ case "#": return createText(parent, vnode, nextSibling)
368
+ case "<": return createHTML(parent, vnode, nextSibling)
369
+ case "[": return createFragment(parent, vnode, hooks, ns, nextSibling)
370
+ default: return createElement(parent, vnode, hooks, ns, nextSibling)
371
+ }
372
+ }
373
+ else return createComponent(parent, vnode, hooks, ns, nextSibling)
374
+ }
375
+ function createText(parent, vnode, nextSibling) {
376
+ vnode.dom = $doc.createTextNode(vnode.children)
377
+ insertNode(parent, vnode.dom, nextSibling)
378
+ return vnode.dom
379
+ }
380
+ function createHTML(parent, vnode, nextSibling) {
381
+ var match1 = vnode.children.match(/^\s*?<(\w+)/im) || []
382
+ var parent1 = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"}[match1[1]] || "div"
383
+ var temp = $doc.createElement(parent1)
384
+ temp.innerHTML = vnode.children
385
+ vnode.dom = temp.firstChild
386
+ vnode.domSize = temp.childNodes.length
387
+ var fragment = $doc.createDocumentFragment()
388
+ var child
389
+ while (child = temp.firstChild) {
390
+ fragment.appendChild(child)
391
+ }
392
+ insertNode(parent, fragment, nextSibling)
393
+ return fragment
394
+ }
395
+ function createFragment(parent, vnode, hooks, ns, nextSibling) {
396
+ var fragment = $doc.createDocumentFragment()
397
+ if (vnode.children != null) {
398
+ var children = vnode.children
399
+ createNodes(fragment, children, 0, children.length, hooks, null, ns)
400
+ }
401
+ vnode.dom = fragment.firstChild
402
+ vnode.domSize = fragment.childNodes.length
403
+ insertNode(parent, fragment, nextSibling)
404
+ return fragment
405
+ }
406
+ function createElement(parent, vnode, hooks, ns, nextSibling) {
407
+ var tag = vnode.tag
408
+ switch (vnode.tag) {
409
+ case "svg": ns = "http://www.w3.org/2000/svg"; break
410
+ case "math": ns = "http://www.w3.org/1998/Math/MathML"; break
411
+ }
412
+ var attrs2 = vnode.attrs
413
+ var is = attrs2 && attrs2.is
414
+ var element = ns ?
415
+ is ? $doc.createElementNS(ns, tag, {is: is}) : $doc.createElementNS(ns, tag) :
416
+ is ? $doc.createElement(tag, {is: is}) : $doc.createElement(tag)
417
+ vnode.dom = element
418
+ if (attrs2 != null) {
419
+ setAttrs(vnode, attrs2, ns)
420
+ }
421
+ insertNode(parent, element, nextSibling)
422
+ if (vnode.attrs != null && vnode.attrs.contenteditable != null) {
423
+ setContentEditable(vnode)
424
+ }
425
+ else {
426
+ if (vnode.text != null) {
427
+ if (vnode.text !== "") element.textContent = vnode.text
428
+ else vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
429
+ }
430
+ if (vnode.children != null) {
431
+ var children = vnode.children
432
+ createNodes(element, children, 0, children.length, hooks, null, ns)
433
+ setLateAttrs(vnode)
434
+ }
435
+ }
436
+ return element
437
+ }
438
+ function createComponent(parent, vnode, hooks, ns, nextSibling) {
439
+ vnode.state = Object.create(vnode.tag)
440
+ var view = vnode.tag.view
441
+ if (view.reentrantLock != null) return $emptyFragment
442
+ view.reentrantLock = true
443
+ initLifecycle(vnode.tag, vnode, hooks)
444
+ vnode.instance = Vnode.normalize(view.call(vnode.state, vnode))
445
+ view.reentrantLock = null
446
+ if (vnode.instance != null) {
447
+ if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as arguments")
448
+ var element = createNode(parent, vnode.instance, hooks, ns, nextSibling)
449
+ vnode.dom = vnode.instance.dom
450
+ vnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0
451
+ insertNode(parent, element, nextSibling)
452
+ return element
453
+ }
454
+ else {
455
+ vnode.domSize = 0
456
+ return $emptyFragment
457
+ }
458
+ }
459
+ //update
460
+ function updateNodes(parent, old, vnodes, recycling, hooks, nextSibling, ns) {
461
+ if (old === vnodes || old == null && vnodes == null) return
462
+ else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, undefined)
463
+ else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
464
+ else {
465
+ if (old.length === vnodes.length) {
466
+ var isUnkeyed = false
467
+ for (var i = 0; i < vnodes.length; i++) {
468
+ if (vnodes[i] != null && old[i] != null) {
469
+ isUnkeyed = vnodes[i].key == null && old[i].key == null
470
+ break
471
+ }
472
+ }
473
+ if (isUnkeyed) {
474
+ for (var i = 0; i < old.length; i++) {
475
+ if (old[i] === vnodes[i]) continue
476
+ else if (old[i] == null && vnodes[i] != null) createNode(parent, vnodes[i], hooks, ns, getNextSibling(old, i + 1, nextSibling))
477
+ else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes)
478
+ else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), false, ns)
479
+ }
480
+ return
481
+ }
482
+ }
483
+ recycling = recycling || isRecyclable(old, vnodes)
484
+ if (recycling) old = old.concat(old.pool)
485
+
486
+ var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
487
+ while (oldEnd >= oldStart && end >= start) {
488
+ var o = old[oldStart], v = vnodes[start]
489
+ if (o === v && !recycling) oldStart++, start++
490
+ else if (o == null) oldStart++
491
+ else if (v == null) start++
492
+ else if (o.key === v.key) {
493
+ oldStart++, start++
494
+ updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), recycling, ns)
495
+ if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
496
+ }
497
+ else {
498
+ var o = old[oldEnd]
499
+ if (o === v && !recycling) oldEnd--, start++
500
+ else if (o == null) oldEnd--
501
+ else if (v == null) start++
502
+ else if (o.key === v.key) {
503
+ updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
504
+ if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling))
505
+ oldEnd--, start++
506
+ }
507
+ else break
508
+ }
509
+ }
510
+ while (oldEnd >= oldStart && end >= start) {
511
+ var o = old[oldEnd], v = vnodes[end]
512
+ if (o === v && !recycling) oldEnd--, end--
513
+ else if (o == null) oldEnd--
514
+ else if (v == null) end--
515
+ else if (o.key === v.key) {
516
+ updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
517
+ if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
518
+ if (o.dom != null) nextSibling = o.dom
519
+ oldEnd--, end--
520
+ }
521
+ else {
522
+ if (!map) map = getKeyMap(old, oldEnd)
523
+ if (v != null) {
524
+ var oldIndex = map[v.key]
525
+ if (oldIndex != null) {
526
+ var movable = old[oldIndex]
527
+ updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
528
+ insertNode(parent, toFragment(movable), nextSibling)
529
+ old[oldIndex].skip = true
530
+ if (movable.dom != null) nextSibling = movable.dom
531
+ }
532
+ else {
533
+ var dom = createNode(parent, v, hooks, undefined, nextSibling)
534
+ nextSibling = dom
535
+ }
536
+ }
537
+ end--
538
+ }
539
+ if (end < start) break
540
+ }
541
+ createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
542
+ removeNodes(old, oldStart, oldEnd + 1, vnodes)
543
+ }
544
+ }
545
+ function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) {
546
+ var oldTag = old.tag, tag = vnode.tag
547
+ if (oldTag === tag) {
548
+ vnode.state = old.state
549
+ vnode.events = old.events
550
+ if (shouldUpdate(vnode, old)) return
551
+ if (vnode.attrs != null) {
552
+ updateLifecycle(vnode.attrs, vnode, hooks, recycling)
553
+ }
554
+ if (typeof oldTag === "string") {
555
+ switch (oldTag) {
556
+ case "#": updateText(old, vnode); break
557
+ case "<": updateHTML(parent, old, vnode, nextSibling); break
558
+ case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break
559
+ default: updateElement(old, vnode, recycling, hooks, ns)
560
+ }
561
+ }
562
+ else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns)
563
+ }
564
+ else {
565
+ removeNode(old, null)
566
+ createNode(parent, vnode, hooks, ns, nextSibling)
567
+ }
568
+ }
569
+ function updateText(old, vnode) {
570
+ if (old.children.toString() !== vnode.children.toString()) {
571
+ old.dom.nodeValue = vnode.children
572
+ }
573
+ vnode.dom = old.dom
574
+ }
575
+ function updateHTML(parent, old, vnode, nextSibling) {
576
+ if (old.children !== vnode.children) {
577
+ toFragment(old)
578
+ createHTML(parent, vnode, nextSibling)
579
+ }
580
+ else vnode.dom = old.dom, vnode.domSize = old.domSize
581
+ }
582
+ function updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns) {
583
+ updateNodes(parent, old.children, vnode.children, recycling, hooks, nextSibling, ns)
584
+ var domSize = 0, children = vnode.children
585
+ vnode.dom = null
586
+ if (children != null) {
587
+ for (var i = 0; i < children.length; i++) {
588
+ var child = children[i]
589
+ if (child != null && child.dom != null) {
590
+ if (vnode.dom == null) vnode.dom = child.dom
591
+ domSize += child.domSize || 1
592
+ }
593
+ }
594
+ if (domSize !== 1) vnode.domSize = domSize
595
+ }
596
+ }
597
+ function updateElement(old, vnode, recycling, hooks, ns) {
598
+ var element = vnode.dom = old.dom
599
+ switch (vnode.tag) {
600
+ case "svg": ns = "http://www.w3.org/2000/svg"; break
601
+ case "math": ns = "http://www.w3.org/1998/Math/MathML"; break
602
+ }
603
+ if (vnode.tag === "textarea") {
604
+ if (vnode.attrs == null) vnode.attrs = {}
605
+ if (vnode.text != null) {
606
+ vnode.attrs.value = vnode.text //FIXME handle0 multiple children
607
+ vnode.text = undefined
608
+ }
609
+ }
610
+ updateAttrs(vnode, old.attrs, vnode.attrs, ns)
611
+ if (vnode.attrs != null && vnode.attrs.contenteditable != null) {
612
+ setContentEditable(vnode)
613
+ }
614
+ else if (old.text != null && vnode.text != null && vnode.text !== "") {
615
+ if (old.text.toString() !== vnode.text.toString()) old.dom.firstChild.nodeValue = vnode.text
616
+ }
617
+ else {
618
+ if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)]
619
+ if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
620
+ updateNodes(element, old.children, vnode.children, recycling, hooks, null, ns)
621
+ }
622
+ }
623
+ function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
624
+ vnode.instance = Vnode.normalize(vnode.tag.view.call(vnode.state, vnode))
625
+ updateLifecycle(vnode.tag, vnode, hooks, recycling)
626
+ if (vnode.instance != null) {
627
+ if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling)
628
+ else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns)
629
+ vnode.dom = vnode.instance.dom
630
+ vnode.domSize = vnode.instance.domSize
631
+ }
632
+ else if (old.instance != null) {
633
+ removeNode(old.instance, null)
634
+ vnode.dom = undefined
635
+ vnode.domSize = 0
636
+ }
637
+ else {
638
+ vnode.dom = old.dom
639
+ vnode.domSize = old.domSize
640
+ }
641
+ }
642
+ function isRecyclable(old, vnodes) {
643
+ if (old.pool != null && Math.abs(old.pool.length - vnodes.length) <= Math.abs(old.length - vnodes.length)) {
644
+ var oldChildrenLength = old[0] && old[0].children && old[0].children.length || 0
645
+ var poolChildrenLength = old.pool[0] && old.pool[0].children && old.pool[0].children.length || 0
646
+ var vnodesChildrenLength = vnodes[0] && vnodes[0].children && vnodes[0].children.length || 0
647
+ if (Math.abs(poolChildrenLength - vnodesChildrenLength) <= Math.abs(oldChildrenLength - vnodesChildrenLength)) {
648
+ return true
649
+ }
650
+ }
651
+ return false
652
+ }
653
+ function getKeyMap(vnodes, end) {
654
+ var map = {}, i = 0
655
+ for (var i = 0; i < end; i++) {
656
+ var vnode = vnodes[i]
657
+ if (vnode != null) {
658
+ var key2 = vnode.key
659
+ if (key2 != null) map[key2] = i
660
+ }
661
+ }
662
+ return map
663
+ }
664
+ function toFragment(vnode) {
665
+ var count0 = vnode.domSize
666
+ if (count0 != null || vnode.dom == null) {
667
+ var fragment = $doc.createDocumentFragment()
668
+ if (count0 > 0) {
669
+ var dom = vnode.dom
670
+ while (--count0) fragment.appendChild(dom.nextSibling)
671
+ fragment.insertBefore(dom, fragment.firstChild)
672
+ }
673
+ return fragment
674
+ }
675
+ else return vnode.dom
676
+ }
677
+ function getNextSibling(vnodes, i, nextSibling) {
678
+ for (; i < vnodes.length; i++) {
679
+ if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom
680
+ }
681
+ return nextSibling
682
+ }
683
+ function insertNode(parent, dom, nextSibling) {
684
+ if (nextSibling && nextSibling.parentNode) parent.insertBefore(dom, nextSibling)
685
+ else parent.appendChild(dom)
686
+ }
687
+ function setContentEditable(vnode) {
688
+ var children = vnode.children
689
+ if (children != null && children.length === 1 && children[0].tag === "<") {
690
+ var content = children[0].children
691
+ if (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content
692
+ }
693
+ else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted")
694
+ }
695
+ //remove
696
+ function removeNodes(vnodes, start, end, context) {
697
+ for (var i = start; i < end; i++) {
698
+ var vnode = vnodes[i]
699
+ if (vnode != null) {
700
+ if (vnode.skip) vnode.skip = false
701
+ else removeNode(vnode, context)
702
+ }
703
+ }
704
+ }
705
+ function removeNode(vnode, context) {
706
+ var expected = 1, called = 0
707
+ if (vnode.attrs && vnode.attrs.onbeforeremove) {
708
+ var result = vnode.attrs.onbeforeremove.call(vnode.state, vnode)
709
+ if (result != null && typeof result.then === "function") {
710
+ expected++
711
+ result.then(continuation, continuation)
712
+ }
713
+ }
714
+ if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) {
715
+ var result = vnode.tag.onbeforeremove.call(vnode.state, vnode)
716
+ if (result != null && typeof result.then === "function") {
717
+ expected++
718
+ result.then(continuation, continuation)
719
+ }
720
+ }
721
+ continuation()
722
+ function continuation() {
723
+ if (++called === expected) {
724
+ onremove(vnode)
725
+ if (vnode.dom) {
726
+ var count0 = vnode.domSize || 1
727
+ if (count0 > 1) {
728
+ var dom = vnode.dom
729
+ while (--count0) {
730
+ removeNodeFromDOM(dom.nextSibling)
731
+ }
732
+ }
733
+ removeNodeFromDOM(vnode.dom)
734
+ if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements
735
+ if (!context.pool) context.pool = [vnode]
736
+ else context.pool.push(vnode)
737
+ }
738
+ }
739
+ }
740
+ }
741
+ }
742
+ function removeNodeFromDOM(node) {
743
+ var parent = node.parentNode
744
+ if (parent != null) parent.removeChild(node)
745
+ }
746
+ function onremove(vnode) {
747
+ if (vnode.attrs && vnode.attrs.onremove) vnode.attrs.onremove.call(vnode.state, vnode)
748
+ if (typeof vnode.tag !== "string" && vnode.tag.onremove) vnode.tag.onremove.call(vnode.state, vnode)
749
+ if (vnode.instance != null) onremove(vnode.instance)
750
+ else {
751
+ var children = vnode.children
752
+ if (Array.isArray(children)) {
753
+ for (var i = 0; i < children.length; i++) {
754
+ var child = children[i]
755
+ if (child != null) onremove(child)
756
+ }
757
+ }
758
+ }
759
+ }
760
+ //attrs2
761
+ function setAttrs(vnode, attrs2, ns) {
762
+ for (var key2 in attrs2) {
763
+ setAttr(vnode, key2, null, attrs2[key2], ns)
764
+ }
765
+ }
766
+ function setAttr(vnode, key2, old, value, ns) {
767
+ var element = vnode.dom
768
+ if (key2 === "key" || key2 === "is" || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key2)) return
769
+ var nsLastIndex = key2.indexOf(":")
770
+ if (nsLastIndex > -1 && key2.substr(0, nsLastIndex) === "xlink") {
771
+ element.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(nsLastIndex + 1), value)
772
+ }
773
+ else if (key2[0] === "o" && key2[1] === "n" && typeof value === "function") updateEvent(vnode, key2, value)
774
+ else if (key2 === "style") updateStyle(element, old, value)
775
+ else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) {
776
+ //setting input[value] to same value by typing on focused element moves cursor to end in Chrome
777
+ if (vnode.tag === "input" && key2 === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return
778
+ //setting select[value] to same value while having select open blinks select dropdown in Chrome
779
+ if (vnode.tag === "select" && key2 === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return
780
+ //setting option[value] to same value while having select open blinks select dropdown in Chrome
781
+ if (vnode.tag === "option" && key2 === "value" && vnode.dom.value === value) return
782
+ element[key2] = value
783
+ }
784
+ else {
785
+ if (typeof value === "boolean") {
786
+ if (value) element.setAttribute(key2, "")
787
+ else element.removeAttribute(key2)
788
+ }
789
+ else element.setAttribute(key2 === "className" ? "class" : key2, value)
790
+ }
791
+ }
792
+ function setLateAttrs(vnode) {
793
+ var attrs2 = vnode.attrs
794
+ if (vnode.tag === "select" && attrs2 != null) {
795
+ if ("value" in attrs2) setAttr(vnode, "value", null, attrs2.value, undefined)
796
+ if ("selectedIndex" in attrs2) setAttr(vnode, "selectedIndex", null, attrs2.selectedIndex, undefined)
797
+ }
798
+ }
799
+ function updateAttrs(vnode, old, attrs2, ns) {
800
+ if (attrs2 != null) {
801
+ for (var key2 in attrs2) {
802
+ setAttr(vnode, key2, old && old[key2], attrs2[key2], ns)
803
+ }
804
+ }
805
+ if (old != null) {
806
+ for (var key2 in old) {
807
+ if (attrs2 == null || !(key2 in attrs2)) {
808
+ if (key2 === "className") key2 = "class"
809
+ if (key2[0] === "o" && key2[1] === "n" && !isLifecycleMethod(key2)) updateEvent(vnode, key2, undefined)
810
+ else if (key2 !== "key") vnode.dom.removeAttribute(key2)
811
+ }
812
+ }
813
+ }
814
+ }
815
+ function isFormAttribute(vnode, attr) {
816
+ return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement
817
+ }
818
+ function isLifecycleMethod(attr) {
819
+ return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate"
820
+ }
821
+ function isAttribute(attr) {
822
+ return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type"
823
+ }
824
+ function isCustomElement(vnode){
825
+ return vnode.attrs.is || vnode.tag.indexOf("-") > -1
826
+ }
827
+ function hasIntegrationMethods(source) {
828
+ return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove)
829
+ }
830
+ //style
831
+ function updateStyle(element, old, style) {
832
+ if (old === style) element.style.cssText = "", old = null
833
+ if (style == null) element.style.cssText = ""
834
+ else if (typeof style === "string") element.style.cssText = style
835
+ else {
836
+ if (typeof old === "string") element.style.cssText = ""
837
+ for (var key2 in style) {
838
+ element.style[key2] = style[key2]
839
+ }
840
+ if (old != null && typeof old !== "string") {
841
+ for (var key2 in old) {
842
+ if (!(key2 in style)) element.style[key2] = ""
843
+ }
844
+ }
845
+ }
846
+ }
847
+ //event
848
+ function updateEvent(vnode, key2, value) {
849
+ var element = vnode.dom
850
+ var callback = typeof onevent !== "function" ? value : function(e) {
851
+ var result = value.call(element, e)
852
+ onevent.call(element, e)
853
+ return result
854
+ }
855
+ if (key2 in element) element[key2] = typeof value === "function" ? callback : null
856
+ else {
857
+ var eventName = key2.slice(2)
858
+ if (vnode.events === undefined) vnode.events = {}
859
+ if (vnode.events[key2] === callback) return
860
+ if (vnode.events[key2] != null) element.removeEventListener(eventName, vnode.events[key2], false)
861
+ if (typeof value === "function") {
862
+ vnode.events[key2] = callback
863
+ element.addEventListener(eventName, vnode.events[key2], false)
864
+ }
865
+ }
866
+ }
867
+ //lifecycle
868
+ function initLifecycle(source, vnode, hooks) {
869
+ if (typeof source.oninit === "function") source.oninit.call(vnode.state, vnode)
870
+ if (typeof source.oncreate === "function") hooks.push(source.oncreate.bind(vnode.state, vnode))
871
+ }
872
+ function updateLifecycle(source, vnode, hooks, recycling) {
873
+ if (recycling) initLifecycle(source, vnode, hooks)
874
+ else if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode))
875
+ }
876
+ function shouldUpdate(vnode, old) {
877
+ var forceVnodeUpdate, forceComponentUpdate
878
+ if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") forceVnodeUpdate = vnode.attrs.onbeforeupdate.call(vnode.state, vnode, old)
879
+ if (typeof vnode.tag !== "string" && typeof vnode.tag.onbeforeupdate === "function") forceComponentUpdate = vnode.tag.onbeforeupdate.call(vnode.state, vnode, old)
880
+ if (!(forceVnodeUpdate === undefined && forceComponentUpdate === undefined) && !forceVnodeUpdate && !forceComponentUpdate) {
881
+ vnode.dom = old.dom
882
+ vnode.domSize = old.domSize
883
+ vnode.instance = old.instance
884
+ return true
885
+ }
886
+ return false
887
+ }
888
+ function render(dom, vnodes) {
889
+ if (!dom) throw new Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.")
890
+ var hooks = []
891
+ var active = $doc.activeElement
892
+ // First time0 rendering into a node clears it out
893
+ if (dom.vnodes == null) dom.textContent = ""
894
+ if (!Array.isArray(vnodes)) vnodes = [vnodes]
895
+ updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, undefined)
896
+ dom.vnodes = vnodes
897
+ for (var i = 0; i < hooks.length; i++) hooks[i]()
898
+ if ($doc.activeElement !== active) active.focus()
899
+ }
900
+ return {render: render, setEventCallback: setEventCallback}
901
+ }
902
+ function throttle(callback) {
903
+ //60fps translates to 16.6ms, round it down since setTimeout requires int
904
+ var time = 16
905
+ var last = 0, pending = null
906
+ var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout
907
+ return function() {
908
+ var now = Date.now()
909
+ if (last === 0 || now - last >= time) {
910
+ last = now
911
+ callback()
912
+ }
913
+ else if (pending === null) {
914
+ pending = timeout(function() {
915
+ pending = null
916
+ callback()
917
+ last = Date.now()
918
+ }, time - (now - last))
919
+ }
920
+ }
921
+ }
922
+ var _11 = function($window) {
923
+ var renderService = coreRenderer($window)
924
+ renderService.setEventCallback(function(e) {
925
+ if (e.redraw !== false) redraw()
926
+ })
927
+ var callbacks = []
928
+ function subscribe(key1, callback) {
929
+ unsubscribe(key1)
930
+ callbacks.push(key1, throttle(callback))
931
+ }
932
+ function unsubscribe(key1) {
933
+ var index = callbacks.indexOf(key1)
934
+ if (index > -1) callbacks.splice(index, 2)
935
+ }
936
+ function redraw() {
937
+ for (var i = 1; i < callbacks.length; i += 2) {
938
+ callbacks[i]()
939
+ }
940
+ }
941
+ return {subscribe: subscribe, unsubscribe: unsubscribe, redraw: redraw, render: renderService.render}
942
+ }
943
+ var redrawService = _11(window)
944
+ requestService.setCompletionCallback(redrawService.redraw)
945
+ var _16 = function(redrawService0) {
946
+ return function(root, component) {
947
+ if (component === null) {
948
+ redrawService0.render(root, [])
949
+ redrawService0.unsubscribe(root)
950
+ return
951
+ }
952
+
953
+ if (component.view == null) throw new Error("m.mount(element, component) expects a component, not a vnode")
954
+
955
+ var run0 = function() {
956
+ redrawService0.render(root, Vnode(component))
957
+ }
958
+ redrawService0.subscribe(root, run0)
959
+ redrawService0.redraw()
960
+ }
961
+ }
962
+ m.mount = _16(redrawService)
963
+ var Promise = PromisePolyfill
964
+ var parseQueryString = function(string) {
965
+ if (string === "" || string == null) return {}
966
+ if (string.charAt(0) === "?") string = string.slice(1)
967
+ var entries = string.split("&"), data0 = {}, counters = {}
968
+ for (var i = 0; i < entries.length; i++) {
969
+ var entry = entries[i].split("=")
970
+ var key5 = decodeURIComponent(entry[0])
971
+ var value = entry.length === 2 ? decodeURIComponent(entry[1]) : ""
972
+ if (value === "true") value = true
973
+ else if (value === "false") value = false
974
+ var levels = key5.split(/\]\[?|\[/)
975
+ var cursor = data0
976
+ if (key5.indexOf("[") > -1) levels.pop()
977
+ for (var j = 0; j < levels.length; j++) {
978
+ var level = levels[j], nextLevel = levels[j + 1]
979
+ var isNumber = nextLevel == "" || !isNaN(parseInt(nextLevel, 10))
980
+ var isValue = j === levels.length - 1
981
+ if (level === "") {
982
+ var key5 = levels.slice(0, j).join()
983
+ if (counters[key5] == null) counters[key5] = 0
984
+ level = counters[key5]++
985
+ }
986
+ if (cursor[level] == null) {
987
+ cursor[level] = isValue ? value : isNumber ? [] : {}
988
+ }
989
+ cursor = cursor[level]
990
+ }
991
+ }
992
+ return data0
993
+ }
994
+ var coreRouter = function($window) {
995
+ var supportsPushState = typeof $window.history.pushState === "function"
996
+ var callAsync0 = typeof setImmediate === "function" ? setImmediate : setTimeout
997
+ function normalize1(fragment0) {
998
+ var data = $window.location[fragment0].replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent)
999
+ if (fragment0 === "pathname" && data[0] !== "/") data = "/" + data
1000
+ return data
1001
+ }
1002
+ var asyncId
1003
+ function debounceAsync(callback0) {
1004
+ return function() {
1005
+ if (asyncId != null) return
1006
+ asyncId = callAsync0(function() {
1007
+ asyncId = null
1008
+ callback0()
1009
+ })
1010
+ }
1011
+ }
1012
+ function parsePath(path, queryData, hashData) {
1013
+ var queryIndex = path.indexOf("?")
1014
+ var hashIndex = path.indexOf("#")
1015
+ var pathEnd = queryIndex > -1 ? queryIndex : hashIndex > -1 ? hashIndex : path.length
1016
+ if (queryIndex > -1) {
1017
+ var queryEnd = hashIndex > -1 ? hashIndex : path.length
1018
+ var queryParams = parseQueryString(path.slice(queryIndex + 1, queryEnd))
1019
+ for (var key4 in queryParams) queryData[key4] = queryParams[key4]
1020
+ }
1021
+ if (hashIndex > -1) {
1022
+ var hashParams = parseQueryString(path.slice(hashIndex + 1))
1023
+ for (var key4 in hashParams) hashData[key4] = hashParams[key4]
1024
+ }
1025
+ return path.slice(0, pathEnd)
1026
+ }
1027
+ var router = {prefix: "#!"}
1028
+ router.getPath = function() {
1029
+ var type2 = router.prefix.charAt(0)
1030
+ switch (type2) {
1031
+ case "#": return normalize1("hash").slice(router.prefix.length)
1032
+ case "?": return normalize1("search").slice(router.prefix.length) + normalize1("hash")
1033
+ default: return normalize1("pathname").slice(router.prefix.length) + normalize1("search") + normalize1("hash")
1034
+ }
1035
+ }
1036
+ router.setPath = function(path, data, options) {
1037
+ var queryData = {}, hashData = {}
1038
+ path = parsePath(path, queryData, hashData)
1039
+ if (data != null) {
1040
+ for (var key4 in data) queryData[key4] = data[key4]
1041
+ path = path.replace(/:([^\/]+)/g, function(match2, token) {
1042
+ delete queryData[token]
1043
+ return data[token]
1044
+ })
1045
+ }
1046
+ var query = buildQueryString(queryData)
1047
+ if (query) path += "?" + query
1048
+ var hash = buildQueryString(hashData)
1049
+ if (hash) path += "#" + hash
1050
+ if (supportsPushState) {
1051
+ var state = options ? options.state : null
1052
+ var title = options ? options.title : null
1053
+ $window.onpopstate()
1054
+ if (options && options.replace) $window.history.replaceState(state, title, router.prefix + path)
1055
+ else $window.history.pushState(state, title, router.prefix + path)
1056
+ }
1057
+ else $window.location.href = router.prefix + path
1058
+ }
1059
+ router.defineRoutes = function(routes, resolve, reject) {
1060
+ function resolveRoute() {
1061
+ var path = router.getPath()
1062
+ var params = {}
1063
+ var pathname = parsePath(path, params, params)
1064
+ var state = $window.history.state
1065
+ if (state != null) {
1066
+ for (var k in state) params[k] = state[k]
1067
+ }
1068
+ for (var route0 in routes) {
1069
+ var matcher = new RegExp("^" + route0.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
1070
+ if (matcher.test(pathname)) {
1071
+ pathname.replace(matcher, function() {
1072
+ var keys = route0.match(/:[^\/]+/g) || []
1073
+ var values = [].slice.call(arguments, 1, -2)
1074
+ for (var i = 0; i < keys.length; i++) {
1075
+ params[keys[i].replace(/:|\./g, "")] = decodeURIComponent(values[i])
1076
+ }
1077
+ resolve(routes[route0], params, path, route0)
1078
+ })
1079
+ return
1080
+ }
1081
+ }
1082
+ reject(path, params)
1083
+ }
1084
+ if (supportsPushState) $window.onpopstate = debounceAsync(resolveRoute)
1085
+ else if (router.prefix.charAt(0) === "#") $window.onhashchange = resolveRoute
1086
+ resolveRoute()
1087
+ }
1088
+ return router
1089
+ }
1090
+ var _20 = function($window, redrawService0) {
1091
+ var routeService = coreRouter($window)
1092
+ var identity = function(v) {return v}
1093
+ var render1, component, attrs3, currentPath, lastUpdate
1094
+ var route = function(root, defaultRoute, routes) {
1095
+ if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined")
1096
+ var run1 = function() {
1097
+ if (render1 != null) redrawService0.render(root, render1(Vnode(component, attrs3.key, attrs3)))
1098
+ }
1099
+ var bail = function(path) {
1100
+ if (path !== defaultRoute) routeService.setPath(defaultRoute, null, {replace: true})
1101
+ else throw new Error("Could not resolve default route " + defaultRoute)
1102
+ }
1103
+ routeService.defineRoutes(routes, function(payload, params, path) {
1104
+ var update = lastUpdate = function(routeResolver, comp) {
1105
+ if (update !== lastUpdate) return
1106
+ component = comp != null && typeof comp.view === "function" ? comp : "div", attrs3 = params, currentPath = path, lastUpdate = null
1107
+ render1 = (routeResolver.render || identity).bind(routeResolver)
1108
+ run1()
1109
+ }
1110
+ if (payload.view) update({}, payload)
1111
+ else {
1112
+ if (payload.onmatch) {
1113
+ Promise.resolve(payload.onmatch(params, path)).then(function(resolved) {
1114
+ update(payload, resolved)
1115
+ }, bail)
1116
+ }
1117
+ else update(payload, "div")
1118
+ }
1119
+ }, bail)
1120
+ redrawService0.subscribe(root, run1)
1121
+ }
1122
+ route.set = function(path, data, options) {
1123
+ if (lastUpdate != null) options = {replace: true}
1124
+ lastUpdate = null
1125
+ routeService.setPath(path, data, options)
1126
+ }
1127
+ route.get = function() {return currentPath}
1128
+ route.prefix = function(prefix0) {routeService.prefix = prefix0}
1129
+ route.link = function(vnode1) {
1130
+ vnode1.dom.setAttribute("href", routeService.prefix + vnode1.attrs.href)
1131
+ vnode1.dom.onclick = function(e) {
1132
+ if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return
1133
+ e.preventDefault()
1134
+ e.redraw = false
1135
+ var href = this.getAttribute("href")
1136
+ if (href.indexOf(routeService.prefix) === 0) href = href.slice(routeService.prefix.length)
1137
+ route.set(href, undefined, undefined)
1138
+ }
1139
+ }
1140
+ route.param = function(key3) {
1141
+ if(typeof attrs3 !== "undefined" && typeof key3 !== "undefined") return attrs3[key3]
1142
+ return attrs3
1143
+ }
1144
+ return route
1145
+ }
1146
+ m.route = _20(window, redrawService)
1147
+ m.withAttr = function(attrName, callback1, context) {
1148
+ return function(e) {
1149
+ callback1.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName))
1150
+ }
1151
+ }
1152
+ var _28 = coreRenderer(window)
1153
+ m.render = _28.render
1154
+ m.redraw = redrawService.redraw
1155
+ m.request = requestService.request
1156
+ m.jsonp = requestService.jsonp
1157
+ m.parseQueryString = parseQueryString
1158
+ m.buildQueryString = buildQueryString
1159
+ m.version = "1.0.1"
1160
+ m.vnode = Vnode
1161
+ if (typeof module !== "undefined") module["exports"] = m
1162
+ else window.m = m
1163
+ }