@litejs/ui 24.7.0 → 24.11.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.
package/ui.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /* litejs.com/MIT-LICENSE.txt */
3
3
 
4
- /* global xhr, navigator */
4
+ /* global escape, navigator, xhr */
5
5
 
6
6
  /*** debug ***/
7
7
  console.log("LiteJS is in debug mode, but it's fine for production")
@@ -12,17 +12,22 @@ console.log("LiteJS is in debug mode, but it's fine for production")
12
12
  asEmitter(window.LiteJS = LiteJS)
13
13
 
14
14
  var UNDEF, lastExp, parser, pushBase, styleNode
15
+ , NUL = null
15
16
  , html = document.documentElement
16
17
  , body = document.body
17
18
  , splitRe = /[,\s]+/
18
19
  , emptyArr = []
20
+ , plugins = {}
21
+ , sources = []
19
22
  , assign = Object.assign
23
+ , bind = El.bind.bind(El.call)
20
24
  , create = Object.create
25
+ , hasOwn = bind(plugins.hasOwnProperty)
21
26
  , isArr = Array.isArray
22
27
  , 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)")
28
+ , elReplace = Function("a,b,c", "a&&b&&(c=a.parentNode)&&c.replaceChild(b,a)")
29
+ , elRm = Function("a,b", "a&&(b=a.parentNode)&&b.removeChild(a)")
30
+ , getAttr = Function("a,b", "return a&&a.getAttribute&&a.getAttribute(b)")
26
31
  , replace = Function("a,b,c", "return a.replace(b,c)")
27
32
 
28
33
  // JScript engine in IE8 and below does not recognize vertical tabulation character `\v`.
@@ -32,8 +37,8 @@ console.log("LiteJS is in debug mode, but it's fine for production")
32
37
  , BIND_ATTR = "data-bind"
33
38
  , elSeq = 0
34
39
  , elCache = {}
35
- , formatRe = /{((?:("|')(?:\\\2|[\s\S])*?\2|[^"'{}])+?)}/g
36
- , renderRe = /[;\s]*([-\w$]+)(?:([ :!])((?:(["'\/])(?:\\.|[^\\])*?\4|[^;])*))?/g
40
+ , formatRe = /{((?:("|')(?:\\.|[^\\])*?\2|.)+?)}/g
41
+ , renderRe = /[;\s]*([-.\w$]+)(?:([ :!])((?:(["'\/])(?:\\.|[^\\])*?\4|[^;])*))?/g
37
42
  , selectorRe = /([.#:[])([-\w]+)(?:([~^$*|]?)=(("|')(?:\\.|[^\\])*?\5|[-\w]+))?]?/g
38
43
  , templateRe = /([ \t]*)(%?)((?:("|')(?:\\.|[^\\])*?\4|[-\w:.#[\]~^$*|]=?)*) ?([\/>+=@^;]|)(([\])}]?).*?([[({]?))(?=\x1f|\n|$)+/g
39
44
  , fnCache = {}
@@ -42,14 +47,14 @@ console.log("LiteJS is in debug mode, but it's fine for production")
42
47
  , camelRe = /\-([a-z])/g
43
48
  // innerText is implemented in IE4, textContent in IE9, Node.text in Opera 9-10
44
49
  // Safari 2.x innerText results an empty string when style.display=="none" or Node is not in DOM
45
- , txtAttr = "textContent" in html ? "textContent" : "innerText"
50
+ , txtAttr = "textContent" in html ? "textContent" /* c8 ignore next */ : "innerText"
46
51
  , bindingsCss = acceptMany(function(el, key, val) {
47
52
  el.style[replace(key, camelRe, camelFn)] = val
48
53
  })
49
54
  , bindingsOn = acceptMany(addEvent, function(el, val, selector, data) {
50
55
  return isStr(val) ? function(e) {
51
56
  var target = selector ? closest(e.target, selector) : el
52
- if (target) emit.apply(elScope(el).$ui, [val, e, target].concat(data))
57
+ if (target) emit.apply(target, [elScope(el).$ui, val, e, target].concat(data))
53
58
  } :
54
59
  selector ? function(e, a1, a2) {
55
60
  if (matches(e.target, selector)) val(e, a1, a2)
@@ -69,8 +74,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
69
74
  }
70
75
  , globalScope = {
71
76
  El: El,
72
- _: format,
73
- _f: format,
74
77
  $b: bindings
75
78
  }
76
79
  , elArr = {
@@ -89,14 +92,60 @@ console.log("LiteJS is in debug mode, but it's fine for production")
89
92
  return deep
90
93
  }
91
94
  }
92
- , plugins = {}
93
- , sources = []
94
- , hasOwn = plugins.hasOwnProperty
95
95
 
96
96
  , Event = window.Event || window
97
97
  , fixEv = Event.fixEv || (Event.fixEv = {})
98
98
  , fixFn = Event.fixFn || (Event.fixFn = {})
99
99
 
100
+ /*** markup ***/
101
+ , blockRe = /^(?:(=+|>| -) ([\s\S]+)|\[! *(\S*) *!] ?(.*))/
102
+ , tags = {
103
+ " -": "ul",
104
+ "!": "a",
105
+ "*": "b",
106
+ "+": "ins",
107
+ ",": "sub",
108
+ "-": "del",
109
+ "/": "i",
110
+ ":": "mark",
111
+ ";": "span",
112
+ ">": "blockquote",
113
+ "@": "time",
114
+ "^": "sup",
115
+ "_": "u",
116
+ "`": "code",
117
+ "~": "s"
118
+ }
119
+ function inline(tag, op, text, name, link, attr) {
120
+ return op && !isArr(text) ? "<" +
121
+ (tag = tags[op] || "h" + op.length) +
122
+ (tag == "a" ? " href=\"" + (link || text) + "\"" : op == "@" ? " datetime=\"" + name + "\"" : "") +
123
+ (attr ? " class=\"" + attr.slice(1) + "\">" : ">") +
124
+ (
125
+ op === ">" ? doc(replace(text, /^> ?/gm, "")) :
126
+ tag == "ul" ? "<li>" + text.split(/\n - (?=\S)/).map(inline).join("</li>\n<li>") + "</li>" :
127
+ inline(tag == "a" ? replace(name, /^\w+:\/{0,2}/, "") : text)
128
+ ) +
129
+ "</" + tag + ">" :
130
+ replace(tag, /\[([-!*+,/:;@^_`~])((.+?)(?: (\S+?))?)\1(\.[.\w]+)?]/g, inline)
131
+ }
132
+ function block(tag, op, text, media, alt) {
133
+ return op && !isArr(text) ? inline(tag, op, text) :
134
+ media ? "<img src=\"" + media + "\" alt=\"" + alt + "\">" :
135
+ blockRe.test(tag) ? replace(tag, blockRe, block) :
136
+ tag === "---" ? "<hr>" : "<p>" + inline(tag) + "</p>"
137
+ }
138
+ function doc(txt) {
139
+ return replace(txt.trim(), /^ \b/gm, "<br>").split(/\n\n+/).map(block).join("\n")
140
+ }
141
+ bindings.t = function(el, text) {
142
+ el.innerHTML = inline(replace(text, /</g, "&lt;"))
143
+ }
144
+ bindings.d = function(el, text) {
145
+ el.innerHTML = doc(replace(text, /</g, "&lt;"))
146
+ }
147
+ /**/
148
+
100
149
  /*** svg ***/
101
150
  bindings.xlink = function(el, href) {
102
151
  // In SVG2, xlink namespace is not needed, plain href can be used (Chrome50 2016, Firefox51 2017).
@@ -110,26 +159,29 @@ console.log("LiteJS is in debug mode, but it's fine for production")
110
159
  }
111
160
  /**/
112
161
 
113
- Event.asEmitter = asEmitter
114
- Event.stop = eventStop
115
-
116
162
  xhr.css = injectCss
117
- xhr.ui = sources.push.bind(sources)
163
+ xhr.ui = function(src) {
164
+ sources.push(src)
165
+ }
118
166
 
119
167
  function asEmitter(obj) {
120
168
  obj.on = on
121
169
  obj.off = off
122
170
  obj.one = one
123
- obj.emit = emit
171
+ obj.emit = wrap(emit)
124
172
  // emitNext, emitLate
173
+ function wrap(fn) {
174
+ return function(a, b, c, d, e) {
175
+ return fn(this, a, b, c, d, e)
176
+ }
177
+ }
125
178
  }
126
179
 
127
180
  function on(type, fn, scope, _origin) {
128
181
  var emitter = this === window ? emptyArr : this
129
- , events = emitter._e || (emitter._e = create(null))
182
+ , events = emitter._e || (emitter._e = create(NUL))
130
183
  if (type && fn) {
131
- if (isStr(fn)) fn = emit.bind(emitter, fn)
132
- emit.call(emitter, "newListener", type, fn, scope, _origin)
184
+ emit(emitter, "newListener", type, fn, scope, _origin)
133
185
  ;(events[type] || (events[type] = [])).unshift(scope, _origin, fn)
134
186
  }
135
187
  return this
@@ -143,7 +195,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
143
195
  for (i = events.length - 2; i > 0; i -= 3) {
144
196
  if ((events[i + 1] === fn || events[i] === fn) && events[i - 1] == scope) {
145
197
  args = events.splice(i - 1, 3)
146
- emit.call(emitter, "removeListener", type, args[2], args[0], args[1])
198
+ emit(emitter, "removeListener", type, args[2], args[0], args[1])
147
199
  if (fn) break
148
200
  }
149
201
  }
@@ -162,13 +214,13 @@ console.log("LiteJS is in debug mode, but it's fine for production")
162
214
  return this
163
215
  }
164
216
 
165
- function emit(type) {
217
+ function emit(emitter, type) {
218
+ if (emitter === window) emitter = emptyArr
166
219
  var args, i
167
- , emitter = this === window ? emptyArr : this
168
220
  , _e = emitter._e
169
221
  , arr = _e ? (_e[type] || emptyArr).concat(_e["*"] || emptyArr) : emptyArr
170
222
  if ((_e = arr.length)) {
171
- for (i = _e - 1, args = slice.call(arguments, 1); i > 1; i -= 3) {
223
+ for (i = _e - 1, args = slice.call(arguments, 2); i > 1; i -= 3) {
172
224
  if (arr[i]) arr[i].apply(arr[i - 2] || emitter, args)
173
225
  }
174
226
  }
@@ -214,7 +266,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
214
266
 
215
267
  function LiteJS(opts) {
216
268
  opts = assign({
217
- path: "",
218
269
  /*** breakpoints ***/
219
270
  breakpoints: {
220
271
  sm: 0,
@@ -255,45 +306,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
255
306
 
256
307
  asEmitter(View)
257
308
  asEmitter(View.prototype = {
258
- show: function(_params) {
259
- var parent
260
- , params = lastParams = _params || {} // jshint ignore:line
261
- , view = lastView = this // jshint ignore:line
262
- , tmp = params._v || view // Continue bubbleUp from _v
263
-
264
- params._c = view.o ? view : params._c
265
- for (View.route = view.r; tmp; tmp = parent) {
266
- viewEmit(syncResume = params._v = tmp, "ping", params, View)
267
- syncResume = UNDEF
268
- if (lastParams !== params) return
269
- if ((parent = tmp.p)) {
270
- if (parent.c && parent.c !== tmp) {
271
- params._c = parent.c
272
- }
273
- parent.c = tmp
274
- }
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")
283
- }
284
- return View("404").show({origin:params})
285
- }
286
- }
287
-
288
- for (tmp in params) {
289
- if (tmp.charAt(0) !== "_" && (syncResume = hasOwn.call(paramCb, tmp) && paramCb[tmp] || paramCb["*"])) {
290
- syncResume(params[tmp], tmp, view, params)
291
- syncResume = UNDEF
292
- }
293
- }
294
- viewEmit(view, "nav")
295
- bubbleDown(params)
296
- },
297
309
  wait: function() {
298
310
  var params = lastParams
299
311
  params._p = 1 + (params._p | 0) // pending
@@ -302,14 +314,13 @@ console.log("LiteJS is in debug mode, but it's fine for production")
302
314
  if (params._d) {
303
315
  bubbleDown(params)
304
316
  } else if (params._v) {
305
- lastView.show(params)
317
+ viewPing(lastView, params)
306
318
  }
307
319
  }
308
320
  }
309
321
  })
310
322
 
311
- var root = opts.root
312
- , viewFn, lastView, lastUrl, syncResume
323
+ var viewFn, lastView, lastUrl, syncResume
313
324
  , fnStr = ""
314
325
  , reStr = ""
315
326
  , reEsc = /[.*+?^${}()|[\]/\\]/g
@@ -319,11 +330,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
319
330
  , views = View.views = {}
320
331
  , paramCb = {}
321
332
  , lastParams = paramCb
322
- , $d = elScope(View("#", root).e, root)
333
+ , root = View("#", opts.root).e
334
+ , $d = elScope(root, root)
323
335
 
324
336
  $d.$ui = assign(View, {
325
- $: find.bind(View, root),
326
- $$: findAll.bind(View, root),
337
+ $: bind(find, View, root),
338
+ $$: bind(findAll, View, root),
327
339
  $d: $d,
328
340
  def: viewDef,
329
341
  get: viewGet,
@@ -349,14 +361,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
349
361
  }
350
362
  })
351
363
 
352
- function appendBind(el, val, sep, q) {
353
- var current = getAttr(el, BIND_ATTR)
354
- setAttr(el, BIND_ATTR, (current ? (
355
- q === "^" ?
356
- val + sep + current :
357
- current + sep + val
358
- ) : val))
359
- }
360
364
  function bubbleDown(params) {
361
365
  var view = params._v
362
366
  , close = params._c
@@ -404,15 +408,15 @@ console.log("LiteJS is in debug mode, but it's fine for production")
404
408
  }
405
409
  }
406
410
  function viewEmit(view, event, a, b) {
407
- view.emit(event, a, b)
408
- View.emit(event, view, a, b)
409
- LiteJS.emit(event, view, a, b)
411
+ emit(view, event, a, b)
412
+ emit(View, event, view, a, b)
413
+ emit(LiteJS, event, view, a, b)
410
414
  }
411
415
  function viewEval(str, scope) {
412
416
  try {
413
417
  Function("$s,$ui,$d,$,$$", str)(scope, View, $d, View.$, View.$$)
414
418
  } catch(e) {
415
- logErr(e, "viewEval: " + str)
419
+ throw e + "\nviewEval: " + str
416
420
  }
417
421
  }
418
422
  function viewGet(url, params) {
@@ -468,7 +472,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
468
472
  append(parent, text) // + "\n")
469
473
  } else {
470
474
  if (op === "") {
471
- text = "txt _('" + replace(text, /'/g, "\\'") + "',$s)"
475
+ text = "txt _(" + quote(text) + ",$s)"
472
476
  }
473
477
  appendBind(parent, text, ";", op)
474
478
  }
@@ -488,17 +492,55 @@ console.log("LiteJS is in debug mode, but it's fine for production")
488
492
  histStart(viewShow)
489
493
  }
490
494
  }
491
- function viewShow(url, _params) {
495
+ function viewPing(view, params) {
496
+ var parent
497
+ , tmp = params._v || view // Continue bubbleUp from _v
498
+ lastParams = params
499
+ lastView = view
500
+ params._c = view.o ? view : params._c
501
+ for (View.route = view.r; tmp; tmp = parent) {
502
+ viewEmit(syncResume = params._v = tmp, "ping", params, View)
503
+ syncResume = UNDEF
504
+ if (lastParams !== params) return
505
+ if ((parent = tmp.p)) {
506
+ if (parent.c && parent.c !== tmp) {
507
+ params._c = parent.c
508
+ }
509
+ parent.c = tmp
510
+ }
511
+ if (tmp.f) {
512
+ return xhr.load(
513
+ replace(tmp.f, /^|,/g, "$&" + (View.path || "")).split(","),
514
+ bind(readTemplates, view, view.wait(tmp.f = ""))
515
+ )
516
+ } else if (!tmp.e) {
517
+ if (tmp.r === "404") {
518
+ viewParse("%view 404 #\nh2 Not found")
519
+ }
520
+ return viewShow("404")
521
+ }
522
+ }
523
+
524
+ for (tmp in params) {
525
+ if (tmp.charAt(0) !== "_" && (syncResume = hasOwn(paramCb, tmp) && paramCb[tmp] || paramCb["*"])) {
526
+ syncResume(params[tmp], tmp, view, params)
527
+ syncResume = UNDEF
528
+ }
529
+ }
530
+ viewEmit(view, "nav")
531
+ bubbleDown(params)
532
+ }
533
+ function viewShow(url) {
492
534
  if (url === true) {
493
535
  if (lastParams._p > 0) return
494
536
  url = lastUrl
495
537
  lastUrl = 0
496
538
  }
497
- var params = _params || {}
539
+ var params = $d.params = { _t: Date.now() }
498
540
  , view = viewGet(url, params)
499
541
  if (!view.o || lastUrl !== url) {
500
542
  $d.url = lastExp = lastUrl = url
501
- view.show($d.params = params)
543
+ viewPing(view, params)
502
544
  }
503
545
  }
504
546
 
@@ -523,7 +565,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
523
565
  plugin.e.p = plugin
524
566
  }
525
567
  }
526
- if (proto.r) proto.d = Function("p", "p.r(p.o||p.t)")
568
+ if (proto.r) proto.d = Function("p", "p.r(p.o+p.t)")
527
569
  assign(Plugin.prototype, proto)
528
570
  }
529
571
  function usePluginContent(plugin) {
@@ -562,40 +604,36 @@ console.log("LiteJS is in debug mode, but it's fine for production")
562
604
  addPlugin("def", { r: viewDef })
563
605
  addPlugin("js", { r: viewEval })
564
606
  addPlugin("each", {
565
- r: function(params) {
607
+ r: function() {
566
608
  var txt = this.t
567
- each(params, function(param) {
609
+ each(this.o, function(param) {
568
610
  viewParse(replace(txt, /{key}/g, param))
569
611
  })
570
612
  }
571
613
  })
572
614
  addPlugin("el", {
573
615
  c: 1,
574
- d: function(plugin) {
575
- var parent = plugin.u
576
- , el = usePluginContent(plugin)
616
+ d: function(plugin, el) {
617
+ el = usePluginContent(plugin)
577
618
  elCache[plugin.n] = el
578
- return parent
579
619
  }
580
620
  })
581
621
  plugins.svg = plugins.el
582
622
  addPlugin("map", {
583
- r: function() {
623
+ r: function(txt) {
584
624
  var plugin = this
585
- , txt = plugin.o + plugin.t
586
625
  appendBind(plugin.u, plugin.s ? txt.slice(1) : txt, plugin.s)
587
626
  }
588
627
  })
589
628
  addPlugin("view", {
590
629
  c: 1,
591
630
  d: function(plugin) {
592
- var bind = getAttr(plugin.e, BIND_ATTR)
631
+ var expr = getAttr(plugin.e, BIND_ATTR)
593
632
  , view = View(plugin.n, usePluginContent(plugin), plugin.x)
594
- if (bind) {
595
- bind = replace(bind, renderRe, function(_, name, op, args) {
633
+ if (expr) {
634
+ viewEval(replace(expr, renderRe, function(_, name, op, args) {
596
635
  return "($s." + name + (isFn(view[name]) ? "(" + (args || "") + ")" : "=" + args) + "),"
597
- }) + "1"
598
- viewEval(bind, view)
636
+ }) + "1", view)
599
637
  }
600
638
  }
601
639
  })
@@ -625,7 +663,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
625
663
  cls(html, lastOrient = next)
626
664
  }
627
665
 
628
- View.emit("resize")
666
+ emit(View, "resize")
629
667
  }, 99)
630
668
 
631
669
  if (breakpoints) {
@@ -635,26 +673,244 @@ console.log("LiteJS is in debug mode, but it's fine for production")
635
673
  /**/
636
674
 
637
675
  /*** i18n ***/
638
- var iData = {}
639
- , iFormat = create(null)
640
- , iGlobals = assignDeep(create(null), opts.locales)
641
- each(iGlobals, function(translations, iKey) {
642
- translations = iData[iKey] = assignDeep(create(iGlobals), opts[iKey])
643
- iFormat[iKey] = function(str, data) {
644
- return format(get(translations, str, str || ""), data)
676
+ globalScope._ = format
677
+ var iFormat = create(NUL)
678
+ each(opts.locales || { en: "en" }, function(translations, lang, locales) {
679
+ translations = formatGet.t = assignDeep(assignDeep(create(opts.globals || NUL), locales), opts[lang])
680
+ formatGet.g = getExt
681
+ iFormat[lang] = formatGet
682
+ var iAlias = {
683
+ "#": "num", "num": "#",
684
+ "*": "plural", "plural": "*",
685
+ "?": "pick", "pick": "?",
686
+ "@": "date", "date": "@",
687
+ "~": "pattern", "pattern": "~"
688
+ }
689
+ , cache = create(NUL)
690
+ , dateRe = /([Md])\1\1\1?|([YMDdHhmswSZ])(\2?)|[uUaSoQ]|'((?:''|[^'])*)'|(["\\\n\r\u2028\u2029])/g
691
+ , date1 = new Date()
692
+ , date2 = new Date()
693
+ , iExt = formatGet.ext = {
694
+ date: function(input, _mask, _zone) {
695
+ var undef
696
+ , offset = 4294967295
697
+ , d = input * (input > offset || input < -offset ? 1 : 1000) || Date.parse(input)
698
+ , t = translations["@"] || {}
699
+ , mask = t[_mask] || _mask || "UTC:Y-MM-DD'T'HH:mm:ss'Z'"
700
+ , zone = _zone != undef ? _zone : Date._tz != undef ? Date._tz : undef
701
+ , utc = mask.slice(0, 4) == "UTC:"
702
+ if (zone != undef && !utc) {
703
+ offset = 60 * zone
704
+ date1.setTime(d + offset * 6e4)
705
+ utc = mask = "UTC:" + mask
706
+ } else {
707
+ date1.setTime(d)
708
+ offset = utc ? 0 : -date1.getTimezoneOffset()
709
+ }
710
+ return isNaN(d) ? "" + date1 : (
711
+ cache[mask] || (cache[mask] = Function("d,a,o,l", "var t;return \"" + dateStr(mask, utc) + "\"")))(
712
+ date1,
713
+ date2,
714
+ offset,
715
+ t
716
+ )
717
+ },
718
+ lo: function(str) {
719
+ return isStr(str) ? str.toLowerCase() : ""
720
+ },
721
+ map: function(input, str, sep, lastSep) {
722
+ var arr = []
723
+ each(input, function(val) {
724
+ arr.push(formatGet(str, val))
725
+ })
726
+ lastSep = lastSep && arr.length > 1 ? lastSep + arr.pop() : ""
727
+ return arr.join(sep || ", ") + lastSep
728
+ },
729
+ num: function(input, format) {
730
+ var t = translations["#"] || {}
731
+ return (
732
+ cache[format = t[format] || "#" + format] || (cache[format] = Function("d", "var N=d<0&&(d=-d),n,r,o;return " + numStr(format, t)))
733
+ )(input)
734
+ },
735
+ pattern: function(str, re) {
736
+ var values = []
737
+ , t = translations["~"] || {}
738
+ , key = replace(str, RegExp(re || t[""] || "[\\d.]+", "g"), function(a) {
739
+ values.push(a)
740
+ return "#"
741
+ })
742
+ return str != key && t[key] ? replace(t[key], /#/g, bind(values.shift, values)) : str
743
+ },
744
+ pick: function(val, word) {
745
+ for (var t = translations["?"] || {}, arr = replace((t[word] || word), /([^;=,]+?)\?/g, "$1=$1;").split(/[;=,]/), i = 1|arr.length; i > 0; ) {
746
+ if ((i-=2) < 0 || arr[i] && (arr[i] == "" + val || +arr[i] <= val)) {
747
+ return arr[i + 1] ? replace(arr[i + 1], "#", val) : ""
748
+ }
749
+ }
750
+ },
751
+ plural: function(n, word, expr) {
752
+ var t = translations["*"] || {}
753
+ return (
754
+ cache[expr = t[""] || "n!=1"] || (cache[expr] = Function("a,n", "return (a[+(" + expr + ")]||a[0]).replace('#',n)"))
755
+ )((t[word] || "# " + word).split(";"), n)
756
+ },
757
+ up: function(str) {
758
+ return isStr(str) ? str.toUpperCase() : ""
759
+ }
760
+ }
761
+
762
+ function dateStr(mask, utc) {
763
+ var get = "d.get" + (utc ? "UTC" : "")
764
+ , dateMap = {
765
+ d: "Day()||7",
766
+ M: "Month()+1",
767
+ D: "Date()",
768
+ H: "Hours()",
769
+ h: "Hours()%12||12",
770
+ m: "Minutes()",
771
+ s: "Seconds()",
772
+ S: "Milliseconds()"
773
+ }
774
+ , setA = "a.setTime(+d+((4-(" + get + dateMap.d + "))*864e5))"
775
+ return replace((utc ? mask.slice(4) : mask), dateRe, function(match, MD, single, pad, text, esc) {
776
+ mask = (
777
+ esc ? replace(replace(escape(esc), /%u/g, "\\u"), /%/g, "\\x") :
778
+ text !== UNDEF ? replace(text, /''/g, "'") :
779
+ MD || match == "dd" ? "l[''][" + get + (MD == "M" ? "Month()+" + (match == "MMM" ? 14 : 26) : "Day()" + (pad ? (pad = "") : "+7")) + "]" :
780
+ match == "u" ? "(d/1000)>>>0" :
781
+ match == "U" ? "+d" :
782
+ match == "Q" ? "((" + get + "Month()/3)|0)+1" :
783
+ match == "a" ? "l[" + get + dateMap.H + ">11?'pm':'am']" :
784
+ match == "o" ? setA + ",a" + get.slice(1) + "FullYear()" :
785
+ single == "Y" ? get + "FullYear()" + (pad == "Y" ? "%100" : "") :
786
+ single == "Z" ? "(t=o)?(t<0?((t=-t),'-'):'+')+(t<600?'0':'')+(0|(t/60))" + (pad ? (pad = "") : "+':'") + "+((t%=60)>9?t:'0'+t):'Z'" :
787
+ single == "w" ? "Math.ceil(((" + setA + "-a.s" + get.slice(3) + "Month(0,1))/864e5+1)/7)" :
788
+ get + dateMap[single || match]
789
+ )
790
+ return text !== UNDEF || esc ? mask : "\"+(" + (
791
+ match == "SS" ? "(t=" + mask + ")>9?t>99?t:'0'+t:'00'+t" :
792
+ pad ? "(t=" + mask + ")>9?t:'0'+t" :
793
+ mask
794
+ ) + ")+\""
795
+ })
796
+ }
797
+
798
+ function numStr(format, t) {
799
+ // format;NaN;negFormat;0;Infinity;-Infinity;roundPoint
800
+ // 🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹
801
+ var conf = format.split(";")
802
+ , nan_value = conf[1] || "-"
803
+ , o = (t.ordinal||"").split(";")
804
+ , pre = {
805
+ a: "(o+=d<1e3?'':d<1e6?(d/=1e3,'k'):d<1e9?(d/=1e6,'M'):d<1e12?(d/=1e9,'G'):d<1e15?(d/=1e12,'T'):d<1e18?(d/=1e15,'P'):(d/=1e18,'E')),"
806
+ }
807
+ , post = {
808
+ o: "r+(o=" + JSON.stringify(o.slice(0,-1)) + "," + o.pop() + ")"
809
+ }
810
+ , m2 = /([^\d#]*)([\d# .,_·']*\/?\d+)(?:(\s*)([a-z%]+)(\d*))?(.*)/.exec(conf[0])
811
+ , m3 = /([.,\/])(\d*)$/.exec(m2[2])
812
+ , decimals = m3 && m3[2].length || 0
813
+ , full = m3 ? m2[2].slice(0, m3.index) : m2[2]
814
+ , num = replace(full, /\D+/g, "")
815
+ , sLen = num.length
816
+ , step = decimals ? +(m3[1] === "/" ? 1 / m3[2] : num + "." + m3[2]) : num
817
+ , decSep = m3 && m3[1]
818
+ , fn = "d===Infinity?(N?" + quote(conf[5]||nan_value) + ":" + quote(conf[4]||nan_value) + "):d>0||d===0?(o=" + quote(m2[3]) + "," + (pre[m2[4]] || "") + "n=" + (
819
+ // Use exponential notation to fix float rounding
820
+ // Math.round(1.005*100)/100 = 1 instead of 1.01
821
+ decimals ?
822
+ "d>1e-" + (decimals + 1) + "?(n=(d+'e" + decimals + "')/" + (step + "e" + decimals) + "":
823
+ "d>"+num+"e-1?(n=d/" + num
824
+ ) + ",Math.floor(n" + (
825
+ conf[6] == 1 ? "%1?n+1:n" : "+" + (conf[6] || 0.5)
826
+ ) + ")*" + step + "):0,r=" + (
827
+ m2[5] ? "(''+(+n.toPrecision(" + (m2[5]) + ")))" :
828
+ decimals ? "n.toFixed(" + decimals + ")" :
829
+ "n+''"
830
+ )
831
+
832
+ if (decimals) {
833
+ if (decSep == "/") {
834
+ fn += ".replace(/\\.\\d+/,'" + (
835
+ m3[2] == 5 ?
836
+ "⅕⅖⅗⅘'.charAt(5" :
837
+ "⅛¼⅜½⅝¾⅞'.charAt(8"
838
+ ) + "*(n%1)-1))"
839
+ } else if (decSep != ".") {
840
+ fn += ".replace('.','" + decSep + "')"
841
+ }
842
+ if (sLen === 0) {
843
+ fn += ",n<1&&(r=r.slice(1)||'0')"
844
+ }
845
+ }
846
+ if (sLen > 1) {
847
+ if (decimals) sLen += decimals + 1
848
+ fn += ",r=(r.length<" + sLen + "?(1e15+r).slice(-" + sLen + "):r)"
849
+ }
850
+
851
+ if ((num = full.match(/[^\d#][\d#]+/g))) {
852
+ fn += ",r=" + numJunk(num.length - 1, 0, decimals ? decimals + 1 : 0)
853
+ }
854
+
855
+ fn += (
856
+ (m2[4] ? ",r=" + (post[m2[4]] || "r+o") : "") +
857
+ // negative format
858
+ ",N&&n>0?" + replace(quote(conf[2] || "-#"), "#", "'+r+'") + ":" +
859
+ (conf[3] ? "n===0?" + quote(conf[3]) + ":" : "") +
860
+ (m2[1] ? quote(m2[1]) + "+r" : "r") +
861
+ (m2[6] ? "+" + quote(m2[6]) : "")
862
+ )
863
+
864
+ return fn + "):" + quote(nan_value)
865
+
866
+ function numJunk(i, lastLen, dec) {
867
+ var len = lastLen + num[i].length - 1
868
+
869
+ return "(n<1e" + len + (
870
+ lastLen ? "?r.slice(0,-" + (lastLen + dec) + "):" : "?r:"
871
+ ) + (
872
+ len < 16 ? numJunk(i?i-1:i, len, dec) : "r.slice(0,-" + (lastLen + dec) + ")"
873
+ ) + "+" + quote(num[i].charAt(0)) + "+r.slice(-" + (len + dec) + (
874
+ lastLen ? ",-" + (lastLen + dec) : ""
875
+ ) + "))"
876
+ }
877
+ }
878
+
879
+ function formatGet(str, data) {
880
+ return format(iGet(translations, str, str || ""), data, getExt)
881
+ }
882
+ function getExt(obj, str) {
883
+ var fn = cache[str] || (cache[str] = (replace(replace(str, /;\s*([#*?@~])(.*)/, function(_, op, arg) {
884
+ return ";" + iAlias[op] + " " + quote(arg)
885
+ }), renderRe, function(_, name, op, args) {
886
+ fn = (_ === name) ? name : "$el." + name + "(" + fn + (args ? "," + args : "") + ")"
887
+ }), fn === str ? str : makeFn(fn, fn)))
888
+ return str == "$" ? obj : isStr(fn) ? iGet(obj, str, "") : isFn(fn) ? fn(iExt, obj, translations) : ""
645
889
  }
646
890
  })
647
- assignDeep(iGlobals, opts.globals)
648
- iSet([localStorage.lang, navigator.language, navigator.userLanguage].concat(navigator.languages, opts.lang).find(iResolve))
649
- $d.locales = Object.keys(iFormat)
650
- View.lang = iSet
651
- function iResolve(lang) {
652
- return lang && (iFormat[lang = ("" + lang).toLowerCase()] || iFormat[lang = lang.split("-")[0]]) && lang
891
+ ;[localStorage.lang, opts.lang, navigator.language].concat(navigator.languages, html.lang, $d.locales = Object.keys(iFormat))
892
+ .find(View.lang = function(lang, translations) {
893
+ if (lang && (iFormat[lang = ("" + lang).toLowerCase()] || iFormat[lang = lang.split("-")[0]])) {
894
+ assignDeep(iFormat[html.lang = $d.lang = localStorage.lang = lang].t, translations)
895
+ return ($d._ = iFormat[lang])
896
+ }
897
+ })
898
+ function format(str, data, getter) {
899
+ return replace(str, formatRe, function(all, path) {
900
+ return getter(data, path, "")
901
+ })
653
902
  }
654
- function iSet(lang, translations) {
655
- assignDeep(iData[lang = html.lang = $d.lang = localStorage.lang = iResolve(lang) || $d.lang || opts.lang], translations)
656
- return ($d._ = iFormat[lang] || format)
903
+ function iGet(obj, path, fallback) {
904
+ return isStr(path) ? (
905
+ isStr(obj[path]) ? obj[path] :
906
+ (path = path.split("."))[1] && isObj(obj = obj[path[0]]) && isStr(obj[path[1]]) ? obj[path[1]] :
907
+ fallback
908
+ ) :
909
+ isArr(path) ? iGet(obj, path[0]) || iGet(obj, path[1]) || iGet(obj, path[2], fallback) :
910
+ fallback
657
911
  }
912
+ /*/
913
+ globalScope._ = String
658
914
  /**/
659
915
 
660
916
  return View
@@ -663,7 +919,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
663
919
  function setUrl(url, rep, checkUrl) {
664
920
  /*** pushState ***/
665
921
  if (pushBase) {
666
- history[rep ? "replaceState" : "pushState"](null, null, pushBase + url)
922
+ history[rep ? "replaceState" : "pushState"](NUL, NUL, pushBase + url)
667
923
  } else {
668
924
  /**/
669
925
  location[rep ? "replace" : "assign"]("#" + url)
@@ -678,20 +934,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
678
934
  function histStart(cb) {
679
935
  /*** pushState ***/
680
936
  // Chrome5, Firefox4, IE10, Safari5, Opera11.50
681
- var histLast, url
682
- , base = find(html, "base")
683
- LiteJS.base = replace((base || location).href, /[^\/]*(#.*)?$/, "")
684
- if (base) base = replace(base.href, /.*:\/\/[^/]*|[^\/]*$/g, "")
685
- if (base && !history.pushState) {
686
- url = location.pathname.slice(base.length)
687
- if (url) {
688
- location.replace(base + "#" + url)
689
- }
690
- }
691
- if (base && history.pushState) {
692
- pushBase = base
937
+ var histLast
938
+ , baseEl = find(html, "base")
939
+ , url = getUrl()
940
+ if (baseEl && history.pushState) {
941
+ pushBase = replace(baseEl.href, /.*:\/\/[^/]*|[^\/]*$/g, "")
693
942
 
694
- url = location.href.split("#")[1]
695
943
  if (url && !getUrl()) {
696
944
  setUrl(url, 1)
697
945
  }
@@ -716,8 +964,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
716
964
  /*** pushState ***/
717
965
  pushBase ? location.pathname.slice(pushBase.length) :
718
966
  /**/
719
- // bug in Firefox where location.hash is decoded
720
- // bug in Safari where location.pathname is decoded
967
+ // NOTE: in Firefox location.hash is decoded; in Safari location.pathname is decoded
721
968
  location.href.split("#")[1] || "", /^[#\/\!]+|[\s\/]+$/g, "")
722
969
  }
723
970
  }
@@ -764,7 +1011,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
764
1011
  }
765
1012
 
766
1013
  assign(El, bindings, {
767
- emit: elEmit,
1014
+ emit: emit,
768
1015
  empty: elEmpty,
769
1016
  kill: elKill,
770
1017
  off: acceptMany(rmEvent),
@@ -796,57 +1043,65 @@ console.log("LiteJS is in debug mode, but it's fine for production")
796
1043
  })
797
1044
 
798
1045
  assign(El, {
799
- append: append,
800
1046
  $b: assign(bindings, {
801
1047
  each: function(el, name, list) {
1048
+ /*** debug ***/
1049
+ if (el._li) throw "Binding each must be type of once: each!" + name
1050
+ /**/
1051
+
802
1052
  var comm = Comm("each " + name, up)
803
1053
  , pos = 0
804
1054
  , nodes = []
1055
+
805
1056
  comm.$s = this
806
1057
  elReplace(el, comm)
807
- up()
808
- return { a: add, r: remove, u: up }
1058
+ each(list, add)
1059
+ return { a: add, u: up }
809
1060
 
810
1061
  function add(item) {
811
1062
  var clone = nodes[pos] = el.cloneNode(true)
812
1063
  , subScope = elScope(clone, comm)
1064
+ append(comm.parentNode, clone, (pos ? nodes[pos - 1] : comm).nextSibling)
813
1065
  subScope.$i = pos++
814
1066
  subScope.$len = list.length
815
1067
  subScope[name] = item
816
1068
  clone[BIND_ATTR] = el[BIND_ATTR]
817
- append(comm.parentNode, clone, comm)
1069
+ /*** debug ***/
1070
+ clone._li = up
1071
+ /**/
818
1072
  render(clone)
819
1073
  }
820
- function remove(i) {
821
- elKill(nodes.splice(i, 1)[0])
822
- }
823
1074
  function up() {
824
- for (; pos; ) remove(--pos)
825
- each(list, add)
1075
+ for (var i = list.length; pos > i; ) elKill(nodes[--pos])
1076
+ for (nodes.length = i; pos < i; ) add(list[pos])
1077
+ for (; i--; ) nodes[i].$s[name] = list[i]
826
1078
  }
827
1079
  },
828
1080
  el: function(el, tag, fallback) {
829
- var child = El(elCache[tag] ? tag : fallback)
830
- , tmp = getAttr(el, BIND_ATTR)
831
- , tmp2 = getAttr(child, BIND_ATTR)
832
- if (tmp) setAttr(child, BIND_ATTR, tmp2 ? tmp + ";" + tmp2 : tmp)
833
- if ((tmp = el.className)) cls(child, tmp)
834
- child.$s = el.$s
835
- elReplace(el, child)
836
- render(child)
837
- return child
1081
+ tag = elCache[tag] ? tag : fallback
1082
+ if (el._el !== tag) {
1083
+ var child = El(tag)
1084
+ , tmp = child._elb = el._el ? el._elb : el[BIND_ATTR]
1085
+ if (tmp) appendBind(child, tmp, ";", "^")
1086
+ child.$s = el.$s
1087
+ child._el = tag
1088
+ elReplace(el, child)
1089
+ if ((tmp = child._elc = el._el ? (elKill(el), el._elc) : el.className)) cls(child, tmp)
1090
+ render(child)
1091
+ return true
1092
+ }
838
1093
  },
839
1094
  "if": function(el, enabled) {
840
1095
  if (enabled) {
841
1096
  elReplace(el._if, el)
842
1097
  } else {
843
- elReplace(el, el._if || (el._if = Comm("if", render.bind(el, el))))
1098
+ elReplace(el, el._if || (el._if = Comm("if", bind(render, el, el, this))))
844
1099
  return true
845
1100
  }
846
1101
  },
847
1102
  is: function(el, val, opts, prefix) {
848
1103
  if (!prefix) prefix = "is-"
849
- var match = format(val, opts)
1104
+ var match = elScope(el)._.ext.pick(val, opts)
850
1105
  cls(el, el[prefix + opts], 0)
851
1106
  cls(el, el[prefix + opts] = match && prefix + match)
852
1107
  },
@@ -863,15 +1118,18 @@ console.log("LiteJS is in debug mode, but it's fine for production")
863
1118
  })
864
1119
  }
865
1120
  }),
1121
+ $d: globalScope,
1122
+ append: append,
1123
+ asEmitter: asEmitter,
866
1124
  blur: blur,
867
1125
  cache: elCache,
868
1126
  closest: closest,
869
- $d: globalScope,
870
1127
  get: getAttr,
871
1128
  hasClass: hasClass,
872
1129
  matches: matches,
873
- next: walk.bind(El, "nextSibling"),
874
- prev: walk.bind(El, "previousSibling"),
1130
+ nearest: nearest,
1131
+ next: bind(walk, El, "nextSibling"),
1132
+ prev: bind(walk, El, "previousSibling"),
875
1133
  rate: rate,
876
1134
  replace: elReplace,
877
1135
  scope: elScope,
@@ -885,7 +1143,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
885
1143
  var current = getAttr(el, key)
886
1144
 
887
1145
  /*** ie8 ***/
888
- // Bug: IE5-7 doesn't set styles and removes events when you try to set them.
1146
+ // NOTE: IE5-7 doesn't set styles and removes events when you try to set them.
889
1147
  // IE6 label with a for attribute will re-select the first option of SELECT list instead of just giving focus.
890
1148
  // http://webbugtrack.blogspot.com/2007/09/bug-116-for-attribute-woes-in-ie6.html
891
1149
  // IE8 and below have a bug where changed 'name' not accepted on form submit
@@ -941,7 +1199,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
941
1199
  isNum(before) ? el.childNodes[before < 0 ? el.childNodes.length - before - 2 : before] :
942
1200
  isArr(before) ? before[0] :
943
1201
  before
944
- ) || null)
1202
+ ) || NUL)
945
1203
  /*** debug ***/
946
1204
  if (el.namespaceURI && child.namespaceURI && el.namespaceURI !== child.namespaceURI && el.tagName !== "foreignObject" && child.tagName !== "svg") {
947
1205
  console.error("NAMESPACE CHANGE!", el, child)
@@ -951,6 +1209,15 @@ console.log("LiteJS is in debug mode, but it's fine for production")
951
1209
  }
952
1210
  }
953
1211
 
1212
+ function appendBind(el, val, sep, q) {
1213
+ var current = getAttr(el, BIND_ATTR)
1214
+ setAttr(el, BIND_ATTR, (current ? (
1215
+ q === "^" ?
1216
+ val + sep + current :
1217
+ current + sep + val
1218
+ ) : val))
1219
+ }
1220
+
954
1221
  function hasClass(el, name) {
955
1222
  var current = el.className || ""
956
1223
 
@@ -990,9 +1257,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
990
1257
  }
991
1258
  }
992
1259
 
993
- function elEmit(el) {
994
- emit.apply(el, slice.call(arguments, 1))
995
- }
996
1260
  function elEmpty(el) {
997
1261
  for (; el.lastChild; elKill(el.lastChild));
998
1262
  }
@@ -1004,15 +1268,15 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1004
1268
  if (isObj(tr)) bindingsCss(el, tr)
1005
1269
  tr = "transitionend"
1006
1270
  // transitionend fires for each property transitioned
1007
- if ("on" + tr in el) return addEvent(el, tr, elKill.bind(el, el, el = UNDEF))
1271
+ if ("on" + tr in el) return addEvent(el, tr, bind(elKill, el, el, el = UNDEF))
1008
1272
  }
1009
1273
  if (el._e) {
1010
- emit.call(el, "kill")
1274
+ emit(el, "kill")
1011
1275
  el._e = UNDEF
1012
1276
  }
1013
1277
  elRm(el)
1014
- el.$s = UNDEF
1015
1278
  if (el.nodeType < 2) {
1279
+ el.$s = UNDEF
1016
1280
  elEmpty(el)
1017
1281
  if (el.valObject !== UNDEF) {
1018
1282
  el.valObject = UNDEF
@@ -1089,12 +1353,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1089
1353
  }
1090
1354
 
1091
1355
  return checkbox && !el.checked ?
1092
- (type === "radio" ? UNDEF : null) :
1356
+ (type === "radio" ? UNDEF : NUL) :
1093
1357
  el.valObject !== UNDEF ? el.valObject : el.value
1094
1358
 
1095
1359
  function replacer(_, _key, offset) {
1096
1360
  if (step == opts) key = key.slice(0, offset)
1097
- step = step[key] || (step[key] = step[key] === null || _key && +_key != _key ? {} : [])
1361
+ step = step[key] || (step[key] = step[key] === NUL || _key && +_key != _key ? {} : [])
1098
1362
  key = _key
1099
1363
  }
1100
1364
  }
@@ -1112,7 +1376,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1112
1376
  return
1113
1377
  }
1114
1378
 
1115
- var bind, next
1379
+ var el, next
1116
1380
  , scope = node.$s || $s || closestScope(node)
1117
1381
 
1118
1382
  /*** ie8 ***/
@@ -1122,27 +1386,27 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1122
1386
  /**/
1123
1387
 
1124
1388
  if (hydrate(node, BIND_ATTR, scope)) return
1125
- for (bind = node.firstChild; bind; bind = next) {
1126
- next = bind.nextSibling
1127
- render(bind, scope)
1389
+ for (el = node.firstChild; el; el = next) {
1390
+ next = el.nextSibling
1391
+ render(el, scope)
1128
1392
  }
1129
1393
  hydrate(node, "data-out", scope)
1130
1394
  }
1131
1395
 
1132
1396
  function hydrate(node, attr, scope) {
1133
1397
  var fn
1134
- , bind = node[attr] || (node[attr] = setAttr(node, attr, "") || true)
1135
- if (bind !== true) try {
1136
- fn = fnCache[bind] || (fnCache[bind] = makeFn(bind))
1398
+ , expr = node[attr] || (node[attr] = setAttr(node, attr, "") || true)
1399
+ if (expr !== true) try {
1400
+ fn = fnCache[expr] || (fnCache[expr] = makeFn(expr))
1137
1401
  return fn(node, scope, attr, fn.o)
1138
1402
  } catch (e) {
1139
- logErr(e, attr + ": " + bind, node)
1403
+ throw e + "\n" + attr + ": " + expr
1140
1404
  }
1141
1405
  }
1142
- function makeFn(fn) {
1406
+ function makeFn(fn, raw) {
1143
1407
  var i = 0
1144
1408
  , bindOnce = []
1145
- fn = "$s&&(" + replace(fn, renderRe, function(match, name, op, args) {
1409
+ fn = raw || "$s&&(" + replace(fn, renderRe, function(match, name, op, args) {
1146
1410
  return (
1147
1411
  (op === "!" && (bindOnce[i] = match)) ?
1148
1412
  "($el[$a]=$el[$a].replace($o[" + (i++)+ "],''),0)||" :
@@ -1154,7 +1418,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1154
1418
  if (vars.indexOf(vars[i]) !== i) vars.splice(i, 1)
1155
1419
  else vars[i] += "=$s." + vars[i]
1156
1420
  }
1157
- fn = Function("$el,$s,$a,$o,$r", "var " + vars + ";return " + fn)
1421
+ fn = Function("$el,$s,$a,$o,$r", (vars[0] ? "var " + vars : "") + ";return " + fn)
1158
1422
  fn.o = bindOnce
1159
1423
  return fn
1160
1424
  }
@@ -1170,7 +1434,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1170
1434
  if (map) {
1171
1435
  kbMaps.unshift(map)
1172
1436
  if (killEl) {
1173
- addEvent(killEl, "kill", rmKb.bind(map, map))
1437
+ addEvent(killEl, "kill", bind(rmKb, map, map))
1174
1438
  }
1175
1439
  }
1176
1440
  }
@@ -1178,19 +1442,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1178
1442
  map = kbMaps.indexOf(map)
1179
1443
  if (map > -1) kbMaps.splice(map, 1)
1180
1444
  }
1181
- function runKb(e, code, chr) {
1182
- var fn, map
1183
- , i = 0
1184
- , el = e.target
1185
- , input = /INPUT|TEXTAREA|SELECT/i.test((el.nodeType < 2 ? el : el.parentNode).tagName)
1186
-
1187
- for (; (map = kbMaps[i++]) && (
1188
- !(fn = !input || map.input ? map[code] || map[chr] || map.num && code > 47 && code < 58 && (chr|=0, map.num) || map.all : fn) &&
1189
- map.bubble
1190
- ););
1191
- if (isStr(fn)) setUrl(fn)
1192
- if (isFn(fn)) fn(e, chr, el)
1193
- }
1194
1445
 
1195
1446
  addEvent(document, "keydown", function(e) {
1196
1447
  if (kbMaps[0]) {
@@ -1203,18 +1454,30 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1203
1454
  if (code == 8 && kbMaps[0].backspace) {
1204
1455
  eventStop(e)
1205
1456
  }
1206
- runKb(e, code, key)
1207
- if (e.shiftKey && code != 16) runKb(e, code, "shift+" + key)
1457
+ runKb(key)
1458
+ if (e.shiftKey && code != 16) runKb("shift+" + key)
1208
1459
  // people in Poland use Right-Alt+S to type in Ś.
1209
1460
  // Right-Alt+S is mapped internally to Ctrl+Alt+S.
1210
1461
  // THANKS: Marcin Wichary - disappearing Polish Ś [https://medium.engineering/fa398313d4df]
1211
1462
  if (e.altKey) {
1212
- if (code != 18) runKb(e, code, "alt+" + key)
1463
+ if (code != 18) runKb("alt+" + key)
1213
1464
  } else if (code != 17) {
1214
- if (e.ctrlKey) runKb(e, code, "ctrl+" + key)
1215
- if (e[kbMod] && code != 91) runKb(e, code, "mod+" + key)
1465
+ if (e.ctrlKey) runKb("ctrl+" + key)
1466
+ if (e[kbMod] && code != 91) runKb("mod+" + key)
1216
1467
  }
1217
1468
  }
1469
+ function runKb(chr) {
1470
+ for (
1471
+ var fn, map
1472
+ , i = 0
1473
+ , el = e.target
1474
+ , input = /INPUT|TEXTAREA|SELECT/i.test((el.nodeType < 2 ? el : el.parentNode).tagName);
1475
+ (map = kbMaps[i++]) && !(
1476
+ fn = !input || map.input ? map[code] || map[chr] || map.num && code > 47 && code < 58 && (chr|=0, map.num) || map.all : fn
1477
+ ) && map.bubble; );
1478
+ if (isStr(fn)) setUrl(fn)
1479
+ if (isFn(fn)) fn(e, chr, el)
1480
+ }
1218
1481
  })
1219
1482
  /**/
1220
1483
 
@@ -1243,7 +1506,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1243
1506
  var len = e ? touches.push(e) : touches.length
1244
1507
  , MOVE = "pointermove"
1245
1508
  if (touchMode || len < 1) {
1246
- elEmit(touchEl, touchMode ? touchMode + END : "tap", e2, touchEv, touchEl)
1509
+ emit(touchEl, touchMode ? touchMode + END : "tap", e2, touchEv, touchEl)
1247
1510
  touchMode = UNDEF
1248
1511
  }
1249
1512
  if (len < 0) {
@@ -1270,7 +1533,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1270
1533
  function touchPos(name, offset) {
1271
1534
  var val = (
1272
1535
  touchEl.getBBox ?
1273
- touchEl.getAttributeNS(null, name == "top" ? "y":"x") :
1536
+ touchEl.getAttributeNS(NUL, name == "top" ? "y":"x") :
1274
1537
  touchEl.style[name]
1275
1538
  )
1276
1539
  touchEv[name] = parseInt(val, 10) || 0
@@ -1293,7 +1556,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1293
1556
  // Chrome M35 and Firefox 55 followed up.
1294
1557
  if (!touches[0]) {
1295
1558
  var ev = e.ctrlKey ? "pinch" : e.altKey ? "rotate" : UNDEF
1296
- if (ev && emit.call(e.currentTarget || e.target, ev, e, e.deltaY/20, 0)) {
1559
+ if (ev && emit(e.currentTarget || e.target, ev, e, e.deltaY/20, 0)) {
1297
1560
  return eventStop(e)
1298
1561
  }
1299
1562
  }
@@ -1315,9 +1578,9 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1315
1578
  )
1316
1579
  if (!touchMode) return
1317
1580
  clearTimeout(touchTick)
1318
- elEmit(touchEl, touchMode + START, e, touchEv, touchEl)
1581
+ emit(touchEl, touchMode + START, e, touchEv, touchEl)
1319
1582
  }
1320
- elEmit(touchEl, touchMode, e, touchEv, touchEl)
1583
+ emit(touchEl, touchMode, e, touchEv, touchEl)
1321
1584
  function haveEv(name, set) {
1322
1585
  return set && (evs[name] || evs[name + START] || evs[name + END]) && name
1323
1586
  }
@@ -1332,12 +1595,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1332
1595
 
1333
1596
  if (touchDist !== UNDEF) {
1334
1597
  diff = dist - touchDist
1335
- if (diff) elEmit(touchEl, "pinch", e, diff, angle)
1598
+ if (diff) emit(touchEl, "pinch", e, diff, angle)
1336
1599
  // GestureEvent onGestureChange: function(e) {
1337
1600
  // e.target.style.transform =
1338
1601
  // 'scale(' + e.scale + startScale + ') rotate(' + e.rotation + startRotation + 'deg)'
1339
1602
  diff = angle - touchAngle
1340
- if (diff) elEmit(touchEl, "rotate", e, diff * (180/Math.PI))
1603
+ if (diff) emit(touchEl, "rotate", e, diff * (180/Math.PI))
1341
1604
  }
1342
1605
  touchDist = dist
1343
1606
  touchAngle = angle
@@ -1345,6 +1608,9 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1345
1608
  }
1346
1609
  /**/
1347
1610
 
1611
+ function closest(el, sel) {
1612
+ return el && html.closest.call(el.nodeType < 2 ? el : el.parentNode, sel)
1613
+ }
1348
1614
  function find(root, sel, startNode) {
1349
1615
  return html.querySelector.call(startNode || root, sel)
1350
1616
  }
@@ -1354,8 +1620,8 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1354
1620
  function matches(el, sel) {
1355
1621
  return el && html.matches.call(el, sel)
1356
1622
  }
1357
- function closest(el, sel) {
1358
- return el && html.closest.call(el.nodeType < 2 ? el : el.parentNode, sel)
1623
+ function nearest(el, sel) {
1624
+ return el ? find(el, sel) || nearest(el.parentNode, sel) : NUL
1359
1625
  }
1360
1626
  function walk(attr, el, sel) {
1361
1627
  for (; el && !matches(el = el[attr], sel); );
@@ -1365,17 +1631,22 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1365
1631
  return function f(el, name, val, selector, delay, data) {
1366
1632
  if (el && name) {
1367
1633
  var i = arguments.length
1368
- if (i > 3 && i < 6 && isNum(selector)) {
1369
- data = delay
1370
- delay = selector
1371
- selector = UNDEF
1634
+ if (i > 3 && i < 6) {
1635
+ if (isArr(selector)) {
1636
+ data = selector
1637
+ delay = selector = UNDEF
1638
+ } else if (isNum(selector)) {
1639
+ data = delay
1640
+ delay = selector
1641
+ selector = UNDEF
1642
+ }
1372
1643
  }
1373
1644
  if (delay > 0) {
1374
1645
  setTimeout(f, delay, el, name, val, selector, 0, data)
1375
1646
  return
1376
1647
  }
1377
1648
  if (isObj(name)) {
1378
- for (delay in name) if (hasOwn.call(name, delay)) {
1649
+ for (delay in name) if (hasOwn(name, delay)) {
1379
1650
  f(el, delay, name[delay], selector, 0, data)
1380
1651
  }
1381
1652
  return
@@ -1392,8 +1663,9 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1392
1663
  }
1393
1664
  }
1394
1665
  function assignDeep(target, map) {
1395
- if (map) for (var k in map) if (hasOwn.call(map, k)) {
1396
- target[k] = isObj(map[k]) && isObj(target[k]) ? assignDeep(target[k], map[k]) : map[k]
1666
+ if (map) for (var k in map) if (hasOwn(map, k)) {
1667
+ if (isObj(map[k]) && isObj(target[k]) && hasOwn(target, k)) assignDeep(target[k], map[k])
1668
+ else target[k] = map[k]
1397
1669
  }
1398
1670
  return target
1399
1671
  }
@@ -1412,7 +1684,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1412
1684
  if (arr) {
1413
1685
  if (isStr(arr)) arr = arr.split(splitRe)
1414
1686
  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)
1687
+ else for (key in arr) if (hasOwn(arr, key)) fn.call(scope, arr[key], key, arr)
1416
1688
  }
1417
1689
  }
1418
1690
  function expand(str) {
@@ -1424,28 +1696,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1424
1696
  (lastExp = str)
1425
1697
  )
1426
1698
  }
1427
- function format(str, data) {
1428
- return replace(str, formatRe, function(all, path) {
1429
- return get(data, path, "")
1430
- })
1431
- }
1432
- function get(obj, path, fallback) {
1433
- return isStr(path) ? (
1434
- obj[path] !== UNDEF ? obj[path] :
1435
- (path = path.split("."))[1] && isObj(obj = obj[path[0]]) && obj[path[1]] !== UNDEF ? obj[path[1]] : fallback
1436
- ) :
1437
- isArr(path) ? get(obj, path[0]) || get(obj, path[1]) || get(obj, path[2], fallback) :
1438
- fallback
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
- }
1449
1699
  function injectCss(cssText) {
1450
1700
  if (!styleNode) {
1451
1701
  // Safari and IE6-8 requires dynamically created
@@ -1468,6 +1718,9 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1468
1718
  function isStr(str) {
1469
1719
  return typeof str === "string"
1470
1720
  }
1721
+ function quote(str) {
1722
+ return "'" + replace(replace(str || "", /'/g, "\\'"), /\n/g, "\\n") + "'"
1723
+ }
1471
1724
  // Maximum call rate for Function with optional leading edge and trailing edge
1472
1725
  function rate(fn, ms, onStart, onEnd) {
1473
1726
  var tick
@@ -1508,7 +1761,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1508
1761
  elKill(el)
1509
1762
  return el.src
1510
1763
  }), function(res) {
1511
- res = res.concat(sources, (next || res).innerHTML).filter(Boolean)
1764
+ res = res.concat(sources, next && next.src && next.innerHTML).filter(Boolean)
1512
1765
  if (res[sources.length = 0]) {
1513
1766
  if (!parser) LiteJS.ui = LiteJS()
1514
1767
  each(res, parser)