@litejs/ui 25.1.0 → 25.10.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
@@ -13,6 +13,8 @@ console.log("LiteJS is in debug mode, but it's fine for production")
13
13
 
14
14
  var UNDEF, parser, pushBase, styleNode
15
15
  , NUL = null
16
+ // THIS will be undefined in strict mode and window in sloppy mode
17
+ , THIS = this
16
18
  , html = document.documentElement
17
19
  , body = document.body
18
20
  , splitRe = /[,\s]+/
@@ -28,44 +30,121 @@ console.log("LiteJS is in debug mode, but it's fine for production")
28
30
  , elReplace = Function("a,b,c", "a&&b&&(c=a.parentNode)&&c.replaceChild(b,a)")
29
31
  , elRm = Function("a,b", "a&&(b=a.parentNode)&&b.removeChild(a)")
30
32
  , getAttr = Function("a,b", "return a&&a.getAttribute&&a.getAttribute(b)")
31
- , replace = Function("a,b,c", "return a.replace(b,c)")
33
+ , replace = Function("a,b,c", "return c.replace(a,b)")
34
+ , toCamel = replace.bind(NUL, /\-([a-z])/g, Function("a,b", "return b.toUpperCase()"))
32
35
 
36
+ /*** ie9 ***/
33
37
  // JScript engine in IE8 and below does not recognize vertical tabulation character `\v`.
34
38
  // http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
35
39
  , ie678 = !+"\v1" // jshint ignore:line
40
+ // innerText is implemented in IE4, textContent in IE9, Node.text in Opera 9-10
41
+ // Safari 2.x innerText results an empty string when style.display=="none" or Node is not in DOM
42
+ , txtAttr = "textContent" in html ? "textContent" : "innerText"
43
+ , elTxt = function(el, txt) {
44
+ if (el[txtAttr] !== txt) el[txtAttr] = txt
45
+ }
46
+ /*/
47
+ , elTxt = function(el, txt) {
48
+ if (el.textContent !== txt) el.textContent = txt
49
+ }
50
+ /**/
36
51
 
37
- , BIND_ATTR = "data-bind"
38
52
  , elSeq = 0
39
53
  , elCache = {}
40
54
  , renderRe = /[;\s]*([-.\w$]+)(?:(!?)[ :]*((?:(["'\/])(?:\\.|[^\\])*?\4|[^;])*))?/g
41
55
  , selectorRe = /([.#:[])([-\w]+)(?:([~^$*|]?)=(("|')(?:\\.|[^\\])*?\5|[-\w]+))?]?/g
42
56
  , fnCache = {}
43
- , 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
57
+ , fnRe = /('|")(?:\\.|[^\\])*?\1|\/(?:\\.|[^\\])+?\/[gim]*|\$el\b|\$[aorsS]\b|\b(?:false|in|if|new|null|this|true|typeof|void|function|var|else|return)\b|\.\w+|\w+:/g
44
58
  , wordRe = /[a-z_$][\w$]*/ig
45
- , camelRe = /\-([a-z])/g
46
- // innerText is implemented in IE4, textContent in IE9, Node.text in Opera 9-10
47
- // Safari 2.x innerText results an empty string when style.display=="none" or Node is not in DOM
48
- , txtAttr = "textContent" in html ? "textContent" /* c8 ignore next */ : "innerText"
49
- , bindingsCss = acceptMany(function(el, key, val) {
50
- el.style[replace(key, camelRe, camelFn)] = val
51
- })
52
- , bindingsOn = acceptMany(addEvent, function(el, val, selector, data) {
53
- return isStr(val) ? function(e) {
54
- var target = selector ? closest(e.target, selector) : el
55
- if (target) emit.apply(target, [elScope(el).$ui, val, e, target].concat(data))
56
- } :
57
- selector ? function(e, a1, a2) {
58
- if (matches(e.target, selector)) val(e, a1, a2)
59
- } :
60
- val
59
+ , bindingsCss = acceptMany(function(el, key, val, current) {
60
+ current = el.style[key = toCamel(key)]
61
+ el.style[key] = val
62
+ return current
61
63
  })
64
+ , bindingsOn = acceptMany(addEvent, 1)
62
65
  , bindings = {
63
66
  cls: acceptMany(cls),
64
67
  css: bindingsCss,
65
68
  on: bindingsOn,
69
+ one: acceptMany(function(el, ev, fn) {
70
+ addEvent(el, ev, function remove() {
71
+ rmEvent(el, ev, remove)
72
+ fn.apply(el, arguments)
73
+ })
74
+ }, 1),
66
75
  set: acceptMany(setAttr),
67
76
  txt: elTxt,
68
- val: elVal,
77
+ /*** form ***/
78
+ val: function elVal(el, val, input) {
79
+ try {
80
+ if (!el || !input && document.activeElement === el) return
81
+ } catch (e) {}
82
+ var step, key, value
83
+ , i = 0
84
+ , type = el.type
85
+ , opts = el.options
86
+ , checkbox = type === "checkbox" || type === "radio"
87
+
88
+ if (el.tagName === "FORM") {
89
+ // Disabled controls do not receive focus,
90
+ // are skipped in tabbing navigation, cannot be successfully posted.
91
+ //
92
+ // Read-only elements receive focus but cannot be modified by the user,
93
+ // are included in tabbing navigation, are successfully posted.
94
+ //
95
+ // Read-only checkboxes can be changed by the user
96
+
97
+ for (opts = {}; (input = el.elements[i++]); ) if (!input.disabled && (key = input.name || input.id)) {
98
+ value = elVal(input, val != UNDEF ? val[key] : UNDEF)
99
+ if (value !== UNDEF) {
100
+ step = opts
101
+ replace(/\[(.*?)\]/g, replacer, key)
102
+ step[key || step.length] = value
103
+ }
104
+ }
105
+ return opts
106
+ }
107
+
108
+ if (val !== UNDEF) {
109
+ if (opts) {
110
+ for (value = (isArr(val) ? val : [ val ]).map(String); (input = opts[i++]); ) {
111
+ input.selected = value.indexOf(input.value) > -1
112
+ }
113
+ } else if (el.val) {
114
+ el.val(val)
115
+ } else if (checkbox) {
116
+ el.checked = !!val
117
+ } else {
118
+ el.value = val
119
+ }
120
+ return
121
+ }
122
+
123
+ if (opts) {
124
+ if (type === "select-multiple") {
125
+ for (val = []; (input = opts[i++]); ) {
126
+ if (input.selected && !input.disabled) {
127
+ val.push(input.valObject || input.value)
128
+ }
129
+ }
130
+ return val
131
+ }
132
+ // IE8 throws error when accessing to options[-1]
133
+ value = el.selectedIndex
134
+ el = value > -1 && opts[value] || el
135
+ }
136
+
137
+ return checkbox && !el.checked ?
138
+ (type === "radio" ? UNDEF : NUL) :
139
+ el.valObject !== UNDEF ? el.valObject : el.value
140
+
141
+ function replacer(_, _key, offset) {
142
+ if (step == opts) key = key.slice(0, offset)
143
+ step = step[key] || (step[key] = step[key] === NUL || _key && +_key != _key ? {} : [])
144
+ key = _key
145
+ }
146
+ }
147
+ /**/
69
148
  }
70
149
  , bindOnce = []
71
150
  , globalScope = {
@@ -118,27 +197,27 @@ console.log("LiteJS is in debug mode, but it's fine for production")
118
197
  (tag == "a" ? " href=\"" + (link || text) + "\"" : op == "@" ? " datetime=\"" + name + "\"" : "") +
119
198
  (attr ? " class=\"" + attr.slice(1) + "\">" : ">") +
120
199
  (
121
- op === ">" ? doc(replace(text, /^> ?/gm, "")) :
200
+ op === ">" ? doc(replace(/^> ?/gm, "", text)) :
122
201
  tag == "ul" ? "<li>" + text.split(/\n - (?=\S)/).map(inline).join("</li>\n<li>") + "</li>" :
123
- inline(tag == "a" ? replace(name, /^\w+:\/{0,2}/, "") : text)
202
+ inline(tag == "a" ? replace(/^\w+:\/{0,2}/, "", name) : text)
124
203
  ) +
125
204
  "</" + tag + ">" :
126
- replace(tag, /\[([-!*+,/:;@^_`~])((.+?)(?: (\S+?))?)\1(\.[.\w]+)?]/g, inline)
205
+ replace(/\[([-!*+,/:;@^_`~])((.+?)(?: (\S+?))?)\1(\.[.\w]+)?]/g, inline, tag)
127
206
  }
128
207
  function block(tag, op, text, media, alt) {
129
208
  return op && !isArr(text) ? inline(tag, op, text) :
130
209
  media ? "<img src=\"" + media + "\" alt=\"" + alt + "\">" :
131
- blockRe.test(tag) ? replace(tag, blockRe, block) :
210
+ blockRe.test(tag) ? replace(blockRe, block, tag) :
132
211
  tag === "---" ? "<hr>" : "<p>" + inline(tag) + "</p>"
133
212
  }
134
213
  function doc(txt) {
135
- return replace(txt.trim(), /^ \b/gm, "<br>").split(/\n\n+/).map(block).join("\n")
214
+ return replace(/^ \b/gm, "<br>", txt.trim()).split(/\n\n+/).map(block).join("\n")
136
215
  }
137
216
  bindings.t = function(el, text) {
138
- el.innerHTML = inline(replace(text, /</g, "&lt;"))
217
+ el.innerHTML = inline(replace(/</g, "&lt;", text))
139
218
  }
140
219
  bindings.d = function(el, text) {
141
- el.innerHTML = doc(replace(text, /</g, "&lt;"))
220
+ el.innerHTML = doc(replace(/</g, "&lt;", text))
142
221
  }
143
222
  /**/
144
223
 
@@ -161,7 +240,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
161
240
  }
162
241
 
163
242
  function asEmitter(obj) {
164
- obj.on = on
243
+ obj.on = wrap(on)
165
244
  obj.off = off
166
245
  obj.one = one
167
246
  obj.emit = wrap(emit)
@@ -171,27 +250,33 @@ console.log("LiteJS is in debug mode, but it's fine for production")
171
250
  return fn(this, a, b, c, d, e)
172
251
  }
173
252
  }
253
+ function one(type, fn, scope) {
254
+ var emitter = this
255
+ on(emitter, type, function remove() {
256
+ off.call(emitter, type, remove, scope)
257
+ fn.apply(scope, arguments)
258
+ }, scope)
259
+ return emitter
260
+ }
174
261
  }
175
262
 
176
- function on(type, fn, scope, _origin) {
177
- var emitter = this === window ? emptyArr : this
178
- , events = emitter._e || (emitter._e = create(NUL))
179
- if (type && fn) {
180
- emit(emitter, "newListener", type, fn, scope, _origin)
263
+ function on(emitter, type, fn, scope, _origin) {
264
+ if (emitter && type && fn) {
265
+ if (emitter === window) emitter = emptyArr
266
+ var events = emitter._e || (emitter._e = create(NUL))
181
267
  ;(events[type] || (events[type] = [])).unshift(scope, _origin, fn)
182
268
  }
183
- return this
269
+ return emitter
184
270
  }
185
271
 
186
272
  function off(type, fn, scope) {
187
- var i, args
273
+ var i
188
274
  , emitter = this === window ? emptyArr : this
189
275
  , events = emitter._e && emitter._e[type]
190
276
  if (events) {
191
277
  for (i = events.length - 2; i > 0; i -= 3) {
192
278
  if ((events[i + 1] === fn || events[i] === fn) && events[i - 1] == scope) {
193
- args = events.splice(i - 1, 3)
194
- emit(emitter, "removeListener", type, args[2], args[0], args[1])
279
+ events.splice(i - 1, 3)
195
280
  if (fn) break
196
281
  }
197
282
  }
@@ -199,18 +284,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
199
284
  return this
200
285
  }
201
286
 
202
- function one(type, fn, scope) {
203
- var emitter = this === window ? emptyArr : this
204
-
205
- function remove() {
206
- off.call(emitter, type, fn, scope)
207
- off.call(emitter, type, remove, scope)
208
- }
209
- on.call(emitter, type, remove, scope)
210
- on.call(emitter, type, fn, scope)
211
- return this
212
- }
213
-
214
287
  function emit(emitter, type) {
215
288
  if (emitter === window) emitter = emptyArr
216
289
  var args, i
@@ -230,15 +303,15 @@ console.log("LiteJS is in debug mode, but it's fine for production")
230
303
 
231
304
  if (ev2 !== "" && "on" + ev2 in el) {
232
305
  // polyfilled addEventListener returns patched function
233
- // Since Chrome 56 touchstart/move have the { passive: true } by default.
234
- // preventDefault() won't work unless you set passive to false.
235
- fn2 = html.addEventListener.call(el, ev2, fn2, opts != UNDEF ? opts : false) || fn2
306
+ // useCapture defaults to false
307
+ // Chrome56 touchstart/move sets {passive:true} by default; use {passive:false} to enable preventDefault()
308
+ fn2 = html.addEventListener.call(el, ev2, fn2, opts) || fn2
236
309
  }
237
310
 
238
- on.call(el, ev, fn2, el, fn)
311
+ on(el, ev, fn2, el, fn)
239
312
  }
240
313
 
241
- function rmEvent(el, ev, fn) {
314
+ function rmEvent(el, ev, fn, opts) {
242
315
  var evs = el._e && el._e[ev]
243
316
  , id = evs && evs.indexOf(fn)
244
317
  , ev2 = fixEv[ev] || ev
@@ -247,7 +320,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
247
320
  evs[id + 1]._rm()
248
321
  }
249
322
  if (ev2 !== "" && "on" + ev2 in el) {
250
- html.removeEventListener.call(el, ev2, evs[id + 1])
323
+ html.removeEventListener.call(el, ev2, evs[id + 1], opts)
251
324
  }
252
325
  evs.splice(id - 1, 3)
253
326
  }
@@ -264,11 +337,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
264
337
  function LiteJS(opts) {
265
338
  opts = assign({
266
339
  /*** breakpoints ***/
267
- breakpoints: {
268
- sm: 0,
269
- md: 601,
270
- lg: 1025
271
- },
340
+ breakpoints: "sm,601=md,1025=lg",
272
341
  /**/
273
342
  home: "home",
274
343
  root: body
@@ -284,18 +353,18 @@ console.log("LiteJS is in debug mode, but it's fine for production")
284
353
  return view
285
354
  }
286
355
  view = this
287
- if (!(view instanceof View)) return new View(route, el, parent)
356
+ if (view === THIS) return new View(route, el, parent)
288
357
  views[view.r = route] = view
289
358
  view.e = isStr(el) ? find(html, el) : el
290
359
  view.p = parent && View(parent)
291
360
 
292
361
  if (route.charAt(0) !== "#") {
293
362
  fnStr += "m[" + (view.s = routeSeq++) + "]?("
294
- reStr += "|(" + replace(route, routeRe, function(_, expr) {
363
+ reStr += "|(" + replace(routeRe, function(_, expr) {
295
364
  return expr ?
296
365
  (fnStr += "p['" + expr + "']=m[" + (routeSeq++) + "],") && "([^/]+?)" :
297
- replace(_, reEsc, "\\$&")
298
- }) + ")"
366
+ replace(reEsc, "\\$&", _)
367
+ }, route) + ")"
299
368
  fnStr += "'" + route + "'):"
300
369
  viewFn = 0
301
370
  }
@@ -308,11 +377,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
308
377
  params._p = 1 + (params._p | 0) // pending
309
378
  return function() {
310
379
  if (--params._p || lastParams !== params || syncResume) return
311
- if (params._d) {
312
- bubbleDown(params)
313
- } else if (params._v) {
314
- viewPing(lastView, params)
315
- }
380
+ bubbleUp(params)
316
381
  }
317
382
  }
318
383
  })
@@ -343,7 +408,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
343
408
  },
344
409
  parse: (parser = viewParse),
345
410
  ping: function(view, fn) {
346
- View(view).on("ping", fn)
411
+ on(View(view), "ping", fn)
347
412
  },
348
413
  show: viewShow
349
414
  })
@@ -358,6 +423,42 @@ console.log("LiteJS is in debug mode, but it's fine for production")
358
423
  }
359
424
  })
360
425
 
426
+ function bubbleUp(params) {
427
+ var parent
428
+ , view = lastView
429
+ , tmp = params._v || view // Continue bubbleUp from _v
430
+ params._c = view.o ? view : params._c
431
+ for (View.route = view.r; tmp; tmp = parent) {
432
+ viewEmit(syncResume = params._v = tmp, "ping", params, View)
433
+ syncResume = UNDEF
434
+ if (lastParams !== params) return
435
+ if ((parent = tmp.p)) {
436
+ if (parent.c && parent.c !== tmp) {
437
+ params._c = parent.c
438
+ }
439
+ parent.c = tmp
440
+ }
441
+ if (tmp.f) {
442
+ return xhr.load(
443
+ replace(/^|,/g, "$&" + (View.path || ""), tmp.f).split(","),
444
+ bind(readTemplates, view, view.wait(tmp.f = ""))
445
+ )
446
+ } else if (!tmp.e) {
447
+ if (tmp.r === "404") {
448
+ viewParse("%view 404 #\nh2 Not found")
449
+ }
450
+ return viewShow("404")
451
+ }
452
+ }
453
+
454
+ for (tmp in params) {
455
+ if (tmp.charAt(0) !== "_" && (syncResume = hasOwn(paramCb, tmp) && paramCb[tmp] || paramCb["*"])) {
456
+ syncResume(params[tmp], tmp, view, params)
457
+ syncResume = UNDEF
458
+ }
459
+ }
460
+ bubbleDown(params)
461
+ }
361
462
  function bubbleDown(params) {
362
463
  var view = params._v
363
464
  , close = params._c
@@ -376,27 +477,30 @@ console.log("LiteJS is in debug mode, but it's fine for production")
376
477
  /**/
377
478
  params._c = UNDEF
378
479
  }
379
- if ((params._d = params._v = view.c)) {
480
+ if ((params._v = view.c)) {
380
481
  bubbleDown(params)
381
482
  }
382
483
  if ((lastView === view)) {
383
- viewEmit(view, "show", params)
484
+ for (; view; view = view.p) {
485
+ viewEmit(view, "pong", params, View)
486
+ }
487
+ viewEmit(lastView, "show", params)
384
488
  blur()
385
489
  }
386
- }
387
-
388
- function viewClose(view, open) {
389
- if (view && view.o) {
390
- viewEmit(view.p, "closeChild", view, open)
391
- viewClose(view.c)
392
- elKill(view.o)
393
- view.o = UNDEF
394
- /*** kb ***/
395
- rmKb(view.kb)
396
- /**/
397
- viewEmit(view, "close")
490
+ function viewClose(view, open) {
491
+ if (view && view.o) {
492
+ viewEmit(view.p, "closeChild", view, open)
493
+ viewClose(view.c)
494
+ elKill(view.o)
495
+ view.o = UNDEF
496
+ /*** kb ***/
497
+ rmKb(view.kb)
498
+ /**/
499
+ viewEmit(view, "close")
500
+ }
398
501
  }
399
502
  }
503
+
400
504
  function viewDef(str) {
401
505
  for (var match, re = /(\S+) (\S+)/g; (match = re.exec(str)); ) {
402
506
  each(match[1], def)
@@ -430,24 +534,37 @@ console.log("LiteJS is in debug mode, but it's fine for production")
430
534
  return View(url ? viewFn(url, params || {}, "404") : View.home)
431
535
  }
432
536
  function viewParse(str) {
537
+ if (!str) return
433
538
  var parent = El("div")
434
539
  , stack = [-1]
435
540
  , parentStack = []
436
- , templateRe = /([ \t]*)(%?)((?:("|')(?:\\.|[^\\])*?\4|[-\w:.#[\]~^$*|]=?)*) ?([\/>=@^;]|)(([\])}]?).*?([[({]?))(?=\x1f|$)/gm
541
+ , templateRe = /([ \t]*)(%?)((?:("|')(?:\\.|[^\\])*?\4|[-#:.\w[\]](?:[~^$*|]?=)?)*) ?([\/>=@^;]|)(([\])}]?).*?([[({]?))(?=\x1f|$)/gm
542
+ replace(templateRe, work, str)
543
+ work("", "")
544
+ if (parent.childNodes[0]) {
545
+ append(root, parent.childNodes)
546
+ render(root)
547
+ /*** debug ***/
548
+ console.log("Outside view defined elements are rendered immediately into UI")
549
+ /**/
550
+ }
551
+ if (parent.i) {
552
+ histStart(viewShow)
553
+ }
437
554
 
438
555
  function work(all, indent, plugin, sel, q, op, text, mapEnd, mapStart, offset) {
439
556
  if (offset && all === indent) return
440
557
 
441
558
  for (q = indent.length; q <= stack[0]; ) {
442
- if (parent.p) {
443
- if (parent.p.c && !parent.p.e.childNodes[0]) break
444
- parent.p.d(parent.p)
559
+ if ((offset = parent.p)) {
560
+ if (offset.c && !offset.e.childNodes[0]) break
561
+ offset.d(offset)
445
562
  }
446
563
  parent = parentStack.pop()
447
564
  stack.shift()
448
565
  }
449
566
  if (op === "@") {
450
- text = replace(text, /([\w,.]+):?/, "on!'$1',")
567
+ text = replace(/([\w,.]+)[!:]?/, /^\w+!/.test(text) ? "one!'$1'," : "on!'$1',", text)
451
568
  }
452
569
  if (parent.r) {
453
570
  parent.t += "\n" + all
@@ -469,7 +586,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
469
586
  }
470
587
  if (text && op != "/") {
471
588
  if (op === ">") {
472
- replace(indent + " " + text, templateRe, work)
589
+ replace(templateRe, work, indent + " " + text)
473
590
  } else if (op === "=") {
474
591
  append(parent, text) // + "\n")
475
592
  } else {
@@ -481,56 +598,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
481
598
  }
482
599
  }
483
600
  }
484
- replace(str, templateRe, work)
485
- work("", "")
486
- if (parent.childNodes[0]) {
487
- append(root, parent.childNodes)
488
- render(root)
489
- /*** debug ***/
490
- console.log("Outside view defined elements are rendered immediately into UI")
491
- /**/
492
- }
493
- if (parent.i) {
494
- histStart(viewShow)
495
- }
496
- }
497
- function viewPing(view, params) {
498
- var parent
499
- , tmp = params._v || view // Continue bubbleUp from _v
500
- lastParams = params
501
- lastView = view
502
- params._c = view.o ? view : params._c
503
- for (View.route = view.r; tmp; tmp = parent) {
504
- viewEmit(syncResume = params._v = tmp, "ping", params, View)
505
- syncResume = UNDEF
506
- if (lastParams !== params) return
507
- if ((parent = tmp.p)) {
508
- if (parent.c && parent.c !== tmp) {
509
- params._c = parent.c
510
- }
511
- parent.c = tmp
512
- }
513
- if (tmp.f) {
514
- return xhr.load(
515
- replace(tmp.f, /^|,/g, "$&" + (View.path || "")).split(","),
516
- bind(readTemplates, view, view.wait(tmp.f = ""))
517
- )
518
- } else if (!tmp.e) {
519
- if (tmp.r === "404") {
520
- viewParse("%view 404 #\nh2 Not found")
521
- }
522
- return viewShow("404")
523
- }
524
- }
525
-
526
- for (tmp in params) {
527
- if (tmp.charAt(0) !== "_" && (syncResume = hasOwn(paramCb, tmp) && paramCb[tmp] || paramCb["*"])) {
528
- syncResume(params[tmp], tmp, view, params)
529
- syncResume = UNDEF
530
- }
531
- }
532
- viewEmit(view, "nav")
533
- bubbleDown(params)
534
601
  }
535
602
  function viewShow(url) {
536
603
  if (url === true) {
@@ -542,11 +609,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
542
609
  , view = viewGet(url, params)
543
610
  if (!view.o || lastUrl !== url) {
544
611
  $d.url = lastUrl = expand(url)
545
- viewPing(view, params)
612
+ viewEmit(lastView = view, "nav", lastParams = params)
613
+ bubbleUp(params)
546
614
  }
547
615
  }
548
616
 
549
- function addPlugin(name, proto) {
617
+ function addPlugin(name, proto, expectContent) {
550
618
  plugins[name] = Plugin
551
619
  function Plugin(parent, op, sep) {
552
620
  var plugin = this
@@ -560,15 +628,14 @@ console.log("LiteJS is in debug mode, but it's fine for production")
560
628
  plugin.o = op
561
629
  plugin.s = sep
562
630
  } else {
563
- if (plugin.c) {
631
+ if (expectContent) {
564
632
  elCache = create(plugin.c = elCache)
565
633
  }
566
634
  plugin.e = El(name === "svg" ? name : "div")
567
635
  plugin.e.p = plugin
568
636
  }
569
637
  }
570
- if (proto.r) proto.d = Function("p", "p.r(p.o+p.t)")
571
- assign(Plugin.prototype, proto)
638
+ assign(Plugin.prototype, isFn(proto) ? { d: Function("p", "p.r(p.o+p.t)"), r: proto } : proto)
572
639
  }
573
640
  function usePluginContent(plugin) {
574
641
  var el = plugin.e
@@ -602,69 +669,44 @@ console.log("LiteJS is in debug mode, but it's fine for production")
602
669
  parent._cp = parent.childNodes.length - 1
603
670
  }
604
671
  })
605
- addPlugin("css", { r: injectCss })
606
- addPlugin("def", { r: viewDef })
607
- addPlugin("js", { r: viewEval })
608
- addPlugin("each", {
609
- r: function() {
610
- var txt = this.t
611
- each(this.o, function(param) {
612
- viewParse(replace(txt, /{key}/g, param))
613
- })
614
- }
672
+ addPlugin("css", injectCss)
673
+ addPlugin("def", viewDef)
674
+ addPlugin("js", viewEval)
675
+ addPlugin("each", function() {
676
+ var txt = this.t
677
+ each(this.o, function(param) {
678
+ viewParse(replace(/{key}/g, param, txt))
679
+ })
615
680
  })
616
681
  addPlugin("el", {
617
- c: 1,
618
682
  d: function(plugin, el) {
619
683
  el = usePluginContent(plugin)
620
684
  elCache[plugin.n] = el
621
685
  }
622
- })
686
+ }, 1)
623
687
  plugins.svg = plugins.el
624
- addPlugin("map", {
625
- r: function(txt) {
626
- var plugin = this
627
- appendBind(plugin.u, plugin.s ? txt.slice(1) : txt, plugin.s)
628
- }
688
+ addPlugin("map", function(txt) {
689
+ var plugin = this
690
+ appendBind(plugin.u, plugin.s ? txt.slice(1) : txt, plugin.s)
629
691
  })
630
692
  addPlugin("view", {
631
- c: 1,
632
693
  d: function(plugin) {
633
- var expr = getAttr(plugin.e, BIND_ATTR)
694
+ var expr = getAttr(plugin.e, "_b")
634
695
  , view = View(plugin.n, usePluginContent(plugin), plugin.x)
635
696
  if (expr) {
636
- viewEval(replace(expr, renderRe, function(_, name, op, args) {
697
+ viewEval(replace(renderRe, function(_, name, op, args) {
637
698
  return "($s." + name + (isFn(view[name]) ? "(" + (args || "") + ")" : "=" + args) + "),"
638
- }) + "1", view)
699
+ }, expr) + "1", view)
639
700
  }
640
701
  }
641
- })
702
+ }, 1)
642
703
 
643
704
  /*** breakpoints ***/
644
- var lastSize, lastOrient
645
- , breakpoints = opts.breakpoints
646
- , setBreakpointsRated = rate(function() {
705
+ var breakpoints = opts.breakpoints
706
+ , setBreakpointsRated = rate(function(width) {
647
707
  // document.documentElement.clientWidth is 0 in IE5
648
- var point, next
649
- , width = html.offsetWidth
650
-
651
- for (point in breakpoints) {
652
- if (breakpoints[point] > width) break
653
- next = point
654
- }
655
-
656
- if (next != lastSize) {
657
- cls(html, lastSize, 0)
658
- cls(html, lastSize = next)
659
- }
660
-
661
- next = width > html.offsetHeight ? "land" : "port"
662
-
663
- if (next != lastOrient) {
664
- cls(html, lastOrient, 0)
665
- cls(html, lastOrient = next)
666
- }
667
-
708
+ bindingsIs(html, (width = html.offsetWidth), breakpoints, "")
709
+ bindingsIs(html, +(width > html.offsetHeight), "port,1=land", "")
668
710
  emit(View, "resize")
669
711
  }, 99)
670
712
 
@@ -737,18 +779,15 @@ console.log("LiteJS is in debug mode, but it's fine for production")
737
779
  pattern: function(str, re) {
738
780
  var values = []
739
781
  , t = translations["~"] || {}
740
- , key = replace(str, RegExp(re || t[""] || "[\\d.]+", "g"), function(a) {
782
+ , key = replace(RegExp(re || t[""] || "[\\d.]+", "g"), function(a) {
741
783
  values.push(a)
742
784
  return "#"
743
- })
744
- return str != key && t[key] ? replace(t[key], /#/g, bind(values.shift, values)) : str
785
+ }, str)
786
+ return str != key ? replace(/#/g, bind(values.shift, values), iGet(t, key, str)) : str
745
787
  },
746
788
  pick: function(val, word) {
747
- for (var t = translations["?"] || {}, arr = replace((t[word] || word), /([^;=,]+?)\?/g, "$1=$1;").split(/[;=,]/), i = 1|arr.length; i > 0; ) {
748
- if ((i-=2) < 0 || arr[i] && (arr[i] == "" + val || +arr[i] <= val)) {
749
- return arr[i + 1] ? replace(arr[i + 1], "#", val) : ""
750
- }
751
- }
789
+ var t = translations["?"] || {}
790
+ return pick(val, t[word] || word)
752
791
  },
753
792
  plural: function(n, word, expr) {
754
793
  var t = translations["*"] || {}
@@ -774,10 +813,10 @@ console.log("LiteJS is in debug mode, but it's fine for production")
774
813
  S: "Milliseconds()"
775
814
  }
776
815
  , setA = "a.setTime(+d+((4-(" + get + dateMap.d + "))*864e5))"
777
- return replace((utc ? mask.slice(4) : mask), dateRe, function(match, MD, single, pad, text, esc) {
816
+ return replace(dateRe, function(match, MD, single, pad, text, esc) {
778
817
  mask = (
779
- esc ? replace(replace(escape(esc), /%u/g, "\\u"), /%/g, "\\x") :
780
- text !== UNDEF ? replace(text, /''/g, "'") :
818
+ esc ? replace(/%/g, "\\x", replace(/%u/g, "\\u", escape(esc))) :
819
+ text !== UNDEF ? replace(/''/g, "'", text) :
781
820
  MD || match == "dd" ? "l[''][" + get + (MD == "M" ? "Month()+" + (match == "MMM" ? 14 : 26) : "Day()" + (pad ? (pad = "") : "+7")) + "]" :
782
821
  match == "u" ? "(d/1000)>>>0" :
783
822
  match == "U" ? "+d" :
@@ -794,7 +833,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
794
833
  pad ? "(t=" + mask + ")>9?t:'0'+t" :
795
834
  mask
796
835
  ) + ")+\""
797
- })
836
+ }, (utc ? mask.slice(4) : mask))
798
837
  }
799
838
 
800
839
  function numStr(format, t) {
@@ -813,7 +852,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
813
852
  , m3 = /([.,\/])(\d*)$/.exec(m2[2])
814
853
  , decimals = m3 && m3[2].length || 0
815
854
  , full = m3 ? m2[2].slice(0, m3.index) : m2[2]
816
- , num = replace(full, /\D+/g, "")
855
+ , num = replace(/\D+/g, "", full)
817
856
  , sLen = num.length
818
857
  , step = decimals ? +(m3[1] === "/" ? 1 / m3[2] : num + "." + m3[2]) : num
819
858
  , decSep = m3 && m3[1]
@@ -857,7 +896,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
857
896
  fn += (
858
897
  (m2[4] ? ",r=" + (post[m2[4]] || "r+o") : "") +
859
898
  // negative format
860
- ",N&&n>0?" + replace(quote(conf[2] || "-#"), "#", "'+r+'") + ":" +
899
+ ",N&&n>0?" + replace("#", "'+r+'", quote(conf[2] || "-#")) + ":" +
861
900
  (conf[3] ? "n===0?" + quote(conf[3]) + ":" : "") +
862
901
  (m2[1] ? quote(m2[1]) + "+r" : "r") +
863
902
  (m2[6] ? "+" + quote(m2[6]) : "")
@@ -882,11 +921,11 @@ console.log("LiteJS is in debug mode, but it's fine for production")
882
921
  return format(iGet(translations, str, str || ""), data, getExt)
883
922
  }
884
923
  function getExt(obj, str) {
885
- var fn = cache[str] || (cache[str] = (replace(replace(str, /;\s*([#*?@~])(.*)/, function(_, op, arg) {
886
- return ";" + iAlias[op] + " " + quote(arg)
887
- }), renderRe, function(_, name, op, args) {
924
+ var fn = cache[str] || (cache[str] = (replace(renderRe, function(_, name, op, args) {
888
925
  fn = (_ === name) ? name : "$el." + name + "(" + fn + (args ? "," + args : "") + ")"
889
- }), fn === str ? str : makeFn(fn, fn)))
926
+ }, replace(/;\s*([#*?@~])(.*)/, function(_, op, arg) {
927
+ return ";" + iAlias[op] + " " + quote(arg)
928
+ }, str)), fn === str ? str : makeFn(fn, fn)))
890
929
  return str == "$" ? obj : isStr(fn) ? iGet(obj, str, "") : isFn(fn) ? fn(iExt, obj, translations) : ""
891
930
  }
892
931
  })
@@ -915,13 +954,18 @@ console.log("LiteJS is in debug mode, but it's fine for production")
915
954
  }
916
955
  return str
917
956
  }
918
- function iGet(obj, path, fallback) {
957
+ function iGet(obj, path, fallback, tmp) {
919
958
  return isStr(path) ? (
920
- isStr(obj[path]) ? obj[path] :
959
+ NUL != obj[path] ? obj[path] :
960
+ isStr(obj[tmp = path.toLowerCase()]) ? (
961
+ path.slice(1) === tmp.slice(1) ? obj[tmp].charAt(0).toUpperCase() + obj[tmp].slice(1) :
962
+ path === tmp.toUpperCase() ? obj[tmp].toUpperCase() :
963
+ obj[tmp]
964
+ ) :
921
965
  (path = path.split("."))[1] && isObj(obj = obj[path[0]]) && isStr(obj[path[1]]) ? obj[path[1]] :
922
966
  fallback
923
967
  ) :
924
- isArr(path) ? iGet(obj, path[0]) || iGet(obj, path[1]) || iGet(obj, path[2], fallback) :
968
+ isArr(path) ? iGet(obj, path[0], tmp) || iGet(obj, path[1], tmp) || iGet(obj, path[2], fallback) :
925
969
  fallback
926
970
  }
927
971
  /*/
@@ -931,17 +975,13 @@ console.log("LiteJS is in debug mode, but it's fine for production")
931
975
  return View
932
976
  }
933
977
 
934
- function setUrl(url, rep, checkUrl) {
978
+ function setUrl(url, rep) {
935
979
  /*** pushState ***/
936
980
  if (pushBase) {
937
981
  history[rep ? "replaceState" : "pushState"](NUL, NUL, pushBase + url)
938
- } else {
982
+ } else
939
983
  /**/
940
984
  location[rep ? "replace" : "assign"]("#" + url)
941
- /*** pushState ***/
942
- }
943
- /**/
944
- if (checkUrl) checkUrl()
945
985
  }
946
986
 
947
987
  LiteJS.go = setUrl
@@ -953,7 +993,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
953
993
  , baseEl = find(html, "base")
954
994
  , url = getUrl()
955
995
  if (baseEl && history.pushState) {
956
- pushBase = replace(baseEl.href, /.*:\/\/[^/]*|[^\/]*$/g, "")
996
+ pushBase = replace(/.*:\/\/[^/]*|[^\/]*$/g, "", baseEl.href)
957
997
 
958
998
  if (url && !getUrl()) {
959
999
  setUrl(url, 1)
@@ -975,12 +1015,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
975
1015
  if (cb && histLast != (histLast = getUrl())) cb(histLast)
976
1016
  }
977
1017
  function getUrl() {
978
- return replace(
1018
+ return replace(/^[#\/\!]+|[\s\/]+$/g, "",
979
1019
  /*** pushState ***/
980
1020
  pushBase ? location.pathname.slice(pushBase.length) :
981
1021
  /**/
982
1022
  // NOTE: in Firefox location.hash is decoded; in Safari location.pathname is decoded
983
- location.href.split("#")[1] || "", /^[#\/\!]+|[\s\/]+$/g, "")
1023
+ location.href.split("#")[1] || "")
984
1024
  }
985
1025
  }
986
1026
 
@@ -992,7 +1032,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
992
1032
  function El(name) {
993
1033
  var attr
994
1034
  , attrs = {}
995
- , el = replace(name, selectorRe, function(_, op, key, fn, val, quotation) {
1035
+ , el = replace(selectorRe, function(_, op, key, fn, val, quotation) {
996
1036
  attr = 1
997
1037
  val = quotation ? val.slice(1, -1) : val || key
998
1038
  attrs[op =
@@ -1006,7 +1046,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1006
1046
  attrs[op] + (fn === "~" ? " " : "") + val :
1007
1047
  val
1008
1048
  return ""
1009
- }) || "div"
1049
+ }, name) || "div"
1010
1050
 
1011
1051
  // NOTE: IE-s cloneNode consolidates the two text nodes together as one
1012
1052
  // http://brooknovak.wordpress.com/2009/08/23/ies-clonenode-doesnt-actually-clone/
@@ -1030,14 +1070,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1030
1070
  empty: elEmpty,
1031
1071
  kill: elKill,
1032
1072
  off: acceptMany(rmEvent),
1033
- one: acceptMany(function(el, ev, fn) {
1034
- function remove() {
1035
- rmEvent(el, ev, fn)
1036
- rmEvent(el, ev, remove)
1037
- }
1038
- addEvent(el, ev, fn)
1039
- addEvent(el, ev, remove)
1040
- }),
1041
1073
  render: render,
1042
1074
  rm: elRm
1043
1075
  })
@@ -1080,7 +1112,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1080
1112
  subScope.$i = pos++
1081
1113
  subScope.$len = list.length
1082
1114
  subScope[name] = item
1083
- clone[BIND_ATTR] = el[BIND_ATTR]
1115
+ clone._b = el._b
1084
1116
  /*** debug ***/
1085
1117
  clone._li = up
1086
1118
  /**/
@@ -1096,7 +1128,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1096
1128
  tag = elCache[tag] ? tag : fallback
1097
1129
  if (el._el !== tag) {
1098
1130
  var child = El(tag)
1099
- , tmp = child._elb = el._el ? el._elb : el[BIND_ATTR]
1131
+ , tmp = child._elb = el._el ? el._elb : el._b
1100
1132
  if (tmp) appendBind(child, tmp, ";", "^")
1101
1133
  child.$s = el.$s
1102
1134
  child._el = tag
@@ -1114,12 +1146,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1114
1146
  return true
1115
1147
  }
1116
1148
  },
1117
- is: function(el, val, opts, prefix) {
1118
- if (!prefix) prefix = "is-"
1119
- var match = elScope(el)._.ext.pick(val, opts)
1120
- cls(el, el[prefix + opts], 0)
1121
- cls(el, el[prefix + opts] = match && prefix + match)
1122
- },
1149
+ is: bindingsIs,
1123
1150
  name: function(el, name) {
1124
1151
  setAttr(el, "name", expand(name, 1))
1125
1152
  },
@@ -1161,12 +1188,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1161
1188
  function setAttr(el, key, val) {
1162
1189
  var current = getAttr(el, key)
1163
1190
 
1164
- /*** ie8 ***/
1165
1191
  // NOTE: IE5-7 doesn't set styles and removes events when you try to set them.
1166
1192
  // IE6 label with a for attribute will re-select the first option of SELECT list instead of just giving focus.
1167
1193
  // http://webbugtrack.blogspot.com/2007/09/bug-116-for-attribute-woes-in-ie6.html
1168
1194
  // IE8 and below have a bug where changed 'name' not accepted on form submit
1169
- /* c8 ignore next 3 */
1195
+ /* c8 ignore next 4 */
1196
+ /*** ie9 ***/
1170
1197
  if (ie678 && (key === "id" || key === "name" || key === "checked" || key === "style")) {
1171
1198
  el.mergeAttributes(document.createElement("<INPUT " + key + "='" + val + "'>"), false)
1172
1199
  } else
@@ -1229,8 +1256,8 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1229
1256
  }
1230
1257
 
1231
1258
  function appendBind(el, val, sep, q) {
1232
- var current = getAttr(el, BIND_ATTR)
1233
- setAttr(el, BIND_ATTR, (current ? (
1259
+ var current = getAttr(el, "_b")
1260
+ setAttr(el, "_b", (current ? (
1234
1261
  q === "^" ?
1235
1262
  val + sep + current :
1236
1263
  current + sep + val
@@ -1264,7 +1291,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1264
1291
  name = current.split(SP).indexOf(name) > -1 ? current : current + SP + name
1265
1292
  }
1266
1293
  } else {
1267
- name = current ? replace(SP + current + SP, SP + name + SP, SP).trim() : current
1294
+ name = current ? replace(SP + name + SP, SP, SP + current + SP).trim() : current
1268
1295
  }
1269
1296
 
1270
1297
  if (current != name) {
@@ -1274,6 +1301,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1274
1301
  el.className = name
1275
1302
  }
1276
1303
  }
1304
+ return current
1277
1305
  }
1278
1306
 
1279
1307
  function elEmpty(el) {
@@ -1287,7 +1315,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1287
1315
  if (isObj(tr)) bindingsCss(el, tr)
1288
1316
  tr = "transitionend"
1289
1317
  // transitionend fires for each property transitioned
1290
- if ("on" + tr in el) return addEvent(el, tr, bind(elKill, el, el, el = UNDEF))
1318
+ if ("on" + tr in el) return addEvent(el, tr, bind(elKill, el, el))
1291
1319
  }
1292
1320
  if (el._e) {
1293
1321
  emit(el, "kill")
@@ -1312,76 +1340,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1312
1340
  closestScope(el)
1313
1341
  )
1314
1342
  }
1315
- function elTxt(el, txt) {
1316
- if (el[txtAttr] !== txt) el[txtAttr] = txt
1317
- }
1318
- function elVal(el, val) {
1319
- if (!el) return ""
1320
- var input, step, key, value
1321
- , i = 0
1322
- , type = el.type
1323
- , opts = el.options
1324
- , checkbox = type === "checkbox" || type === "radio"
1325
-
1326
- if (el.tagName === "FORM") {
1327
- // Disabled controls do not receive focus,
1328
- // are skipped in tabbing navigation, cannot be successfully posted.
1329
- //
1330
- // Read-only elements receive focus but cannot be modified by the user,
1331
- // are included in tabbing navigation, are successfully posted.
1332
- //
1333
- // Read-only checkboxes can be changed by the user
1334
-
1335
- for (opts = {}; (input = el.elements[i++]); ) if (!input.disabled && (key = input.name || input.id)) {
1336
- value = elVal(input, val != UNDEF ? val[key] : UNDEF)
1337
- if (value !== UNDEF) {
1338
- step = opts
1339
- replace(key, /\[(.*?)\]/g, replacer)
1340
- step[key || step.length] = value
1341
- }
1342
- }
1343
- return opts
1344
- }
1345
-
1346
- if (val !== UNDEF) {
1347
- if (opts) {
1348
- for (value = (isArr(val) ? val : [ val ]).map(String); (input = opts[i++]); ) {
1349
- input.selected = value.indexOf(input.value) > -1
1350
- }
1351
- } else if (el.val) {
1352
- el.val(val)
1353
- } else if (checkbox) {
1354
- el.checked = !!val
1355
- } else {
1356
- el.value = val
1357
- }
1358
- return
1359
- }
1360
-
1361
- if (opts) {
1362
- if (type === "select-multiple") {
1363
- for (val = []; (input = opts[i++]); ) {
1364
- if (input.selected && !input.disabled) {
1365
- val.push(input.valObject || input.value)
1366
- }
1367
- }
1368
- return val
1369
- }
1370
- // IE8 throws error when accessing to options[-1]
1371
- value = el.selectedIndex
1372
- el = value > -1 && opts[value] || el
1373
- }
1374
-
1375
- return checkbox && !el.checked ?
1376
- (type === "radio" ? UNDEF : NUL) :
1377
- el.valObject !== UNDEF ? el.valObject : el.value
1378
-
1379
- function replacer(_, _key, offset) {
1380
- if (step == opts) key = key.slice(0, offset)
1381
- step = step[key] || (step[key] = step[key] === NUL || _key && +_key != _key ? {} : [])
1382
- key = _key
1383
- }
1384
- }
1385
1343
 
1386
1344
  function closestScope(node) {
1387
1345
  for (; (node = node.parentNode); ) {
@@ -1399,13 +1357,13 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1399
1357
  var el, next
1400
1358
  , scope = node.$s || $s || closestScope(node)
1401
1359
 
1402
- /*** ie8 ***/
1360
+ /*** ie9 ***/
1403
1361
  if (ie678 && node.tagName === "SELECT") {
1404
1362
  node.parentNode.insertBefore(node, node)
1405
1363
  }
1406
1364
  /**/
1407
1365
 
1408
- if (hydrate(node, BIND_ATTR, scope)) return
1366
+ if (hydrate(node, "_b", scope)) return
1409
1367
  for (el = node.firstChild; el; el = next) {
1410
1368
  next = el.nextSibling
1411
1369
  render(el, scope)
@@ -1418,23 +1376,23 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1418
1376
  , expr = node[attr] || (node[attr] = setAttr(node, attr, "") || true)
1419
1377
  if (expr !== true) try {
1420
1378
  fn = fnCache[expr] || (fnCache[expr] = makeFn(expr))
1421
- return fn(node, scope, attr, bindOnce)
1379
+ return fn(node, scope, attr, bindOnce, elScope)
1422
1380
  } catch (e) {
1423
1381
  throw e + "\n" + attr + ": " + expr
1424
1382
  }
1425
1383
  }
1426
1384
  function makeFn(fn, raw, i) {
1427
- fn = raw || "$s&&(" + replace(fn, renderRe, function(match, name, op, args) {
1385
+ fn = raw || "$s&&(" + replace(renderRe, function(match, name, op, args) {
1428
1386
  return (
1429
1387
  op ? "($el[$a]=$el[$a].replace($o[" + (i = bindOnce.indexOf(match), i < 0 ? bindOnce.push(match) - 1 : i)+ "],''),0)||" : ""
1430
- ) + "$b['" + (bindings[name] ? name + "'].call($s" + (name == "$s" ? "=El.scope($el,$el)": "") + ",$el" : "set']($el,'" + name + "'") + (args ? "," + args : "") + ")||"
1431
- }) + "$r)"
1432
- var vars = replace(fn, fnRe, "").match(wordRe) || []
1388
+ ) + "$b['" + (bindings[name] ? name + "'].call($s" + (name == "$s" ? "=$S($el,$el)": "") + ",$el" : "set']($el,'" + name + "'") + (args ? "," + args : "") + ")||"
1389
+ }, fn) + "$r)"
1390
+ var vars = replace(fnRe, "", fn).match(wordRe) || []
1433
1391
  for (i = vars.length; i--; ) {
1434
- if (vars.indexOf(vars[i]) !== i) vars.splice(i, 1)
1392
+ if (window[vars[i]] || vars.indexOf(vars[i]) !== i) vars.splice(i, 1)
1435
1393
  else vars[i] += "=$s." + vars[i]
1436
1394
  }
1437
- fn = Function("$el,$s,$a,$o,$r", (vars[0] ? "var " + vars : "") + ";return " + fn)
1395
+ fn = Function("$el,$s,$a,$o,$S,$r", (vars[0] ? "var " + vars : "") + ";return " + fn)
1438
1396
  return fn
1439
1397
  }
1440
1398
 
@@ -1503,8 +1461,8 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1503
1461
  , touches = []
1504
1462
  , touchEv = {}
1505
1463
 
1506
- // tap, swipe + left/right/up/down
1507
- each("pan pinch rotate tap", function(name) {
1464
+ // swipe + left/right/up/down
1465
+ each("hold pan pinch rotate tap", function(name) {
1508
1466
  fixEv[name] = fixEv[name + START] = fixEv[name + END] = ""
1509
1467
  fixFn[name] = touchInit
1510
1468
  })
@@ -1524,7 +1482,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1524
1482
  emit(touchEl, touchMode ? touchMode + END : "tap", e2, touchEv, touchEl)
1525
1483
  touchMode = UNDEF
1526
1484
  }
1527
- if (len < 0) {
1485
+ if (len < 1) {
1528
1486
  touchEl = UNDEF
1529
1487
  }
1530
1488
  if (len === 1) {
@@ -1535,7 +1493,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1535
1493
  touchPos("left", "offsetWidth")
1536
1494
  touchPos("top", "offsetHeight")
1537
1495
  if (e.button === 2 || matches(touchEl, "INPUT,TEXTAREA,SELECT,.no-drag")) return
1538
- touchTick = setTimeout(moveOne, 1500, e, 1)
1496
+ touchTick = setTimeout(moveOne, LiteJS.holdDelay || 800, e, 1)
1539
1497
  }
1540
1498
  moveOne(e || touches[0])
1541
1499
  }
@@ -1624,6 +1582,19 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1624
1582
  }
1625
1583
  /**/
1626
1584
 
1585
+ function bindingsIs(el, val, opts, prefix) {
1586
+ if (!isStr(prefix)) prefix = "is-"
1587
+ var match = pick(val, opts)
1588
+ cls(el, el[prefix + opts], 0)
1589
+ cls(el, el[prefix + opts] = match && prefix + match)
1590
+ }
1591
+ function pick(val, word) {
1592
+ for (var arr = replace(/([^;=,]+?)\?/g, "$1=$1;", word).split(/[;=,]/), i = 1|arr.length; i > 0; ) {
1593
+ if ((i-=2) < 0 || arr[i] && (arr[i] == "" + val || +arr[i] <= val)) {
1594
+ return arr[i + 1] ? replace("#", val, arr[i + 1]) : ""
1595
+ }
1596
+ }
1597
+ }
1627
1598
  function closest(el, sel) {
1628
1599
  return el && html.closest.call(el.nodeType < 2 ? el : el.parentNode, sel)
1629
1600
  }
@@ -1642,16 +1613,13 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1642
1613
  function acceptMany(fn, prepareVal) {
1643
1614
  return function f(el, name, val, selector, delay, data) {
1644
1615
  if (el && name) {
1645
- var i = arguments.length
1646
- if (i > 3 && i < 6) {
1647
- if (isArr(selector)) {
1648
- data = selector
1649
- delay = selector = UNDEF
1650
- } else if (isNum(selector)) {
1651
- data = delay
1652
- delay = selector
1653
- selector = UNDEF
1654
- }
1616
+ if (isNum(selector)) {
1617
+ data = delay
1618
+ delay = selector
1619
+ selector = UNDEF
1620
+ } else if (isArr(selector) || isObj(selector)) {
1621
+ data = selector
1622
+ delay = selector = UNDEF
1655
1623
  }
1656
1624
  if (delay > 0) {
1657
1625
  setTimeout(f, delay, el, name, val, selector, 0, data)
@@ -1659,20 +1627,32 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1659
1627
  }
1660
1628
  if (isObj(name)) {
1661
1629
  for (delay in name) if (hasOwn(name, delay)) {
1662
- f(el, delay, name[delay], selector, 0, data)
1630
+ f(el, delay, name[delay], val, 0, data)
1663
1631
  }
1664
1632
  return
1665
1633
  }
1666
- if (prepareVal) val = prepareVal(el, val, selector, data)
1634
+ if (prepareVal) val = delegate(el, val, selector, data)
1667
1635
  selector = !prepareVal && selector ? findAll(el, selector) : isArr(el) ? el : [ el ]
1668
- var arr = ("" + name).split(splitRe), len = arr.length
1669
1636
  for (delay = 0; (el = selector[delay++]); ) {
1670
- for (i = 0; i < len; ) {
1671
- if (arr[i]) fn(el, arr[i++], isArr(val) ? val[i - 1] : val)
1637
+ for (var result, arr = ("" + name).split(splitRe), i = 0, len = arr.length; i < len; ) {
1638
+ if (arr[i]) {
1639
+ result = fn(el, arr[i++], isArr(val) ? val[i - 1] : val, data)
1640
+ if (!prepareVal && data > 0) f(el, name, result, "", data)
1641
+ }
1672
1642
  }
1673
1643
  }
1674
1644
  }
1675
1645
  }
1646
+ function delegate(el, val, selector, data) {
1647
+ return isStr(val) ? function(e) {
1648
+ var target = selector ? closest(e.target, selector) : el
1649
+ if (target) emit.apply(target, [elScope(el).$ui, val, e, target].concat(data))
1650
+ } :
1651
+ selector ? function(e, touchEv, touchEl) {
1652
+ if (matches(touchEl = e.target, selector)) val(e, touchEv, touchEl, data)
1653
+ } :
1654
+ val
1655
+ }
1676
1656
  }
1677
1657
  function assignDeep(target, map) {
1678
1658
  if (map) for (var k in map) if (hasOwn(map, k)) {
@@ -1687,9 +1667,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1687
1667
  document.activeElement.blur()
1688
1668
  } catch(e) {}
1689
1669
  }
1690
- function camelFn(_, a) {
1691
- return a.toUpperCase()
1692
- }
1693
1670
  function each(arr, fn, scope, key) {
1694
1671
  if (arr) {
1695
1672
  if (isStr(arr)) arr = arr.split(splitRe)
@@ -1730,7 +1707,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1730
1707
  return typeof str === "string"
1731
1708
  }
1732
1709
  function quote(str) {
1733
- return "'" + replace(replace(str || "", /'/g, "\\'"), /\n/g, "\\n") + "'"
1710
+ return "'" + replace(/\n/g, "\\n", replace(/'/g, "\\'", str || "")) + "'"
1734
1711
  }
1735
1712
  // Maximum call rate for Function with optional leading edge and trailing edge
1736
1713
  function rate(fn, ms, onStart, onEnd) {
@@ -1772,7 +1749,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
1772
1749
  elKill(el)
1773
1750
  return el.src
1774
1751
  }), function(res) {
1775
- res = res.concat(sources, next && next.src && next.innerHTML).filter(Boolean)
1752
+ res = res.concat(sources, next && next.src && next.innerHTML)
1776
1753
  if (res[sources.length = 0]) {
1777
1754
  if (!parser) LiteJS.ui = LiteJS()
1778
1755
  each(res, parser)