@litejs/ui 24.5.0 → 24.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,28 +1,33 @@
1
1
 
2
2
  /* litejs.com/MIT-LICENSE.txt */
3
3
 
4
- /* global xhr, getComputedStyle, navigator */
4
+ /* global xhr, navigator */
5
+
6
+ /*** debug ***/
7
+ console.log("LiteJS is in debug mode, but it's fine for production")
8
+ /**/
5
9
 
6
10
  !function(window, document, history, localStorage, location, navigator, Function, Object) {
7
11
  window.El = El
8
- window.LiteJS = LiteJS
12
+ asEmitter(window.LiteJS = LiteJS)
9
13
 
10
- var UNDEF, lastExp, parser, styleNode
14
+ var UNDEF, lastExp, parser, pushBase, styleNode
11
15
  , html = document.documentElement
12
16
  , body = document.body
13
- , histBase, histCb, histLast
14
17
  , splitRe = /[,\s]+/
15
18
  , emptyArr = []
16
19
  , assign = Object.assign
17
20
  , create = Object.create
18
21
  , isArr = Array.isArray
19
22
  , slice = emptyArr.slice
23
+ , elReplace = Function("a,b,c", "(c=a&&b&&a.parentNode)&&c.replaceChild(b,a)")
24
+ , elRm = Function("e,k", "(k=e&&e.parentNode)&&k.removeChild(e)")
25
+ , getAttr = Function("e,k", "return e&&e.getAttribute&&e.getAttribute(k)")
26
+ , replace = Function("a,b,c", "return a.replace(b,c)")
20
27
 
21
28
  // JScript engine in IE8 and below does not recognize vertical tabulation character `\v`.
22
29
  // http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
23
30
  , ie678 = !+"\v1" // jshint ignore:line
24
- // The documentMode is an IE only property, supported in IE8 and up.
25
- , ie67 = ie678 && (document.documentMode | 0) < 8 // jshint ignore:line
26
31
 
27
32
  , BIND_ATTR = "data-bind"
28
33
  , elSeq = 0
@@ -32,24 +37,24 @@
32
37
  , selectorRe = /([.#:[])([-\w]+)(?:([~^$*|]?)=(("|')(?:\\.|[^\\])*?\5|[-\w]+))?]?/g
33
38
  , templateRe = /([ \t]*)(%?)((?:("|')(?:\\.|[^\\])*?\4|[-\w:.#[\]~^$*|]=?)*) ?([\/>+=@^;]|)(([\])}]?).*?([[({]?))(?=\x1f|\n|$)+/g
34
39
  , fnCache = {}
35
- , fnRe = /('|")(?:\\.|[^\\])*?\1|\/(?:\\.|[^\\])+?\/[gim]*|\$el\b|\$[as]\b|\b(?:false|in|if|new|null|this|true|typeof|void|function|var|else|return)\b|\.\w+|\w+:/g
40
+ , fnRe = /('|")(?:\\.|[^\\])*?\1|\/(?:\\.|[^\\])+?\/[gim]*|\$el\b|\$[aos]\b|\b(?:false|in|if|new|null|this|true|typeof|void|function|var|else|return)\b|\.\w+|\w+:/g
36
41
  , wordRe = /[a-z_$][\w$]*/ig
37
42
  , camelRe = /\-([a-z])/g
38
43
  // innerText is implemented in IE4, textContent in IE9, Node.text in Opera 9-10
39
44
  // Safari 2.x innerText results an empty string when style.display=="none" or Node is not in DOM
40
45
  , txtAttr = "textContent" in html ? "textContent" : "innerText"
41
46
  , bindingsCss = acceptMany(function(el, key, val) {
42
- el.style[key.replace(camelRe, camelFn)] = "" + val
47
+ el.style[replace(key, camelRe, camelFn)] = val
43
48
  })
44
- , bindingsOn = acceptMany(addEvent, function(el, selector, data, handler) {
45
- return isStr(handler) ? function(e) {
49
+ , bindingsOn = acceptMany(addEvent, function(el, val, selector, data) {
50
+ return isStr(val) ? function(e) {
46
51
  var target = selector ? closest(e.target, selector) : el
47
- if (target) emit.apply(elScope(el).$ui, [handler, e, target].concat(data))
52
+ if (target) emit.apply(elScope(el).$ui, [val, e, target].concat(data))
48
53
  } :
49
- selector ? function(e) {
50
- if (matches(e.target, selector)) handler(e)
54
+ selector ? function(e, a1, a2) {
55
+ if (matches(e.target, selector)) val(e, a1, a2)
51
56
  } :
52
- handler
57
+ val
53
58
  })
54
59
  , bindings = {
55
60
  cls: acceptMany(cls),
@@ -59,7 +64,7 @@
59
64
  txt: elTxt,
60
65
  val: elVal,
61
66
  view: function(el, url) {
62
- setAttr(el, "href", (histBase || "#") + expand(url || ""))
67
+ setAttr(el, "href", (pushBase || "#") + expand(url || ""))
63
68
  }
64
69
  }
65
70
  , globalScope = {
@@ -85,14 +90,9 @@
85
90
  }
86
91
  }
87
92
  , plugins = {}
88
- , sources = [ (findAll(html, "script").pop() || plugins).innerHTML ]
93
+ , sources = []
89
94
  , hasOwn = plugins.hasOwnProperty
90
95
 
91
- // After iOS 13 iPad with default enabled "desktop" option
92
- // is the only Macintosh with multi-touch
93
- , iOS = /^(Mac|iP)/.test(navigator.platform)
94
- // || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
95
-
96
96
  , Event = window.Event || window
97
97
  , fixEv = Event.fixEv || (Event.fixEv = {})
98
98
  , fixFn = Event.fixFn || (Event.fixFn = {})
@@ -113,12 +113,6 @@
113
113
  Event.asEmitter = asEmitter
114
114
  Event.stop = eventStop
115
115
 
116
- if (iOS) {
117
- // iOS doesn't support beforeunload, use pagehide instead
118
- fixEv.beforeunload = "pagehide"
119
- }
120
-
121
-
122
116
  xhr.css = injectCss
123
117
  xhr.ui = sources.push.bind(sources)
124
118
 
@@ -181,7 +175,7 @@
181
175
  return _e / 3
182
176
  }
183
177
 
184
- function addEvent(el, ev, fn) {
178
+ function addEvent(el, ev, fn, opts) {
185
179
  var fn2 = fixFn[ev] && fixFn[ev](el, fn, ev) || fn
186
180
  , ev2 = fixEv[ev] || ev
187
181
 
@@ -189,7 +183,7 @@
189
183
  // polyfilled addEventListener returns patched function
190
184
  // Since Chrome 56 touchstart/move have the { passive: true } by default.
191
185
  // preventDefault() won't work unless you set passive to false.
192
- fn2 = html.addEventListener.call(el, ev2, fn2, false) || fn2
186
+ fn2 = html.addEventListener.call(el, ev2, fn2, opts != UNDEF ? opts : false) || fn2
193
187
  }
194
188
 
195
189
  on.call(el, ev, fn2, el, fn)
@@ -220,7 +214,7 @@
220
214
 
221
215
  function LiteJS(opts) {
222
216
  opts = assign({
223
- base: "",
217
+ path: "",
224
218
  /*** breakpoints ***/
225
219
  breakpoints: {
226
220
  sm: 0,
@@ -249,10 +243,10 @@
249
243
 
250
244
  if (route.charAt(0) !== "#") {
251
245
  fnStr += "m[" + (view.s = routeSeq++) + "]?("
252
- reStr += "|(" + route.replace(routeRe, function(_, expr) {
246
+ reStr += "|(" + replace(route, routeRe, function(_, expr) {
253
247
  return expr ?
254
248
  (fnStr += "p['" + expr + "']=m[" + (routeSeq++) + "],") && "([^/]+?)" :
255
- _.replace(reEsc, "\\$&")
249
+ replace(_, reEsc, "\\$&")
256
250
  }) + ")"
257
251
  fnStr += "'" + route + "'):"
258
252
  viewFn = 0
@@ -266,42 +260,39 @@
266
260
  , params = lastParams = _params || {} // jshint ignore:line
267
261
  , view = lastView = this // jshint ignore:line
268
262
  , tmp = params._v || view // Continue bubbleUp from _v
269
- , close = view.o && view
270
263
 
264
+ params._c = view.o ? view : params._c
271
265
  for (View.route = view.r; tmp; tmp = parent) {
272
266
  viewEmit(syncResume = params._v = tmp, "ping", params, View)
273
- syncResume = null
267
+ syncResume = UNDEF
274
268
  if (lastParams !== params) return
275
269
  if ((parent = tmp.p)) {
276
270
  if (parent.c && parent.c !== tmp) {
277
- close = parent.c
271
+ params._c = parent.c
278
272
  }
279
273
  parent.c = tmp
280
274
  }
281
- if (!tmp.e) {
282
- if (tmp.f) {
283
- xhr.load(
284
- tmp.f.replace(/^|,/g, "$&" + (View.base || "")).split(","),
285
- readTemplates.bind(view, view.wait(tmp.f = null))
286
- )
287
- } else {
288
- if (tmp.r === "404") {
289
- viewParse("%view 404 #\nh2 Not found")
290
- }
291
- View("404").show({origin:params})
275
+ if (tmp.f) {
276
+ return xhr.load(
277
+ replace(tmp.f, /^|,/g, "$&" + View.path).split(","),
278
+ readTemplates.bind(view, view.wait(tmp.f = ""))
279
+ )
280
+ } else if (!tmp.e) {
281
+ if (tmp.r === "404") {
282
+ viewParse("%view 404 #\nh2 Not found")
292
283
  }
293
- return
284
+ return View("404").show({origin:params})
294
285
  }
295
286
  }
296
287
 
297
288
  for (tmp in params) {
298
289
  if (tmp.charAt(0) !== "_" && (syncResume = hasOwn.call(paramCb, tmp) && paramCb[tmp] || paramCb["*"])) {
299
- syncResume.call(view, params[tmp], tmp, params, View)
300
- syncResume = null
290
+ syncResume(params[tmp], tmp, view, params)
291
+ syncResume = UNDEF
301
292
  }
302
293
  }
303
294
  viewEmit(view, "nav")
304
- bubbleDown(params, close)
295
+ bubbleDown(params)
305
296
  },
306
297
  wait: function() {
307
298
  var params = lastParams
@@ -366,8 +357,9 @@
366
357
  current + sep + val
367
358
  ) : val))
368
359
  }
369
- function bubbleDown(params, close) {
360
+ function bubbleDown(params) {
370
361
  var view = params._v
362
+ , close = params._c
371
363
  , parent = view && view.p
372
364
  if (!view || params._p && /{/.test(view.r)) {
373
365
  return viewClose(close)
@@ -379,10 +371,10 @@
379
371
  viewEmit(parent, "openChild", view, close)
380
372
  viewEmit(view, "open", params)
381
373
  addKb(view.kb)
382
- close = null
374
+ params._c = UNDEF
383
375
  }
384
376
  if ((params._d = params._v = view.c)) {
385
- bubbleDown(params, close)
377
+ bubbleDown(params)
386
378
  }
387
379
  if ((lastView === view)) {
388
380
  viewEmit(view, "show", params)
@@ -395,7 +387,7 @@
395
387
  viewEmit(view.p, "closeChild", view, open)
396
388
  viewClose(view.c)
397
389
  elKill(view.o)
398
- view.o = null
390
+ view.o = UNDEF
399
391
  rmKb(view.kb)
400
392
  viewEmit(view, "close")
401
393
  }
@@ -414,9 +406,14 @@
414
406
  function viewEmit(view, event, a, b) {
415
407
  view.emit(event, a, b)
416
408
  View.emit(event, view, a, b)
409
+ LiteJS.emit(event, view, a, b)
417
410
  }
418
411
  function viewEval(str, scope) {
419
- Function("$s,$ui,$d,$,$$", str)(scope, View, $d, View.$, View.$$)
412
+ try {
413
+ Function("$s,$ui,$d,$,$$", str)(scope, View, $d, View.$, View.$$)
414
+ } catch(e) {
415
+ logErr(e, "viewEval: " + str)
416
+ }
420
417
  }
421
418
  function viewGet(url, params) {
422
419
  if (!viewFn) {
@@ -443,7 +440,9 @@
443
440
  parent = parentStack.pop()
444
441
  stack.shift()
445
442
  }
446
-
443
+ if (op === "@") {
444
+ text = replace(text, /([\w,.]+):?/, "on!'$1',")
445
+ }
447
446
  if (parent.r) {
448
447
  parent.t += "\n" + all
449
448
  } else if (plugin || mapStart && (sel = "map")) {
@@ -464,21 +463,19 @@
464
463
  }
465
464
  if (text && op != "/") {
466
465
  if (op === ">" || op === "+") {
467
- (indent + (op === "+" ? text : " " + text)).replace(templateRe, work)
466
+ replace(indent + (op === "+" ? text : " " + text), templateRe, work)
468
467
  } else if (op === "=") {
469
468
  append(parent, text) // + "\n")
470
469
  } else {
471
- if (op === "@") {
472
- text = text.replace(/([\w,]+):?/, "on!'$1',")
473
- } else if (op === "") {
474
- text = "txt _('" + text.replace(/'/g, "\\'") + "',$s)"
470
+ if (op === "") {
471
+ text = "txt _('" + replace(text, /'/g, "\\'") + "',$s)"
475
472
  }
476
473
  appendBind(parent, text, ";", op)
477
474
  }
478
475
  }
479
476
  }
480
477
  }
481
- str.replace(templateRe, work)
478
+ replace(str, templateRe, work)
482
479
  work("", "")
483
480
  if (parent.childNodes[0]) {
484
481
  append(root, parent.childNodes)
@@ -500,8 +497,8 @@
500
497
  var params = _params || {}
501
498
  , view = viewGet(url, params)
502
499
  if (!view.o || lastUrl !== url) {
503
- globalScope.url = lastExp = lastUrl = url
504
- view.show(globalScope.params = params)
500
+ $d.url = lastExp = lastUrl = url
501
+ view.show($d.params = params)
505
502
  }
506
503
  }
507
504
 
@@ -536,13 +533,13 @@
536
533
  , contentPos = el._cp
537
534
 
538
535
  if (contentPos > -1) {
539
- if (childNodes[contentPos].nodeType == 1 && el._sk) {
536
+ if (childNodes[contentPos].nodeType < 2 && el._sk) {
540
537
  setAttr(childNodes[contentPos], "data-slot", el._sk)
541
538
  }
542
539
  child._s = el._s
543
540
  }
544
541
  if (plugin.c) elCache = plugin.c
545
- el.p = plugin.e = plugin.u = null
542
+ el.p = plugin.e = plugin.u = UNDEF
546
543
  return child
547
544
  }
548
545
 
@@ -553,9 +550,9 @@
553
550
  d: function(plugin) {
554
551
  var slotName = plugin.n || ++elSeq
555
552
  , parent = plugin.u
556
- append(parent, Comm("%slot-" + slotName))
553
+ append(parent, Comm("slot" + slotName))
557
554
  // In IE6 root div is inside documentFragment
558
- for (; (parent.parentNode || plugin).nodeType === 1; parent = parent.parentNode);
555
+ for (; (parent.parentNode || plugin).nodeType < 2; parent = parent.parentNode);
559
556
  ;(parent._s || (parent._s = {}))[slotName] = parent.childNodes.length - 1
560
557
  if (!plugin.n) parent._s._ = parent._sk = slotName
561
558
  parent._cp = parent.childNodes.length - 1
@@ -568,7 +565,7 @@
568
565
  r: function(params) {
569
566
  var txt = this.t
570
567
  each(params, function(param) {
571
- viewParse(txt.replace(/{key}/g, param))
568
+ viewParse(replace(txt, /{key}/g, param))
572
569
  })
573
570
  }
574
571
  })
@@ -595,7 +592,7 @@
595
592
  var bind = getAttr(plugin.e, BIND_ATTR)
596
593
  , view = View(plugin.n, usePluginContent(plugin), plugin.x)
597
594
  if (bind) {
598
- bind = bind.replace(renderRe, function(_, name, op, args) {
595
+ bind = replace(bind, renderRe, function(_, name, op, args) {
599
596
  return "($s." + name + (isFn(view[name]) ? "(" + (args || "") + ")" : "=" + args) + "),"
600
597
  }) + "1"
601
598
  viewEval(bind, view)
@@ -616,14 +613,14 @@
616
613
  next = point
617
614
  }
618
615
 
619
- if ( next != lastSize ) {
616
+ if (next != lastSize) {
620
617
  cls(html, lastSize, 0)
621
618
  cls(html, lastSize = next)
622
619
  }
623
620
 
624
621
  next = width > html.offsetHeight ? "land" : "port"
625
622
 
626
- if ( next != lastOrient) {
623
+ if (next != lastOrient) {
627
624
  cls(html, lastOrient, 0)
628
625
  cls(html, lastOrient = next)
629
626
  }
@@ -663,45 +660,28 @@
663
660
  return View
664
661
  }
665
662
 
666
- function getUrl() {
667
- return (
668
- /*** pushState ***/
669
- histBase ? location.pathname.slice(histBase.length) :
670
- /**/
671
- // bug in Firefox where location.hash is decoded
672
- // bug in Safari where location.pathname is decoded
673
- location.href.split("#")[1] || ""
674
- ).replace(/^[#\/\!]+|[\s\/]+$/g, "")
675
- }
676
- function setUrl(url, replace) {
663
+ function setUrl(url, rep, checkUrl) {
677
664
  /*** pushState ***/
678
- if (histBase) {
679
- history[replace ? "replaceState" : "pushState"](null, null, histBase + url)
665
+ if (pushBase) {
666
+ history[rep ? "replaceState" : "pushState"](null, null, pushBase + url)
680
667
  } else {
681
668
  /**/
682
- location[replace ? "replace" : "assign"]("#" + url)
669
+ location[rep ? "replace" : "assign"]("#" + url)
683
670
  /*** pushState ***/
684
671
  }
685
672
  /**/
686
- return checkUrl()
687
- }
688
- function checkUrl() {
689
- if (histLast != (histLast = getUrl())) {
690
- if (histCb) histCb(histLast)
691
- return true
692
- }
673
+ if (checkUrl) checkUrl()
693
674
  }
694
675
 
695
676
  LiteJS.go = setUrl
696
677
  LiteJS.start = histStart
697
678
  function histStart(cb) {
698
- histCb = cb
699
679
  /*** pushState ***/
700
680
  // Chrome5, Firefox4, IE10, Safari5, Opera11.50
701
- var url
681
+ var histLast, url
702
682
  , base = find(html, "base")
703
- LiteJS.base = (base || location).href.replace(/[^\/]*(#.*)?$/, "")
704
- if (base) base = base.href.replace(/.*:\/\/[^/]*|[^\/]*$/g, "")
683
+ LiteJS.base = replace((base || location).href, /[^\/]*(#.*)?$/, "")
684
+ if (base) base = replace(base.href, /.*:\/\/[^/]*|[^\/]*$/g, "")
705
685
  if (base && !history.pushState) {
706
686
  url = location.pathname.slice(base.length)
707
687
  if (url) {
@@ -709,7 +689,7 @@
709
689
  }
710
690
  }
711
691
  if (base && history.pushState) {
712
- histBase = base
692
+ pushBase = base
713
693
 
714
694
  url = location.href.split("#")[1]
715
695
  if (url && !getUrl()) {
@@ -728,9 +708,20 @@
728
708
  /**/
729
709
  window.onhashchange = checkUrl
730
710
  readTemplates(checkUrl)
711
+ function checkUrl() {
712
+ if (cb && histLast != (histLast = getUrl())) cb(histLast)
713
+ }
714
+ function getUrl() {
715
+ return replace(
716
+ /*** pushState ***/
717
+ pushBase ? location.pathname.slice(pushBase.length) :
718
+ /**/
719
+ // bug in Firefox where location.hash is decoded
720
+ // bug in Safari where location.pathname is decoded
721
+ location.href.split("#")[1] || "", /^[#\/\!]+|[\s\/]+$/g, "")
722
+ }
731
723
  }
732
724
 
733
-
734
725
  function Comm(name, render) {
735
726
  var comm = document.createComment(name)
736
727
  if (render) comm.render = render
@@ -739,7 +730,7 @@
739
730
  function El(name) {
740
731
  var attr
741
732
  , attrs = {}
742
- , el = name.replace(selectorRe, function(_, op, key, fn, val, quotation) {
733
+ , el = replace(name, selectorRe, function(_, op, key, fn, val, quotation) {
743
734
  attr = 1
744
735
  val = quotation ? val.slice(1, -1) : val || key
745
736
  attrs[op =
@@ -824,7 +815,7 @@
824
815
  subScope[name] = item
825
816
  clone[BIND_ATTR] = el[BIND_ATTR]
826
817
  append(comm.parentNode, clone, comm)
827
- render(clone, subScope)
818
+ render(clone)
828
819
  }
829
820
  function remove(i) {
830
821
  elKill(nodes.splice(i, 1)[0])
@@ -842,14 +833,14 @@
842
833
  if ((tmp = el.className)) cls(child, tmp)
843
834
  child.$s = el.$s
844
835
  elReplace(el, child)
845
- render(child, this)
836
+ render(child)
846
837
  return child
847
838
  },
848
839
  "if": function(el, enabled) {
849
840
  if (enabled) {
850
841
  elReplace(el._if, el)
851
842
  } else {
852
- elReplace(el, el._if || (el._if = Comm("if", render.bind(el, el, this))))
843
+ elReplace(el, el._if || (el._if = Comm("if", render.bind(el, el))))
853
844
  return true
854
845
  }
855
846
  },
@@ -879,21 +870,17 @@
879
870
  get: getAttr,
880
871
  hasClass: hasClass,
881
872
  matches: matches,
873
+ next: walk.bind(El, "nextSibling"),
874
+ prev: walk.bind(El, "previousSibling"),
882
875
  rate: rate,
883
876
  replace: elReplace,
884
877
  scope: elScope,
885
878
  scrollLeft: scrollLeft,
886
879
  scrollTop: scrollTop,
887
880
  step: step,
888
- style: function(el, key) {
889
- return getComputedStyle(el).getPropertyValue(key)
890
- }
881
+ stop: eventStop
891
882
  })
892
883
 
893
- function getAttr(el, key) {
894
- return el && el.getAttribute && el.getAttribute(key)
895
- }
896
-
897
884
  function setAttr(el, key, val) {
898
885
  var current = getAttr(el, key)
899
886
 
@@ -901,9 +888,9 @@
901
888
  // Bug: IE5-7 doesn't set styles and removes events when you try to set them.
902
889
  // IE6 label with a for attribute will re-select the first option of SELECT list instead of just giving focus.
903
890
  // http://webbugtrack.blogspot.com/2007/09/bug-116-for-attribute-woes-in-ie6.html
891
+ // IE8 and below have a bug where changed 'name' not accepted on form submit
904
892
  /* c8 ignore next 3 */
905
- if (ie67 && (key === "id" || key === "name" || key === "checked" || key === "style")) {
906
- // IE8 and below have a bug where changed 'name' not accepted on form submit
893
+ if (ie678 && (key === "id" || key === "name" || key === "checked" || key === "style")) {
907
894
  el.mergeAttributes(document.createElement("<INPUT " + key + "='" + val + "'>"), false)
908
895
  } else
909
896
  /**/
@@ -928,14 +915,14 @@
928
915
  , i = 0
929
916
  if (child) {
930
917
  if (isStr(child) || isNum(child)) child = document.createTextNode(child)
931
- else if ( !child.nodeType && (i = child.length) ) {
918
+ else if (!child.nodeType && (i = child.length)) {
932
919
  for (tmp = document.createDocumentFragment(); i--; ) append(tmp, child[i], 0)
933
920
  child = tmp
934
921
  }
935
922
 
936
923
  if (child.nodeType) {
937
924
  if ((i = setAttr(child, "slot", "") || getAttr(el, "data-slot"))) {
938
- i = "%slot-" + i
925
+ i = "slot" + i
939
926
  for (tmp = el.firstChild; tmp; tmp = next) {
940
927
  if (tmp.nodeType === 8 && tmp.nodeValue === i) {
941
928
  el = tmp
@@ -979,17 +966,19 @@
979
966
  // className is object on SVGElements
980
967
  var current = el.className || ""
981
968
  , useAttr = !isStr(current)
969
+ , SP = " "
982
970
 
983
971
  if (useAttr) {
984
- current = el.getAttribute("class") || ""
972
+ current = getAttr(el, "class") || ""
985
973
  }
986
974
 
987
975
  if (set === UNDEF || set) {
976
+ if (set && set !== el && set.nodeType < 2) cls(set, name, 0)
988
977
  if (current) {
989
- name = current.split(splitRe).indexOf(name) > -1 ? current : current + " " + name
978
+ name = current.split(SP).indexOf(name) > -1 ? current : current + SP + name
990
979
  }
991
980
  } else {
992
- name = current ? (" " + current + " ").replace(" " + name + " ", " ").trim() : current
981
+ name = current ? replace(SP + current + SP, SP + name + SP, SP).trim() : current
993
982
  }
994
983
 
995
984
  if (current != name) {
@@ -1011,9 +1000,11 @@
1011
1000
  if (el) {
1012
1001
  if (delay > 0) return setTimeout(elKill, delay, el, tr)
1013
1002
  if (tr) {
1014
- cls(el, tr, tr = "transitionend")
1003
+ if (isStr(tr)) cls(el, tr)
1004
+ if (isObj(tr)) bindingsCss(el, tr)
1005
+ tr = "transitionend"
1015
1006
  // transitionend fires for each property transitioned
1016
- if ("on" + tr in el) return addEvent(el, tr, elKill.bind(el, el, el = null))
1007
+ if ("on" + tr in el) return addEvent(el, tr, elKill.bind(el, el, el = UNDEF))
1017
1008
  }
1018
1009
  if (el._e) {
1019
1010
  emit.call(el, "kill")
@@ -1021,24 +1012,16 @@
1021
1012
  }
1022
1013
  elRm(el)
1023
1014
  el.$s = UNDEF
1024
- if (el.nodeType != 1) {
1025
- if (el.kill) el.kill()
1026
- } else {
1015
+ if (el.nodeType < 2) {
1027
1016
  elEmpty(el)
1028
1017
  if (el.valObject !== UNDEF) {
1029
1018
  el.valObject = UNDEF
1030
1019
  }
1020
+ } else {
1021
+ if (el.kill) el.kill()
1031
1022
  }
1032
1023
  }
1033
1024
  }
1034
- function elReplace(oldChild, newChild) {
1035
- var parent = oldChild && oldChild.parentNode
1036
- if (parent && newChild) parent.replaceChild(newChild, oldChild)
1037
- }
1038
- function elRm(el) {
1039
- var parent = el && el.parentNode
1040
- if (parent) parent.removeChild(el)
1041
- }
1042
1025
  function elScope(el, parent) {
1043
1026
  return el.$s || (
1044
1027
  parent ? ((parent = elScope(parent)), el.$s = assign(create(parent), { $up: parent })) :
@@ -1069,7 +1052,7 @@
1069
1052
  value = elVal(input, val != UNDEF ? val[key] : UNDEF)
1070
1053
  if (value !== UNDEF) {
1071
1054
  step = opts
1072
- key.replace(/\[(.*?)\]/g, replacer)
1055
+ replace(key, /\[(.*?)\]/g, replacer)
1073
1056
  step[key || step.length] = value
1074
1057
  }
1075
1058
  }
@@ -1078,8 +1061,7 @@
1078
1061
 
1079
1062
  if (val !== UNDEF) {
1080
1063
  if (opts) {
1081
- value = (isArr(val) ? val : [ val ]).map(String)
1082
- for (; (input = opts[i++]); ) {
1064
+ for (value = (isArr(val) ? val : [ val ]).map(String); (input = opts[i++]); ) {
1083
1065
  input.selected = value.indexOf(input.value) > -1
1084
1066
  }
1085
1067
  } else if (el.val) {
@@ -1125,15 +1107,14 @@
1125
1107
  }
1126
1108
 
1127
1109
  function render(node, $s) {
1128
- if (!node) return
1129
- var bind, next
1130
- , scope = node.$s || $s || closestScope(node)
1131
-
1132
- if (node.nodeType != 1) {
1133
- if (node.render) node.render(scope)
1110
+ if (!node || node.nodeType != 1) {
1111
+ if (node && node.render) node.render()
1134
1112
  return
1135
1113
  }
1136
1114
 
1115
+ var bind, next
1116
+ , scope = node.$s || $s || closestScope(node)
1117
+
1137
1118
  /*** ie8 ***/
1138
1119
  if (ie678 && node.tagName === "SELECT") {
1139
1120
  node.parentNode.insertBefore(node, node)
@@ -1153,41 +1134,34 @@
1153
1134
  , bind = node[attr] || (node[attr] = setAttr(node, attr, "") || true)
1154
1135
  if (bind !== true) try {
1155
1136
  fn = fnCache[bind] || (fnCache[bind] = makeFn(bind))
1156
- scope.$o = fn.o
1157
- return fn(node, scope, attr)
1137
+ return fn(node, scope, attr, fn.o)
1158
1138
  } catch (e) {
1159
- /*** debug ***/
1160
- console.error(e)
1161
- console.error("BINDING: " + bind, node)
1162
- /**/
1163
- if (window.onerror) {
1164
- window.onerror(e.message, e.fileName, e.lineNumber)
1165
- }
1139
+ logErr(e, attr + ": " + bind, node)
1166
1140
  }
1167
1141
  }
1168
1142
  function makeFn(fn) {
1169
1143
  var i = 0
1170
1144
  , bindOnce = []
1171
- fn = "$s&&(" + fn.replace(renderRe, function(match, name, op, args) {
1145
+ fn = "$s&&(" + replace(fn, renderRe, function(match, name, op, args) {
1172
1146
  return (
1173
1147
  (op === "!" && (bindOnce[i] = match)) ?
1174
1148
  "($el[$a]=$el[$a].replace($o[" + (i++)+ "],''),0)||" :
1175
1149
  ""
1176
- ) + "$b['" + (bindings[name] ? name + "'].call($s,$el" : "set']($el,'" + name + "'") + (args ? "," + args.replace(/^\s*(\w+) in /,"'$1',") : "") + ")||"
1150
+ ) + "$b['" + (bindings[name] ? name + "'].call($s,$el" : "set']($el,'" + name + "'") + (args ? "," + replace(args, /^\s*(\w+) in /,"'$1',") : "") + ")||"
1177
1151
  }) + "$r)"
1178
- var vars = fn.replace(fnRe, "").match(wordRe) || []
1152
+ var vars = replace(fn, fnRe, "").match(wordRe) || []
1179
1153
  for (i = vars.length; i--; ) {
1180
1154
  if (vars.indexOf(vars[i]) !== i) vars.splice(i, 1)
1181
1155
  else vars[i] += "=$s." + vars[i]
1182
1156
  }
1183
- fn = Function("$el,$s,$a,$r", "var " + vars + ";return " + fn)
1157
+ fn = Function("$el,$s,$a,$o,$r", "var " + vars + ";return " + fn)
1184
1158
  fn.o = bindOnce
1185
1159
  return fn
1186
1160
  }
1187
1161
 
1188
1162
  /*** kb ***/
1189
1163
  var kbMaps = []
1190
- , kbMod = LiteJS.kbMod = iOS ? "metaKey" : "ctrlKey"
1164
+ , kbMod = LiteJS.kbMod = /^(Mac|iP)/.test(navigator.platform) ? "metaKey" : "ctrlKey"
1191
1165
  , kbCodes = LiteJS.kbCodes = ",,,,,,,,backspace,tab,,,,enter,,,shift,ctrl,alt,pause,caps,,,,,,,esc,,,,,,pgup,pgdown,end,home,left,up,right,down,,,,,ins,del,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,cmd,,,,,,,,,,,,,,,,,,,,,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12".split(splitRe)
1192
1166
 
1193
1167
  El.addKb = addKb
@@ -1207,8 +1181,8 @@
1207
1181
  function runKb(e, code, chr) {
1208
1182
  var fn, map
1209
1183
  , i = 0
1210
- , el = e.target || e.srcElement
1211
- , input = /INPUT|TEXTAREA|SELECT/i.test((el.nodeType == 3 ? el.parentNode : el).tagName)
1184
+ , el = e.target
1185
+ , input = /INPUT|TEXTAREA|SELECT/i.test((el.nodeType < 2 ? el : el.parentNode).tagName)
1212
1186
 
1213
1187
  for (; (map = kbMaps[i++]) && (
1214
1188
  !(fn = !input || map.input ? map[code] || map[chr] || map.num && code > 47 && code < 58 && (chr|=0, map.num) || map.all : fn) &&
@@ -1245,15 +1219,14 @@
1245
1219
  /**/
1246
1220
 
1247
1221
  /*** touch ***/
1248
- var touchEl, touchDist, touchAngle, touchMode
1222
+ var touchEl, touchDist, touchAngle, touchMode, touchTick
1249
1223
  , START = "start"
1250
1224
  , END = "end"
1251
- , MS_WHICH = [0, 1, 4, 2]
1252
1225
  , touches = []
1253
1226
  , touchEv = {}
1254
1227
 
1255
1228
  // tap, swipe + left/right/up/down
1256
- each("pan pinch rotate", function(name) {
1229
+ each("pan pinch rotate tap", function(name) {
1257
1230
  fixEv[name] = fixEv[name + START] = fixEv[name + END] = ""
1258
1231
  fixFn[name] = touchInit
1259
1232
  })
@@ -1265,107 +1238,110 @@
1265
1238
  bindingsCss(el, "touchAction msTouchAction", "none")
1266
1239
  el._ti = 1
1267
1240
  }
1268
- }
1269
- function touchDown(e, e2) {
1270
- var len = e ? touches.push(e) : touches.length
1271
- , MOVE = "pointermove"
1272
- if (touchMode) {
1273
- elEmit(touchEl, touchMode + END, e2, touchEv, touchEl)
1274
- touchMode = UNDEF
1275
- }
1276
- if (len === 0) {
1277
- touchEl = null
1278
- }
1279
- if (len === 1) {
1280
- if (e) {
1281
- touchEl = e.currentTarget || e.target
1282
- if (e.button === 2 || matches(e.target, "INPUT,TEXTAREA,SELECT,.no-drag")) return
1283
- } else {
1284
- e = touches[0]
1241
+ function touchDown(e, e2) {
1242
+ clearTimeout(touchTick)
1243
+ var len = e ? touches.push(e) : touches.length
1244
+ , MOVE = "pointermove"
1245
+ if (touchMode || len < 1) {
1246
+ elEmit(touchEl, touchMode ? touchMode + END : "tap", e2, touchEv, touchEl)
1247
+ touchMode = UNDEF
1285
1248
  }
1286
- touchEv.X = e.clientX
1287
- touchEv.Y = e.clientY
1288
- touchPos("left", "offsetWidth")
1289
- touchPos("top", "offsetHeight")
1290
- moveOne(e)
1291
- }
1292
- if (len === 2) {
1293
- touchDist = touchAngle = null
1294
- moveTwo(e)
1295
- }
1296
- ;(len === 1 ? addEvent : rmEvent)(document, MOVE, moveOne)
1297
- ;(len === 2 ? addEvent : rmEvent)(document, MOVE, moveTwo)
1298
- return eventStop(e)
1299
- function touchPos(name, offset) {
1300
- var val = (
1301
- touchEl.getBBox ?
1302
- touchEl.getAttributeNS(null, name == "top" ? "y":"x") :
1303
- touchEl.style[name]
1304
- )
1305
- touchEv[name] = parseInt(val, 10) || 0
1306
- if (val && val.indexOf("%") > -1) {
1307
- touchEv[name] *= touchEl.parentNode[offset] / 100
1249
+ if (len < 0) {
1250
+ touchEl = UNDEF
1308
1251
  }
1309
- }
1310
- }
1311
- function touchUp(e) {
1312
- for (var i = touches.length; i--; ) {
1313
- if (touches[i].pointerId == e.pointerId) {
1314
- touches.splice(i, 1)
1315
- break
1252
+ if (len === 1) {
1253
+ if (e) {
1254
+ touchEl = e.currentTarget || e.target
1255
+ touchEv.X = e.clientX
1256
+ touchEv.Y = e.clientY
1257
+ touchPos("left", "offsetWidth")
1258
+ touchPos("top", "offsetHeight")
1259
+ if (e.button === 2 || matches(touchEl, "INPUT,TEXTAREA,SELECT,.no-drag")) return
1260
+ touchTick = setTimeout(moveOne, 1500, e, 1)
1261
+ }
1262
+ moveOne(e || touches[0])
1316
1263
  }
1317
- }
1318
- touchDown(null, e)
1319
- }
1320
- function touchWheel(e) {
1321
- // IE10 enabled pinch-to-zoom gestures from multi-touch trackpad’s as mousewheel event with ctrlKey.
1322
- // Chrome M35 and Firefox 55 followed up.
1323
- if (!touches[0]) {
1324
- var ev = e.ctrlKey ? "pinch" : e.altKey ? "rotate" : UNDEF
1325
- if (ev && emit.call(e.currentTarget || e.target, ev, e, e.deltaY/20, 0)) {
1326
- return eventStop(e)
1264
+ if (len === 2) {
1265
+ touchDist = touchAngle = UNDEF
1266
+ moveTwo(e)
1267
+ }
1268
+ ;(len === 1 ? addEvent : rmEvent)(document, MOVE, moveOne)
1269
+ ;(len === 2 ? addEvent : rmEvent)(document, MOVE, moveTwo)
1270
+ function touchPos(name, offset) {
1271
+ var val = (
1272
+ touchEl.getBBox ?
1273
+ touchEl.getAttributeNS(null, name == "top" ? "y":"x") :
1274
+ touchEl.style[name]
1275
+ )
1276
+ touchEv[name] = parseInt(val, 10) || 0
1277
+ if (val && val.indexOf("%") > -1) {
1278
+ touchEv[name] *= touchEl.parentNode[offset] / 100
1279
+ }
1327
1280
  }
1328
1281
  }
1329
- }
1330
- function moveOne(e) {
1331
- // In IE9 mousedown.buttons is OK but mousemove.buttons == 0
1332
- if (touches[0].buttons && touches[0].buttons !== (e.buttons || MS_WHICH[e.which || 0])) {
1333
- return touchUp(e)
1282
+ function touchUp(e) {
1283
+ for (var i = touches.length; i--; ) {
1284
+ if (touches[i].pointerId == e.pointerId) {
1285
+ touches.splice(i, 1)
1286
+ break
1287
+ }
1288
+ }
1289
+ touchDown(UNDEF, e)
1290
+ }
1291
+ function touchWheel(e) {
1292
+ // IE10 enabled pinch-to-zoom gestures from multi-touch trackpad’s as mousewheel event with ctrlKey.
1293
+ // Chrome M35 and Firefox 55 followed up.
1294
+ if (!touches[0]) {
1295
+ var ev = e.ctrlKey ? "pinch" : e.altKey ? "rotate" : UNDEF
1296
+ if (ev && emit.call(e.currentTarget || e.target, ev, e, e.deltaY/20, 0)) {
1297
+ return eventStop(e)
1298
+ }
1299
+ }
1334
1300
  }
1335
- touchEv.x = e.clientX - touchEv.X
1336
- touchEv.y = e.clientY - touchEv.Y
1337
- touchEv.leftPos = touchEv.x + touchEv.left
1338
- touchEv.topPos = touchEv.y + touchEv.top
1339
- if (!touchMode) {
1340
- var evs = touchEl._e
1341
- touchMode = (
1342
- evs.pan && (touchEv.x > 10 || touchEv.x < -10 || touchEv.y > 10 || touchEv.y < -10) ? "pan" :
1343
- UNDEF
1344
- )
1345
- if (!touchMode) return
1346
- elEmit(touchEl, touchMode + START, e, touchEv, touchEl)
1301
+ function moveOne(e, fromTimer) {
1302
+ // In IE9 mousedown.buttons is OK but mousemove.buttons == 0
1303
+ if (touches[0].buttons && touches[0].buttons !== (e.buttons || [0, 1, 4, 2][e.which || 0])) {
1304
+ return touchUp(e)
1305
+ }
1306
+ touchEv.x = e.clientX - touchEv.X
1307
+ touchEv.y = e.clientY - touchEv.Y
1308
+ touchEv.leftPos = touchEv.x + touchEv.left
1309
+ touchEv.topPos = touchEv.y + touchEv.top
1310
+ if (!touchMode) {
1311
+ var evs = touchEl._e
1312
+ touchMode = (
1313
+ haveEv("pan", touchEv.x > 10 || touchEv.x < -10 || touchEv.y > 10 || touchEv.y < -10) ||
1314
+ haveEv("hold", fromTimer)
1315
+ )
1316
+ if (!touchMode) return
1317
+ clearTimeout(touchTick)
1318
+ elEmit(touchEl, touchMode + START, e, touchEv, touchEl)
1319
+ }
1320
+ elEmit(touchEl, touchMode, e, touchEv, touchEl)
1321
+ function haveEv(name, set) {
1322
+ return set && (evs[name] || evs[name + START] || evs[name + END]) && name
1323
+ }
1347
1324
  }
1348
- elEmit(touchEl, touchMode, e, touchEv, touchEl)
1349
- }
1350
- function moveTwo(e) {
1351
- touches[ touches[0].pointerId == e.pointerId ? 0 : 1] = e
1352
- var diff
1353
- , x = touchEv.X - touches[1].clientX
1354
- , y = touchEv.Y - touches[1].clientY
1355
- , dist = Math.sqrt(x*x + y*y) | 0
1356
- , angle = Math.atan2(y, x)
1357
-
1358
- if (touchDist !== null) {
1359
- diff = dist - touchDist
1360
- if (diff) elEmit(touchEl, "pinch", e, diff, angle)
1361
- // GestureEvent onGestureChange: function(e) {
1362
- // e.target.style.transform =
1363
- // 'scale(' + e.scale + startScale + ') rotate(' + e.rotation + startRotation + 'deg)'
1364
- diff = angle - touchAngle
1365
- if (diff) elEmit(touchEl, "rotate", e, diff * (180/Math.PI))
1325
+ function moveTwo(e) {
1326
+ touches[ touches[0].pointerId == e.pointerId ? 0 : 1] = e
1327
+ var diff
1328
+ , x = touchEv.X - touches[1].clientX
1329
+ , y = touchEv.Y - touches[1].clientY
1330
+ , dist = Math.sqrt(x*x + y*y) | 0
1331
+ , angle = Math.atan2(y, x)
1332
+
1333
+ if (touchDist !== UNDEF) {
1334
+ diff = dist - touchDist
1335
+ if (diff) elEmit(touchEl, "pinch", e, diff, angle)
1336
+ // GestureEvent onGestureChange: function(e) {
1337
+ // e.target.style.transform =
1338
+ // 'scale(' + e.scale + startScale + ') rotate(' + e.rotation + startRotation + 'deg)'
1339
+ diff = angle - touchAngle
1340
+ if (diff) elEmit(touchEl, "rotate", e, diff * (180/Math.PI))
1341
+ }
1342
+ touchDist = dist
1343
+ touchAngle = angle
1366
1344
  }
1367
- touchDist = dist
1368
- touchAngle = angle
1369
1345
  }
1370
1346
  /**/
1371
1347
 
@@ -1379,41 +1355,39 @@
1379
1355
  return el && html.matches.call(el, sel)
1380
1356
  }
1381
1357
  function closest(el, sel) {
1382
- return el && html.closest.call(el.closest ? el : el.parentNode, sel)
1358
+ return el && html.closest.call(el.nodeType < 2 ? el : el.parentNode, sel)
1359
+ }
1360
+ function walk(attr, el, sel) {
1361
+ for (; el && !matches(el = el[attr], sel); );
1362
+ return el
1383
1363
  }
1384
1364
  function acceptMany(fn, prepareVal) {
1385
- return function f(el, names, selector, data, val, delay) {
1386
- if (el && names) {
1365
+ return function f(el, name, val, selector, delay, data) {
1366
+ if (el && name) {
1387
1367
  var i = arguments.length
1388
- if (i == 3 || i == 4 && isNum(data)) {
1389
- delay = data
1390
- val = selector
1391
- selector = data = null
1392
- } else if (i == 4 || i == 5 && isNum(val)) {
1393
- delay = val
1394
- val = data
1395
- if (isStr(selector)) {
1396
- data = null
1397
- } else {
1398
- data = selector
1399
- selector = null
1400
- }
1368
+ if (i > 3 && i < 6 && isNum(selector)) {
1369
+ data = delay
1370
+ delay = selector
1371
+ selector = UNDEF
1401
1372
  }
1402
1373
  if (delay > 0) {
1403
- setTimeout(f, delay, el, names, selector, data, val, 0)
1374
+ setTimeout(f, delay, el, name, val, selector, 0, data)
1404
1375
  return
1405
1376
  }
1406
- if (isObj(names)) {
1407
- for (delay in names) if (hasOwn.call(names, delay)) {
1408
- f(el, delay, selector, data, names[delay])
1377
+ if (isObj(name)) {
1378
+ for (delay in name) if (hasOwn.call(name, delay)) {
1379
+ f(el, delay, name[delay], selector, 0, data)
1409
1380
  }
1410
1381
  return
1411
1382
  }
1412
- if (prepareVal) val = prepareVal(el, selector, data, val)
1413
- selector = !prepareVal && selector ? findAll(el, selector) : [ el ]
1414
- var arr = ("" + names).split(splitRe), len = arr.length
1415
- for (delay = 0; (el = selector[delay++]); )
1416
- for (i = 0; i < len; ) if (arr[i]) fn(el, arr[i++], isArr(val) ? val[i - 1] : val)
1383
+ if (prepareVal) val = prepareVal(el, val, selector, data)
1384
+ selector = !prepareVal && selector ? findAll(el, selector) : isArr(el) ? el : [ el ]
1385
+ var arr = ("" + name).split(splitRe), len = arr.length
1386
+ for (delay = 0; (el = selector[delay++]); ) {
1387
+ for (i = 0; i < len; ) {
1388
+ if (arr[i]) fn(el, arr[i++], isArr(val) ? val[i - 1] : val)
1389
+ }
1390
+ }
1417
1391
  }
1418
1392
  }
1419
1393
  }
@@ -1435,9 +1409,11 @@
1435
1409
  return a.toUpperCase()
1436
1410
  }
1437
1411
  function each(arr, fn, scope, key) {
1438
- if (isStr(arr)) arr = arr.split(splitRe)
1439
- if (isArr(arr)) arr.forEach(fn, scope)
1440
- else if (arr) for (key in arr) if (hasOwn.call(arr, key)) fn.call(scope, arr[key], key, arr)
1412
+ if (arr) {
1413
+ if (isStr(arr)) arr = arr.split(splitRe)
1414
+ if (isArr(arr)) arr.forEach(fn, scope)
1415
+ else for (key in arr) if (hasOwn.call(arr, key)) fn.call(scope, arr[key], key, arr)
1416
+ }
1441
1417
  }
1442
1418
  function expand(str) {
1443
1419
  var first = str.charAt(0)
@@ -1449,7 +1425,7 @@
1449
1425
  )
1450
1426
  }
1451
1427
  function format(str, data) {
1452
- return str.replace(formatRe, function(all, path) {
1428
+ return replace(str, formatRe, function(all, path) {
1453
1429
  return get(data, path, "")
1454
1430
  })
1455
1431
  }
@@ -1461,6 +1437,15 @@
1461
1437
  isArr(path) ? get(obj, path[0]) || get(obj, path[1]) || get(obj, path[2], fallback) :
1462
1438
  fallback
1463
1439
  }
1440
+ function logErr(e, source, node) {
1441
+ /*** debug ***/
1442
+ console.error(e)
1443
+ console.error(source, node)
1444
+ /**/
1445
+ if (window.onerror) {
1446
+ window.onerror(e.message, e.fileName, e.lineNumber)
1447
+ }
1448
+ }
1464
1449
  function injectCss(cssText) {
1465
1450
  if (!styleNode) {
1466
1451
  // Safari and IE6-8 requires dynamically created
@@ -1483,13 +1468,12 @@
1483
1468
  function isStr(str) {
1484
1469
  return typeof str === "string"
1485
1470
  }
1486
- // Maximum call rate for Function
1487
- // leading edge, trailing edge
1471
+ // Maximum call rate for Function with optional leading edge and trailing edge
1488
1472
  function rate(fn, ms, onStart, onEnd) {
1489
1473
  var tick
1490
1474
  , next = 0
1491
- onStart = isFn(onStart) ? onStart : (onStart === UNDEF || onStart) && fn
1492
- onEnd = isFn(onEnd) ? onEnd : (onEnd === UNDEF || onEnd) && fn
1475
+ onStart = isFn(onStart) ? onStart : (onStart === tick || onStart) && fn
1476
+ onEnd = isFn(onEnd) ? onEnd : (onEnd === tick || onEnd) && fn
1493
1477
  return function() {
1494
1478
  var now = Date.now()
1495
1479
  clearTimeout(tick)
@@ -1498,7 +1482,8 @@
1498
1482
  if (onStart) onStart()
1499
1483
  } else fn()
1500
1484
  next = now + ms
1501
- } else if (onEnd) {
1485
+ }
1486
+ if (onEnd) {
1502
1487
  tick = setTimeout(onEnd, next - now)
1503
1488
  }
1504
1489
  }
@@ -1523,14 +1508,14 @@
1523
1508
  elKill(el)
1524
1509
  return el.src
1525
1510
  }), function(res) {
1526
- res = res.concat(sources).filter(Boolean)
1511
+ res = res.concat(sources, (next || res).innerHTML).filter(Boolean)
1527
1512
  if (res[sources.length = 0]) {
1528
1513
  if (!parser) LiteJS.ui = LiteJS()
1529
1514
  each(res, parser)
1530
1515
  }
1531
- if (next) next()
1516
+ if (isFn(next)) next()
1532
1517
  }, 1)
1533
1518
  }
1534
- readTemplates()
1519
+ readTemplates(findAll(html, "script").pop())
1535
1520
  }(this, document, history, localStorage, location, navigator, Function, Object) // jshint ignore:line
1536
1521