@litejs/ui 25.5.0 → 26.2.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/README.md +14 -2
- package/css/anim.css +5 -12
- package/css/base.css +19 -155
- package/css/global.css +99 -0
- package/load.js +60 -47
- package/package.json +3 -3
- package/shim.js +59 -24
- package/ui.js +331 -329
package/ui.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
/* litejs.com/MIT-LICENSE.txt */
|
|
3
3
|
|
|
4
|
-
/* global escape, navigator, xhr
|
|
4
|
+
/* global escape, navigator, xhr */
|
|
5
|
+
|
|
6
|
+
// Conditional compilation via toggle comments (processed by build tool):
|
|
7
|
+
// /*** name ***/ code /**/ - `code` active in source; build can strip it
|
|
8
|
+
// /*** name ***/ code1 /*/ code2 /**/ - `code1` active in source, `code2` commented out; build can swap
|
|
5
9
|
|
|
6
10
|
/*** debug ***/
|
|
7
11
|
console.log("LiteJS is in debug mode, but it's fine for production")
|
|
@@ -11,9 +15,9 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
11
15
|
window.El = El
|
|
12
16
|
asEmitter(window.LiteJS = LiteJS)
|
|
13
17
|
|
|
14
|
-
var UNDEF, parser, pushBase, styleNode
|
|
18
|
+
var UNDEF, parser, pushBase, styleNode
|
|
15
19
|
, NUL = null
|
|
16
|
-
// THIS will be undefined in strict mode and window in sloppy mode
|
|
20
|
+
// THIS will be `undefined` in strict mode and `window` in sloppy mode
|
|
17
21
|
, THIS = this
|
|
18
22
|
, html = document.documentElement
|
|
19
23
|
, body = document.body
|
|
@@ -22,57 +26,143 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
22
26
|
, plugins = {}
|
|
23
27
|
, sources = []
|
|
24
28
|
, assign = Object.assign
|
|
29
|
+
// bind(fn, ctx, ...args)() calls fn.call(ctx, ...args); closureless partial application
|
|
25
30
|
, bind = El.bind.bind(El.call)
|
|
26
31
|
, create = Object.create
|
|
27
32
|
, hasOwn = bind(plugins.hasOwnProperty)
|
|
28
33
|
, isArr = Array.isArray
|
|
29
34
|
, slice = emptyArr.slice
|
|
35
|
+
// Closureless utilities via Function() to avoid capturing outer scope
|
|
30
36
|
, elReplace = Function("a,b,c", "a&&b&&(c=a.parentNode)&&c.replaceChild(b,a)")
|
|
31
37
|
, elRm = Function("a,b", "a&&(b=a.parentNode)&&b.removeChild(a)")
|
|
32
38
|
, getAttr = Function("a,b", "return a&&a.getAttribute&&a.getAttribute(b)")
|
|
33
|
-
, replace = Function("a,b,c", "return
|
|
39
|
+
, replace = Function("a,b,c", "return c.replace(a,b)")
|
|
40
|
+
, toCamel = replace.bind(NUL, /\-([a-z])/g, Function("a,b", "return b.toUpperCase()"))
|
|
34
41
|
|
|
42
|
+
/*** ie9 ***/
|
|
35
43
|
// JScript engine in IE8 and below does not recognize vertical tabulation character `\v`.
|
|
36
44
|
// http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
|
|
37
45
|
, ie678 = !+"\v1" // jshint ignore:line
|
|
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 = El.T = "textContent" in html ? "textContent" : "innerText"
|
|
49
|
+
, elTxt = function(el, txt) {
|
|
50
|
+
if (el[txtAttr] !== txt) el[txtAttr] = txt
|
|
51
|
+
}
|
|
52
|
+
/*/
|
|
53
|
+
, elTxt = function(el, txt) {
|
|
54
|
+
if (el.textContent !== txt) el.textContent = txt
|
|
55
|
+
}
|
|
56
|
+
/**/
|
|
38
57
|
|
|
39
58
|
, elSeq = 0
|
|
40
59
|
, elCache = {}
|
|
60
|
+
// Parses ";name! args" binding expressions from _b attribute
|
|
41
61
|
, renderRe = /[;\s]*([-.\w$]+)(?:(!?)[ :]*((?:(["'\/])(?:\\.|[^\\])*?\4|[^;])*))?/g
|
|
62
|
+
// Parses CSS selectors: .class #id [attr=val] :pseudo
|
|
42
63
|
, selectorRe = /([.#:[])([-\w]+)(?:([~^$*|]?)=(("|')(?:\\.|[^\\])*?\5|[-\w]+))?]?/g
|
|
43
64
|
, fnCache = {}
|
|
44
|
-
,
|
|
65
|
+
// Matches tokens to exclude from scope variable extraction: strings, keywords, member access, labels
|
|
66
|
+
, 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
|
|
45
67
|
, wordRe = /[a-z_$][\w$]*/ig
|
|
46
|
-
,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
, bindingsCss = acceptMany(function(el, key, val) {
|
|
51
|
-
el.style[replace(key, camelRe, camelFn)] = val
|
|
52
|
-
})
|
|
53
|
-
, bindingsOn = acceptMany(addEvent, function(el, val, selector, data) {
|
|
54
|
-
return isStr(val) ? function(e) {
|
|
55
|
-
var target = selector ? closest(e.target, selector) : el
|
|
56
|
-
if (target) emit.apply(target, [elScope(el).$ui, val, e, target].concat(data))
|
|
57
|
-
} :
|
|
58
|
-
selector ? function(e, touchEv, touchEl) {
|
|
59
|
-
if (matches(touchEl = e.target, selector)) val(e, touchEv, touchEl, data)
|
|
60
|
-
} :
|
|
61
|
-
val
|
|
68
|
+
, bindingsCss = acceptMany(function(el, key, val, current) {
|
|
69
|
+
current = el.style[key = toCamel(key)]
|
|
70
|
+
el.style[key] = val
|
|
71
|
+
return current
|
|
62
72
|
})
|
|
73
|
+
, bindingsOn = acceptMany(addEvent, 1)
|
|
63
74
|
, bindings = {
|
|
64
75
|
cls: acceptMany(cls),
|
|
65
76
|
css: bindingsCss,
|
|
66
77
|
on: bindingsOn,
|
|
78
|
+
one: acceptMany(function(el, ev, fn) {
|
|
79
|
+
addEvent(el, ev, function remove() {
|
|
80
|
+
rmEvent(el, ev, remove)
|
|
81
|
+
fn.apply(el, arguments)
|
|
82
|
+
})
|
|
83
|
+
}, 1),
|
|
67
84
|
set: acceptMany(setAttr),
|
|
68
85
|
txt: elTxt,
|
|
69
|
-
|
|
86
|
+
/*** form ***/
|
|
87
|
+
val: function elVal(el, val, ignoreFocus) {
|
|
88
|
+
if (!el) return
|
|
89
|
+
var input, step, key, value
|
|
90
|
+
, i = 0
|
|
91
|
+
, type = el.type
|
|
92
|
+
, opts = el.options
|
|
93
|
+
, checkbox = type === "checkbox" || type === "radio"
|
|
94
|
+
|
|
95
|
+
if (el.tagName === "FORM") {
|
|
96
|
+
// Disabled controls do not receive focus,
|
|
97
|
+
// are skipped in tabbing navigation, cannot be successfully posted.
|
|
98
|
+
//
|
|
99
|
+
// Read-only elements receive focus but cannot be modified by the user,
|
|
100
|
+
// are included in tabbing navigation, are successfully posted.
|
|
101
|
+
//
|
|
102
|
+
// Read-only checkboxes can be changed by the user
|
|
103
|
+
|
|
104
|
+
for (opts = {}; (input = el.elements[i++]); ) if (!input.disabled && (key = input.name || input.id)) {
|
|
105
|
+
value = elVal(input, val != UNDEF ? val[key] : UNDEF, ignoreFocus)
|
|
106
|
+
if (value !== UNDEF) {
|
|
107
|
+
step = opts
|
|
108
|
+
replace(/\[(.*?)\]/g, replacer, key)
|
|
109
|
+
step[key || step.length] = value
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return opts
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (val !== UNDEF) {
|
|
116
|
+
try {
|
|
117
|
+
if (!ignoreFocus && document.activeElement === el) return
|
|
118
|
+
} catch (e) {}
|
|
119
|
+
if (opts) {
|
|
120
|
+
for (value = (isArr(val) ? val : [ val ]).map(String); (input = opts[i++]); ) {
|
|
121
|
+
input.selected = value.indexOf(input.value) > -1
|
|
122
|
+
}
|
|
123
|
+
} else if (el.val) {
|
|
124
|
+
el.val(val)
|
|
125
|
+
} else if (checkbox) {
|
|
126
|
+
el.checked = !!val
|
|
127
|
+
} else {
|
|
128
|
+
el.value = val
|
|
129
|
+
}
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (opts) {
|
|
134
|
+
if (type === "select-multiple") {
|
|
135
|
+
for (val = []; (input = opts[i++]); ) {
|
|
136
|
+
if (input.selected && !input.disabled) {
|
|
137
|
+
val.push(input.valObject || input.value)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return val
|
|
141
|
+
}
|
|
142
|
+
// IE8 throws error when accessing to options[-1]
|
|
143
|
+
value = el.selectedIndex
|
|
144
|
+
el = value > -1 && opts[value] || el
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return checkbox && !el.checked ?
|
|
148
|
+
(type === "radio" ? UNDEF : NUL) :
|
|
149
|
+
el.valObject !== UNDEF ? el.valObject : el.value
|
|
150
|
+
|
|
151
|
+
function replacer(_, _key, offset) {
|
|
152
|
+
if (step == opts) key = key.slice(0, offset)
|
|
153
|
+
step = step[key] || (step[key] = step[key] === NUL || _key && +_key != _key ? {} : [])
|
|
154
|
+
key = _key
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**/
|
|
70
158
|
}
|
|
159
|
+
// Stores "!" once-bindings; index used in compiled fn to strip from _b after first run
|
|
71
160
|
, bindOnce = []
|
|
72
161
|
, globalScope = {
|
|
73
162
|
El: El,
|
|
74
163
|
$b: bindings
|
|
75
164
|
}
|
|
165
|
+
// Array-like wrapper methods for multi-element collections (mixed into arrays by ElWrap)
|
|
76
166
|
, elArr = {
|
|
77
167
|
append: function(el) {
|
|
78
168
|
var elWrap = this
|
|
@@ -90,6 +180,8 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
90
180
|
}
|
|
91
181
|
}
|
|
92
182
|
|
|
183
|
+
// fixEv: maps custom event names to native (e.g., touch→"" for non-DOM events)
|
|
184
|
+
// fixFn: transforms event handlers for browser compat (e.g., touch→pointer init)
|
|
93
185
|
, Event = window.Event || window
|
|
94
186
|
, fixEv = Event.fixEv || (Event.fixEv = {})
|
|
95
187
|
, fixFn = Event.fixFn || (Event.fixFn = {})
|
|
@@ -119,27 +211,27 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
119
211
|
(tag == "a" ? " href=\"" + (link || text) + "\"" : op == "@" ? " datetime=\"" + name + "\"" : "") +
|
|
120
212
|
(attr ? " class=\"" + attr.slice(1) + "\">" : ">") +
|
|
121
213
|
(
|
|
122
|
-
op === ">" ? doc(replace(
|
|
214
|
+
op === ">" ? doc(replace(/^> ?/gm, "", text)) :
|
|
123
215
|
tag == "ul" ? "<li>" + text.split(/\n - (?=\S)/).map(inline).join("</li>\n<li>") + "</li>" :
|
|
124
|
-
inline(tag == "a" ? replace(
|
|
216
|
+
inline(tag == "a" ? replace(/^\w+:\/{0,2}/, "", name) : text)
|
|
125
217
|
) +
|
|
126
218
|
"</" + tag + ">" :
|
|
127
|
-
replace(
|
|
219
|
+
replace(/\[([-!*+,/:;@^_`~])((.+?)(?: (\S+?))?)\1(\.[.\w]+)?]/g, inline, tag)
|
|
128
220
|
}
|
|
129
221
|
function block(tag, op, text, media, alt) {
|
|
130
222
|
return op && !isArr(text) ? inline(tag, op, text) :
|
|
131
223
|
media ? "<img src=\"" + media + "\" alt=\"" + alt + "\">" :
|
|
132
|
-
blockRe.test(tag) ? replace(
|
|
224
|
+
blockRe.test(tag) ? replace(blockRe, block, tag) :
|
|
133
225
|
tag === "---" ? "<hr>" : "<p>" + inline(tag) + "</p>"
|
|
134
226
|
}
|
|
135
227
|
function doc(txt) {
|
|
136
|
-
return replace(
|
|
228
|
+
return replace(/^ \b/gm, "<br>", txt.trim()).split(/\n\n+/).map(block).join("\n")
|
|
137
229
|
}
|
|
138
230
|
bindings.t = function(el, text) {
|
|
139
|
-
el.innerHTML = inline(replace(
|
|
231
|
+
el.innerHTML = inline(replace(/</g, "<", text))
|
|
140
232
|
}
|
|
141
233
|
bindings.d = function(el, text) {
|
|
142
|
-
el.innerHTML = doc(replace(
|
|
234
|
+
el.innerHTML = doc(replace(/</g, "<", text))
|
|
143
235
|
}
|
|
144
236
|
/**/
|
|
145
237
|
|
|
@@ -172,12 +264,22 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
172
264
|
return fn(this, a, b, c, d, e)
|
|
173
265
|
}
|
|
174
266
|
}
|
|
267
|
+
function one(type, fn, scope) {
|
|
268
|
+
var emitter = this
|
|
269
|
+
on(emitter, type, function remove() {
|
|
270
|
+
off.call(emitter, type, remove, scope)
|
|
271
|
+
fn.apply(scope, arguments)
|
|
272
|
+
}, scope)
|
|
273
|
+
return emitter
|
|
274
|
+
}
|
|
175
275
|
}
|
|
176
276
|
|
|
277
|
+
// Events stored as triplets [scope, _origin, fn] in emitter._e[type]
|
|
278
|
+
// _origin tracks the unwrapped fn before fixFn (for rmEvent lookup)
|
|
279
|
+
// emptyArr substitutes window as emitter (can't safely add _e property to window)
|
|
177
280
|
function on(emitter, type, fn, scope, _origin) {
|
|
178
281
|
if (emitter && type && fn) {
|
|
179
282
|
if (emitter === window) emitter = emptyArr
|
|
180
|
-
emit(emitter, "newListener", type, fn, scope, _origin)
|
|
181
283
|
var events = emitter._e || (emitter._e = create(NUL))
|
|
182
284
|
;(events[type] || (events[type] = [])).unshift(scope, _origin, fn)
|
|
183
285
|
}
|
|
@@ -185,14 +287,13 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
185
287
|
}
|
|
186
288
|
|
|
187
289
|
function off(type, fn, scope) {
|
|
188
|
-
var i
|
|
290
|
+
var i
|
|
189
291
|
, emitter = this === window ? emptyArr : this
|
|
190
292
|
, events = emitter._e && emitter._e[type]
|
|
191
293
|
if (events) {
|
|
192
294
|
for (i = events.length - 2; i > 0; i -= 3) {
|
|
193
295
|
if ((events[i + 1] === fn || events[i] === fn) && events[i - 1] == scope) {
|
|
194
|
-
|
|
195
|
-
emit(emitter, "removeListener", type, args[2], args[0], args[1])
|
|
296
|
+
events.splice(i - 1, 3)
|
|
196
297
|
if (fn) break
|
|
197
298
|
}
|
|
198
299
|
}
|
|
@@ -200,18 +301,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
200
301
|
return this
|
|
201
302
|
}
|
|
202
303
|
|
|
203
|
-
function one(type, fn, scope) {
|
|
204
|
-
var emitter = this === window ? emptyArr : this
|
|
205
|
-
|
|
206
|
-
function remove() {
|
|
207
|
-
off.call(emitter, type, fn, scope)
|
|
208
|
-
off.call(emitter, type, remove, scope)
|
|
209
|
-
}
|
|
210
|
-
on(emitter, type, remove, scope)
|
|
211
|
-
on(emitter, type, fn, scope)
|
|
212
|
-
return this
|
|
213
|
-
}
|
|
214
|
-
|
|
215
304
|
function emit(emitter, type) {
|
|
216
305
|
if (emitter === window) emitter = emptyArr
|
|
217
306
|
var args, i
|
|
@@ -225,10 +314,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
225
314
|
return _e / 3
|
|
226
315
|
}
|
|
227
316
|
|
|
228
|
-
try {
|
|
229
|
-
addEventListener("t", NUL, { get capture() { canCapture = 1 }})
|
|
230
|
-
} catch(e){}
|
|
231
|
-
|
|
232
317
|
function addEvent(el, ev, fn, opts) {
|
|
233
318
|
var fn2 = fixFn[ev] && fixFn[ev](el, fn, ev) || fn
|
|
234
319
|
, ev2 = fixEv[ev] || ev
|
|
@@ -237,15 +322,13 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
237
322
|
// polyfilled addEventListener returns patched function
|
|
238
323
|
// useCapture defaults to false
|
|
239
324
|
// Chrome56 touchstart/move sets {passive:true} by default; use {passive:false} to enable preventDefault()
|
|
240
|
-
fn2 = html.addEventListener.call(
|
|
241
|
-
el, ev2, fn2, !canCapture && isObj(opts) ? !!opts.capture : opts || false
|
|
242
|
-
) || fn2
|
|
325
|
+
fn2 = html.addEventListener.call(el, ev2, fn2, opts) || fn2
|
|
243
326
|
}
|
|
244
327
|
|
|
245
328
|
on(el, ev, fn2, el, fn)
|
|
246
329
|
}
|
|
247
330
|
|
|
248
|
-
function rmEvent(el, ev, fn) {
|
|
331
|
+
function rmEvent(el, ev, fn, opts) {
|
|
249
332
|
var evs = el._e && el._e[ev]
|
|
250
333
|
, id = evs && evs.indexOf(fn)
|
|
251
334
|
, ev2 = fixEv[ev] || ev
|
|
@@ -254,7 +337,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
254
337
|
evs[id + 1]._rm()
|
|
255
338
|
}
|
|
256
339
|
if (ev2 !== "" && "on" + ev2 in el) {
|
|
257
|
-
html.removeEventListener.call(el, ev2, evs[id + 1])
|
|
340
|
+
html.removeEventListener.call(el, ev2, evs[id + 1], opts)
|
|
258
341
|
}
|
|
259
342
|
evs.splice(id - 1, 3)
|
|
260
343
|
}
|
|
@@ -271,16 +354,16 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
271
354
|
function LiteJS(opts) {
|
|
272
355
|
opts = assign({
|
|
273
356
|
/*** breakpoints ***/
|
|
274
|
-
breakpoints:
|
|
275
|
-
sm: 0,
|
|
276
|
-
md: 601,
|
|
277
|
-
lg: 1025
|
|
278
|
-
},
|
|
357
|
+
breakpoints: "sm,601=md,1025=lg",
|
|
279
358
|
/**/
|
|
280
359
|
home: "home",
|
|
281
360
|
root: body
|
|
282
361
|
}, opts)
|
|
283
362
|
|
|
363
|
+
// View properties:
|
|
364
|
+
// .r route pattern .e template element .p parent view
|
|
365
|
+
// .c active child .o rendered clone .f file dependencies (csv)
|
|
366
|
+
// .s route sequence# .kb keyboard shortcuts
|
|
284
367
|
function View(route, el, parent) {
|
|
285
368
|
var view = views[route]
|
|
286
369
|
if (view) {
|
|
@@ -298,11 +381,11 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
298
381
|
|
|
299
382
|
if (route.charAt(0) !== "#") {
|
|
300
383
|
fnStr += "m[" + (view.s = routeSeq++) + "]?("
|
|
301
|
-
reStr += "|(" + replace(
|
|
384
|
+
reStr += "|(" + replace(routeRe, function(_, expr) {
|
|
302
385
|
return expr ?
|
|
303
386
|
(fnStr += "p['" + expr + "']=m[" + (routeSeq++) + "],") && "([^/]+?)" :
|
|
304
|
-
replace(
|
|
305
|
-
}) + ")"
|
|
387
|
+
replace(reEsc, "\\$&", _)
|
|
388
|
+
}, route) + ")"
|
|
306
389
|
fnStr += "'" + route + "'):"
|
|
307
390
|
viewFn = 0
|
|
308
391
|
}
|
|
@@ -315,11 +398,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
315
398
|
params._p = 1 + (params._p | 0) // pending
|
|
316
399
|
return function() {
|
|
317
400
|
if (--params._p || lastParams !== params || syncResume) return
|
|
318
|
-
|
|
319
|
-
bubbleDown(params)
|
|
320
|
-
} else if (params._v) {
|
|
321
|
-
viewPing(lastView, params)
|
|
322
|
-
}
|
|
401
|
+
bubbleUp(params)
|
|
323
402
|
}
|
|
324
403
|
}
|
|
325
404
|
})
|
|
@@ -365,6 +444,43 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
365
444
|
}
|
|
366
445
|
})
|
|
367
446
|
|
|
447
|
+
// params._p pending async count; ._v current view in traversal; ._c view to close; ._t navigation timestamp
|
|
448
|
+
function bubbleUp(params) {
|
|
449
|
+
var parent
|
|
450
|
+
, view = lastView
|
|
451
|
+
, tmp = params._v || view // Continue bubbleUp from _v
|
|
452
|
+
params._c = view.o ? view : params._c
|
|
453
|
+
for (View.route = view.r; tmp; tmp = parent) {
|
|
454
|
+
viewEmit(syncResume = params._v = tmp, "ping", params, View)
|
|
455
|
+
syncResume = UNDEF
|
|
456
|
+
if (lastParams !== params) return
|
|
457
|
+
if ((parent = tmp.p)) {
|
|
458
|
+
if (parent.c && parent.c !== tmp) {
|
|
459
|
+
params._c = parent.c
|
|
460
|
+
}
|
|
461
|
+
parent.c = tmp
|
|
462
|
+
}
|
|
463
|
+
if (tmp.f) {
|
|
464
|
+
return xhr.load(
|
|
465
|
+
replace(/^|,/g, "$&" + (View.path || ""), tmp.f).split(","),
|
|
466
|
+
bind(readTemplates, view, view.wait(tmp.f = ""))
|
|
467
|
+
)
|
|
468
|
+
} else if (!tmp.e) {
|
|
469
|
+
if (tmp.r === "404") {
|
|
470
|
+
viewParse("%view 404 #\nh2 Not found")
|
|
471
|
+
}
|
|
472
|
+
return viewShow("404")
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
for (tmp in params) {
|
|
477
|
+
if (tmp.charAt(0) !== "_" && (syncResume = hasOwn(paramCb, tmp) && paramCb[tmp] || paramCb["*"])) {
|
|
478
|
+
syncResume(params[tmp], tmp, view, params)
|
|
479
|
+
syncResume = UNDEF
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
bubbleDown(params)
|
|
483
|
+
}
|
|
368
484
|
function bubbleDown(params) {
|
|
369
485
|
var view = params._v
|
|
370
486
|
, close = params._c
|
|
@@ -383,27 +499,30 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
383
499
|
/**/
|
|
384
500
|
params._c = UNDEF
|
|
385
501
|
}
|
|
386
|
-
if ((params.
|
|
502
|
+
if ((params._v = view.c)) {
|
|
387
503
|
bubbleDown(params)
|
|
388
504
|
}
|
|
389
505
|
if ((lastView === view)) {
|
|
390
|
-
|
|
506
|
+
for (; view; view = view.p) {
|
|
507
|
+
viewEmit(view, "pong", params, View)
|
|
508
|
+
}
|
|
509
|
+
viewEmit(lastView, "show", params)
|
|
391
510
|
blur()
|
|
392
511
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
viewEmit(view, "close")
|
|
512
|
+
function viewClose(view, open) {
|
|
513
|
+
if (view && view.o) {
|
|
514
|
+
viewEmit(view.p, "closeChild", view, open)
|
|
515
|
+
viewClose(view.c)
|
|
516
|
+
elKill(view.o)
|
|
517
|
+
view.o = UNDEF
|
|
518
|
+
/*** kb ***/
|
|
519
|
+
rmKb(view.kb)
|
|
520
|
+
/**/
|
|
521
|
+
viewEmit(view, "close")
|
|
522
|
+
}
|
|
405
523
|
}
|
|
406
524
|
}
|
|
525
|
+
|
|
407
526
|
function viewDef(str) {
|
|
408
527
|
for (var match, re = /(\S+) (\S+)/g; (match = re.exec(str)); ) {
|
|
409
528
|
each(match[1], def)
|
|
@@ -437,24 +556,37 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
437
556
|
return View(url ? viewFn(url, params || {}, "404") : View.home)
|
|
438
557
|
}
|
|
439
558
|
function viewParse(str) {
|
|
559
|
+
if (!str) return
|
|
440
560
|
var parent = El("div")
|
|
441
561
|
, stack = [-1]
|
|
442
562
|
, parentStack = []
|
|
443
|
-
, templateRe = /([ \t]*)(%?)((?:("|')(?:\\.|[^\\])*?\4|[
|
|
563
|
+
, templateRe = /([ \t]*)(%?)((?:("|')(?:\\.|[^\\])*?\4|[-#:.\w[\]](?:[~^$*|]?=)?)*) ?([\/>=@^;]|)(([\])}]?).*?([[({]?))(?=\x1f|$)/gm
|
|
564
|
+
replace(templateRe, work, str)
|
|
565
|
+
work("", "")
|
|
566
|
+
if (parent.childNodes[0]) {
|
|
567
|
+
append(root, parent.childNodes)
|
|
568
|
+
render(root)
|
|
569
|
+
/*** debug ***/
|
|
570
|
+
console.log("Outside view defined elements are rendered immediately into UI")
|
|
571
|
+
/**/
|
|
572
|
+
}
|
|
573
|
+
if (parent.i) {
|
|
574
|
+
histStart(viewShow)
|
|
575
|
+
}
|
|
444
576
|
|
|
445
577
|
function work(all, indent, plugin, sel, q, op, text, mapEnd, mapStart, offset) {
|
|
446
578
|
if (offset && all === indent) return
|
|
447
579
|
|
|
448
580
|
for (q = indent.length; q <= stack[0]; ) {
|
|
449
|
-
if (parent.p) {
|
|
450
|
-
if (
|
|
451
|
-
|
|
581
|
+
if ((offset = parent.p)) {
|
|
582
|
+
if (offset.c && !offset.e.childNodes[0]) break
|
|
583
|
+
offset.d(offset)
|
|
452
584
|
}
|
|
453
585
|
parent = parentStack.pop()
|
|
454
586
|
stack.shift()
|
|
455
587
|
}
|
|
456
588
|
if (op === "@") {
|
|
457
|
-
text = replace(
|
|
589
|
+
text = replace(/([\w,.]+)[!:]?/, /^\w+!/.test(text) ? "one!'$1'," : "on!'$1',", text)
|
|
458
590
|
}
|
|
459
591
|
if (parent.r) {
|
|
460
592
|
parent.t += "\n" + all
|
|
@@ -476,7 +608,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
476
608
|
}
|
|
477
609
|
if (text && op != "/") {
|
|
478
610
|
if (op === ">") {
|
|
479
|
-
replace(indent + " " + text
|
|
611
|
+
replace(templateRe, work, indent + " " + text)
|
|
480
612
|
} else if (op === "=") {
|
|
481
613
|
append(parent, text) // + "\n")
|
|
482
614
|
} else {
|
|
@@ -488,56 +620,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
488
620
|
}
|
|
489
621
|
}
|
|
490
622
|
}
|
|
491
|
-
replace(str, templateRe, work)
|
|
492
|
-
work("", "")
|
|
493
|
-
if (parent.childNodes[0]) {
|
|
494
|
-
append(root, parent.childNodes)
|
|
495
|
-
render(root)
|
|
496
|
-
/*** debug ***/
|
|
497
|
-
console.log("Outside view defined elements are rendered immediately into UI")
|
|
498
|
-
/**/
|
|
499
|
-
}
|
|
500
|
-
if (parent.i) {
|
|
501
|
-
histStart(viewShow)
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
function viewPing(view, params) {
|
|
505
|
-
var parent
|
|
506
|
-
, tmp = params._v || view // Continue bubbleUp from _v
|
|
507
|
-
lastParams = params
|
|
508
|
-
lastView = view
|
|
509
|
-
params._c = view.o ? view : params._c
|
|
510
|
-
for (View.route = view.r; tmp; tmp = parent) {
|
|
511
|
-
viewEmit(syncResume = params._v = tmp, "ping", params, View)
|
|
512
|
-
syncResume = UNDEF
|
|
513
|
-
if (lastParams !== params) return
|
|
514
|
-
if ((parent = tmp.p)) {
|
|
515
|
-
if (parent.c && parent.c !== tmp) {
|
|
516
|
-
params._c = parent.c
|
|
517
|
-
}
|
|
518
|
-
parent.c = tmp
|
|
519
|
-
}
|
|
520
|
-
if (tmp.f) {
|
|
521
|
-
return xhr.load(
|
|
522
|
-
replace(tmp.f, /^|,/g, "$&" + (View.path || "")).split(","),
|
|
523
|
-
bind(readTemplates, view, view.wait(tmp.f = ""))
|
|
524
|
-
)
|
|
525
|
-
} else if (!tmp.e) {
|
|
526
|
-
if (tmp.r === "404") {
|
|
527
|
-
viewParse("%view 404 #\nh2 Not found")
|
|
528
|
-
}
|
|
529
|
-
return viewShow("404")
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
for (tmp in params) {
|
|
534
|
-
if (tmp.charAt(0) !== "_" && (syncResume = hasOwn(paramCb, tmp) && paramCb[tmp] || paramCb["*"])) {
|
|
535
|
-
syncResume(params[tmp], tmp, view, params)
|
|
536
|
-
syncResume = UNDEF
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
viewEmit(view, "nav")
|
|
540
|
-
bubbleDown(params)
|
|
541
623
|
}
|
|
542
624
|
function viewShow(url) {
|
|
543
625
|
if (url === true) {
|
|
@@ -549,11 +631,17 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
549
631
|
, view = viewGet(url, params)
|
|
550
632
|
if (!view.o || lastUrl !== url) {
|
|
551
633
|
$d.url = lastUrl = expand(url)
|
|
552
|
-
|
|
634
|
+
viewEmit(lastView = view, "nav", lastParams = params)
|
|
635
|
+
bubbleUp(params)
|
|
553
636
|
}
|
|
554
637
|
}
|
|
555
638
|
|
|
556
|
-
|
|
639
|
+
// Plugin properties:
|
|
640
|
+
// .n name .x parent view name .u parent DOM element
|
|
641
|
+
// .e container el .d done callback .c saved elCache (for %el/%view)
|
|
642
|
+
// When proto is a function, plugin accumulates raw text:
|
|
643
|
+
// .r raw handler .t accumulated text .o original op+text .s separator
|
|
644
|
+
function addPlugin(name, proto, expectContent) {
|
|
557
645
|
plugins[name] = Plugin
|
|
558
646
|
function Plugin(parent, op, sep) {
|
|
559
647
|
var plugin = this
|
|
@@ -567,15 +655,14 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
567
655
|
plugin.o = op
|
|
568
656
|
plugin.s = sep
|
|
569
657
|
} else {
|
|
570
|
-
if (
|
|
658
|
+
if (expectContent) {
|
|
571
659
|
elCache = create(plugin.c = elCache)
|
|
572
660
|
}
|
|
573
661
|
plugin.e = El(name === "svg" ? name : "div")
|
|
574
662
|
plugin.e.p = plugin
|
|
575
663
|
}
|
|
576
664
|
}
|
|
577
|
-
|
|
578
|
-
assign(Plugin.prototype, proto)
|
|
665
|
+
assign(Plugin.prototype, isFn(proto) ? { d: Function("p", "p.r(p.o+p.t)"), r: proto } : proto)
|
|
579
666
|
}
|
|
580
667
|
function usePluginContent(plugin) {
|
|
581
668
|
var el = plugin.e
|
|
@@ -609,69 +696,44 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
609
696
|
parent._cp = parent.childNodes.length - 1
|
|
610
697
|
}
|
|
611
698
|
})
|
|
612
|
-
addPlugin("css",
|
|
613
|
-
addPlugin("def",
|
|
614
|
-
addPlugin("js",
|
|
615
|
-
addPlugin("each", {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
})
|
|
621
|
-
}
|
|
699
|
+
addPlugin("css", injectCss)
|
|
700
|
+
addPlugin("def", viewDef)
|
|
701
|
+
addPlugin("js", viewEval)
|
|
702
|
+
addPlugin("each", function() {
|
|
703
|
+
var txt = this.t
|
|
704
|
+
each(this.o, function(param) {
|
|
705
|
+
viewParse(replace(/{key}/g, param, txt))
|
|
706
|
+
})
|
|
622
707
|
})
|
|
623
708
|
addPlugin("el", {
|
|
624
|
-
c: 1,
|
|
625
709
|
d: function(plugin, el) {
|
|
626
710
|
el = usePluginContent(plugin)
|
|
627
711
|
elCache[plugin.n] = el
|
|
628
712
|
}
|
|
629
|
-
})
|
|
713
|
+
}, 1)
|
|
630
714
|
plugins.svg = plugins.el
|
|
631
|
-
addPlugin("map", {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
appendBind(plugin.u, plugin.s ? txt.slice(1) : txt, plugin.s)
|
|
635
|
-
}
|
|
715
|
+
addPlugin("map", function(txt) {
|
|
716
|
+
var plugin = this
|
|
717
|
+
appendBind(plugin.u, plugin.s ? txt.slice(1) : txt, plugin.s)
|
|
636
718
|
})
|
|
637
719
|
addPlugin("view", {
|
|
638
|
-
c: 1,
|
|
639
720
|
d: function(plugin) {
|
|
640
721
|
var expr = getAttr(plugin.e, "_b")
|
|
641
722
|
, view = View(plugin.n, usePluginContent(plugin), plugin.x)
|
|
642
723
|
if (expr) {
|
|
643
|
-
viewEval(replace(
|
|
724
|
+
viewEval(replace(renderRe, function(_, name, op, args) {
|
|
644
725
|
return "($s." + name + (isFn(view[name]) ? "(" + (args || "") + ")" : "=" + args) + "),"
|
|
645
|
-
}) + "1", view)
|
|
726
|
+
}, expr) + "1", view)
|
|
646
727
|
}
|
|
647
728
|
}
|
|
648
|
-
})
|
|
729
|
+
}, 1)
|
|
649
730
|
|
|
650
731
|
/*** breakpoints ***/
|
|
651
|
-
var
|
|
652
|
-
,
|
|
653
|
-
, setBreakpointsRated = rate(function() {
|
|
732
|
+
var breakpoints = opts.breakpoints
|
|
733
|
+
, setBreakpointsRated = rate(function(width) {
|
|
654
734
|
// document.documentElement.clientWidth is 0 in IE5
|
|
655
|
-
|
|
656
|
-
, width
|
|
657
|
-
|
|
658
|
-
for (point in breakpoints) {
|
|
659
|
-
if (breakpoints[point] > width) break
|
|
660
|
-
next = point
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
if (next != lastSize) {
|
|
664
|
-
cls(html, lastSize, 0)
|
|
665
|
-
cls(html, lastSize = next)
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
next = width > html.offsetHeight ? "land" : "port"
|
|
669
|
-
|
|
670
|
-
if (next != lastOrient) {
|
|
671
|
-
cls(html, lastOrient, 0)
|
|
672
|
-
cls(html, lastOrient = next)
|
|
673
|
-
}
|
|
674
|
-
|
|
735
|
+
bindingsIs(html, (width = html.offsetWidth), breakpoints, "")
|
|
736
|
+
bindingsIs(html, +(width > html.offsetHeight), "port,1=land", "")
|
|
675
737
|
emit(View, "resize")
|
|
676
738
|
}, 99)
|
|
677
739
|
|
|
@@ -744,18 +806,15 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
744
806
|
pattern: function(str, re) {
|
|
745
807
|
var values = []
|
|
746
808
|
, t = translations["~"] || {}
|
|
747
|
-
, key = replace(
|
|
809
|
+
, key = replace(RegExp(re || t[""] || "[\\d.]+", "g"), function(a) {
|
|
748
810
|
values.push(a)
|
|
749
811
|
return "#"
|
|
750
|
-
})
|
|
751
|
-
return str != key ? replace(
|
|
812
|
+
}, str)
|
|
813
|
+
return str != key ? replace(/#/g, bind(values.shift, values), iGet(t, key, str)) : str
|
|
752
814
|
},
|
|
753
815
|
pick: function(val, word) {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
return arr[i + 1] ? replace(arr[i + 1], "#", val) : ""
|
|
757
|
-
}
|
|
758
|
-
}
|
|
816
|
+
var t = translations["?"] || {}
|
|
817
|
+
return pick(val, t[word] || word)
|
|
759
818
|
},
|
|
760
819
|
plural: function(n, word, expr) {
|
|
761
820
|
var t = translations["*"] || {}
|
|
@@ -781,10 +840,10 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
781
840
|
S: "Milliseconds()"
|
|
782
841
|
}
|
|
783
842
|
, setA = "a.setTime(+d+((4-(" + get + dateMap.d + "))*864e5))"
|
|
784
|
-
return replace(
|
|
843
|
+
return replace(dateRe, function(match, MD, single, pad, text, esc) {
|
|
785
844
|
mask = (
|
|
786
|
-
esc ? replace(replace(
|
|
787
|
-
text !== UNDEF ? replace(
|
|
845
|
+
esc ? replace(/%/g, "\\x", replace(/%u/g, "\\u", escape(esc))) :
|
|
846
|
+
text !== UNDEF ? replace(/''/g, "'", text) :
|
|
788
847
|
MD || match == "dd" ? "l[''][" + get + (MD == "M" ? "Month()+" + (match == "MMM" ? 14 : 26) : "Day()" + (pad ? (pad = "") : "+7")) + "]" :
|
|
789
848
|
match == "u" ? "(d/1000)>>>0" :
|
|
790
849
|
match == "U" ? "+d" :
|
|
@@ -801,7 +860,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
801
860
|
pad ? "(t=" + mask + ")>9?t:'0'+t" :
|
|
802
861
|
mask
|
|
803
862
|
) + ")+\""
|
|
804
|
-
})
|
|
863
|
+
}, (utc ? mask.slice(4) : mask))
|
|
805
864
|
}
|
|
806
865
|
|
|
807
866
|
function numStr(format, t) {
|
|
@@ -820,7 +879,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
820
879
|
, m3 = /([.,\/])(\d*)$/.exec(m2[2])
|
|
821
880
|
, decimals = m3 && m3[2].length || 0
|
|
822
881
|
, full = m3 ? m2[2].slice(0, m3.index) : m2[2]
|
|
823
|
-
, num = replace(
|
|
882
|
+
, num = replace(/\D+/g, "", full)
|
|
824
883
|
, sLen = num.length
|
|
825
884
|
, step = decimals ? +(m3[1] === "/" ? 1 / m3[2] : num + "." + m3[2]) : num
|
|
826
885
|
, decSep = m3 && m3[1]
|
|
@@ -864,7 +923,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
864
923
|
fn += (
|
|
865
924
|
(m2[4] ? ",r=" + (post[m2[4]] || "r+o") : "") +
|
|
866
925
|
// negative format
|
|
867
|
-
",N&&n>0?" + replace(quote(conf[2] || "-#")
|
|
926
|
+
",N&&n>0?" + replace("#", "'+r+'", quote(conf[2] || "-#")) + ":" +
|
|
868
927
|
(conf[3] ? "n===0?" + quote(conf[3]) + ":" : "") +
|
|
869
928
|
(m2[1] ? quote(m2[1]) + "+r" : "r") +
|
|
870
929
|
(m2[6] ? "+" + quote(m2[6]) : "")
|
|
@@ -889,11 +948,11 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
889
948
|
return format(iGet(translations, str, str || ""), data, getExt)
|
|
890
949
|
}
|
|
891
950
|
function getExt(obj, str) {
|
|
892
|
-
var fn = cache[str] || (cache[str] = (replace(
|
|
893
|
-
return ";" + iAlias[op] + " " + quote(arg)
|
|
894
|
-
}), renderRe, function(_, name, op, args) {
|
|
951
|
+
var fn = cache[str] || (cache[str] = (replace(renderRe, function(_, name, op, args) {
|
|
895
952
|
fn = (_ === name) ? name : "$el." + name + "(" + fn + (args ? "," + args : "") + ")"
|
|
896
|
-
}
|
|
953
|
+
}, replace(/;\s*([#*?@~])(.*)/, function(_, op, arg) {
|
|
954
|
+
return ";" + iAlias[op] + " " + quote(arg)
|
|
955
|
+
}, str)), fn === str ? str : makeFn(fn, fn)))
|
|
897
956
|
return str == "$" ? obj : isStr(fn) ? iGet(obj, str, "") : isFn(fn) ? fn(iExt, obj, translations) : ""
|
|
898
957
|
}
|
|
899
958
|
})
|
|
@@ -924,7 +983,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
924
983
|
}
|
|
925
984
|
function iGet(obj, path, fallback, tmp) {
|
|
926
985
|
return isStr(path) ? (
|
|
927
|
-
|
|
986
|
+
NUL != obj[path] ? obj[path] :
|
|
928
987
|
isStr(obj[tmp = path.toLowerCase()]) ? (
|
|
929
988
|
path.slice(1) === tmp.slice(1) ? obj[tmp].charAt(0).toUpperCase() + obj[tmp].slice(1) :
|
|
930
989
|
path === tmp.toUpperCase() ? obj[tmp].toUpperCase() :
|
|
@@ -943,17 +1002,13 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
943
1002
|
return View
|
|
944
1003
|
}
|
|
945
1004
|
|
|
946
|
-
function setUrl(url, rep
|
|
1005
|
+
function setUrl(url, rep) {
|
|
947
1006
|
/*** pushState ***/
|
|
948
1007
|
if (pushBase) {
|
|
949
1008
|
history[rep ? "replaceState" : "pushState"](NUL, NUL, pushBase + url)
|
|
950
|
-
} else
|
|
1009
|
+
} else
|
|
951
1010
|
/**/
|
|
952
1011
|
location[rep ? "replace" : "assign"]("#" + url)
|
|
953
|
-
/*** pushState ***/
|
|
954
|
-
}
|
|
955
|
-
/**/
|
|
956
|
-
if (checkUrl) checkUrl()
|
|
957
1012
|
}
|
|
958
1013
|
|
|
959
1014
|
LiteJS.go = setUrl
|
|
@@ -965,7 +1020,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
965
1020
|
, baseEl = find(html, "base")
|
|
966
1021
|
, url = getUrl()
|
|
967
1022
|
if (baseEl && history.pushState) {
|
|
968
|
-
pushBase = replace(
|
|
1023
|
+
pushBase = replace(/.*:\/\/[^/]*|[^\/]*$/g, "", baseEl.href)
|
|
969
1024
|
|
|
970
1025
|
if (url && !getUrl()) {
|
|
971
1026
|
setUrl(url, 1)
|
|
@@ -987,12 +1042,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
987
1042
|
if (cb && histLast != (histLast = getUrl())) cb(histLast)
|
|
988
1043
|
}
|
|
989
1044
|
function getUrl() {
|
|
990
|
-
return replace(
|
|
1045
|
+
return replace(/^[#\/\!]+|[\s\/]+$/g, "",
|
|
991
1046
|
/*** pushState ***/
|
|
992
1047
|
pushBase ? location.pathname.slice(pushBase.length) :
|
|
993
1048
|
/**/
|
|
994
1049
|
// NOTE: in Firefox location.hash is decoded; in Safari location.pathname is decoded
|
|
995
|
-
location.href.split("#")[1] || ""
|
|
1050
|
+
location.href.split("#")[1] || "")
|
|
996
1051
|
}
|
|
997
1052
|
}
|
|
998
1053
|
|
|
@@ -1004,7 +1059,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1004
1059
|
function El(name) {
|
|
1005
1060
|
var attr
|
|
1006
1061
|
, attrs = {}
|
|
1007
|
-
, el = replace(
|
|
1062
|
+
, el = replace(selectorRe, function(_, op, key, fn, val, quotation) {
|
|
1008
1063
|
attr = 1
|
|
1009
1064
|
val = quotation ? val.slice(1, -1) : val || key
|
|
1010
1065
|
attrs[op =
|
|
@@ -1018,7 +1073,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1018
1073
|
attrs[op] + (fn === "~" ? " " : "") + val :
|
|
1019
1074
|
val
|
|
1020
1075
|
return ""
|
|
1021
|
-
}) || "div"
|
|
1076
|
+
}, name) || "div"
|
|
1022
1077
|
|
|
1023
1078
|
// NOTE: IE-s cloneNode consolidates the two text nodes together as one
|
|
1024
1079
|
// http://brooknovak.wordpress.com/2009/08/23/ies-clonenode-doesnt-actually-clone/
|
|
@@ -1042,14 +1097,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1042
1097
|
empty: elEmpty,
|
|
1043
1098
|
kill: elKill,
|
|
1044
1099
|
off: acceptMany(rmEvent),
|
|
1045
|
-
one: acceptMany(function(el, ev, fn) {
|
|
1046
|
-
function remove() {
|
|
1047
|
-
rmEvent(el, ev, fn)
|
|
1048
|
-
rmEvent(el, ev, remove)
|
|
1049
|
-
}
|
|
1050
|
-
addEvent(el, ev, fn)
|
|
1051
|
-
addEvent(el, ev, remove)
|
|
1052
|
-
}),
|
|
1053
1100
|
render: render,
|
|
1054
1101
|
rm: elRm
|
|
1055
1102
|
})
|
|
@@ -1126,12 +1173,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1126
1173
|
return true
|
|
1127
1174
|
}
|
|
1128
1175
|
},
|
|
1129
|
-
is:
|
|
1130
|
-
if (!isStr(prefix)) prefix = "is-"
|
|
1131
|
-
var match = elScope(el)._.ext.pick(val, opts)
|
|
1132
|
-
cls(el, el[prefix + opts], 0)
|
|
1133
|
-
cls(el, el[prefix + opts] = match && prefix + match)
|
|
1134
|
-
},
|
|
1176
|
+
is: bindingsIs,
|
|
1135
1177
|
name: function(el, name) {
|
|
1136
1178
|
setAttr(el, "name", expand(name, 1))
|
|
1137
1179
|
},
|
|
@@ -1164,8 +1206,8 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1164
1206
|
rate: rate,
|
|
1165
1207
|
replace: elReplace,
|
|
1166
1208
|
scope: elScope,
|
|
1167
|
-
scrollLeft: scrollLeft,
|
|
1168
|
-
scrollTop: scrollTop,
|
|
1209
|
+
scrollLeft: bind(scrollPos, NUL, "pageXOffset", "scrollLeft"),
|
|
1210
|
+
scrollTop: bind(scrollPos, NUL, "pageYOffset", "scrollTop"),
|
|
1169
1211
|
step: step,
|
|
1170
1212
|
stop: eventStop
|
|
1171
1213
|
})
|
|
@@ -1173,12 +1215,12 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1173
1215
|
function setAttr(el, key, val) {
|
|
1174
1216
|
var current = getAttr(el, key)
|
|
1175
1217
|
|
|
1176
|
-
/*** ie8 ***/
|
|
1177
1218
|
// NOTE: IE5-7 doesn't set styles and removes events when you try to set them.
|
|
1178
1219
|
// IE6 label with a for attribute will re-select the first option of SELECT list instead of just giving focus.
|
|
1179
1220
|
// http://webbugtrack.blogspot.com/2007/09/bug-116-for-attribute-woes-in-ie6.html
|
|
1180
1221
|
// IE8 and below have a bug where changed 'name' not accepted on form submit
|
|
1181
|
-
/* c8 ignore next
|
|
1222
|
+
/* c8 ignore next 4 */
|
|
1223
|
+
/*** ie9 ***/
|
|
1182
1224
|
if (ie678 && (key === "id" || key === "name" || key === "checked" || key === "style")) {
|
|
1183
1225
|
el.mergeAttributes(document.createElement("<INPUT " + key + "='" + val + "'>"), false)
|
|
1184
1226
|
} else
|
|
@@ -1227,7 +1269,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1227
1269
|
el = before.parentNode
|
|
1228
1270
|
}
|
|
1229
1271
|
el.insertBefore(child, (
|
|
1230
|
-
isNum(before) ? el.childNodes[before < 0 ? el.childNodes.length
|
|
1272
|
+
isNum(before) ? el.childNodes[before < 0 ? el.childNodes.length + before : before] :
|
|
1231
1273
|
isArr(before) ? before[0] :
|
|
1232
1274
|
before
|
|
1233
1275
|
) || NUL)
|
|
@@ -1276,7 +1318,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1276
1318
|
name = current.split(SP).indexOf(name) > -1 ? current : current + SP + name
|
|
1277
1319
|
}
|
|
1278
1320
|
} else {
|
|
1279
|
-
name = current ? replace(SP +
|
|
1321
|
+
name = current ? replace(SP + name + SP, SP, SP + current + SP).trim() : current
|
|
1280
1322
|
}
|
|
1281
1323
|
|
|
1282
1324
|
if (current != name) {
|
|
@@ -1286,6 +1328,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1286
1328
|
el.className = name
|
|
1287
1329
|
}
|
|
1288
1330
|
}
|
|
1331
|
+
return current
|
|
1289
1332
|
}
|
|
1290
1333
|
|
|
1291
1334
|
function elEmpty(el) {
|
|
@@ -1299,7 +1342,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1299
1342
|
if (isObj(tr)) bindingsCss(el, tr)
|
|
1300
1343
|
tr = "transitionend"
|
|
1301
1344
|
// transitionend fires for each property transitioned
|
|
1302
|
-
if ("on" + tr in el) return addEvent(el, tr, bind(elKill, el, el
|
|
1345
|
+
if ("on" + tr in el) return addEvent(el, tr, bind(elKill, el, el))
|
|
1303
1346
|
}
|
|
1304
1347
|
if (el._e) {
|
|
1305
1348
|
emit(el, "kill")
|
|
@@ -1324,76 +1367,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1324
1367
|
closestScope(el)
|
|
1325
1368
|
)
|
|
1326
1369
|
}
|
|
1327
|
-
function elTxt(el, txt) {
|
|
1328
|
-
if (el[txtAttr] !== txt) el[txtAttr] = txt
|
|
1329
|
-
}
|
|
1330
|
-
function elVal(el, val) {
|
|
1331
|
-
if (!el) return ""
|
|
1332
|
-
var input, step, key, value
|
|
1333
|
-
, i = 0
|
|
1334
|
-
, type = el.type
|
|
1335
|
-
, opts = el.options
|
|
1336
|
-
, checkbox = type === "checkbox" || type === "radio"
|
|
1337
|
-
|
|
1338
|
-
if (el.tagName === "FORM") {
|
|
1339
|
-
// Disabled controls do not receive focus,
|
|
1340
|
-
// are skipped in tabbing navigation, cannot be successfully posted.
|
|
1341
|
-
//
|
|
1342
|
-
// Read-only elements receive focus but cannot be modified by the user,
|
|
1343
|
-
// are included in tabbing navigation, are successfully posted.
|
|
1344
|
-
//
|
|
1345
|
-
// Read-only checkboxes can be changed by the user
|
|
1346
|
-
|
|
1347
|
-
for (opts = {}; (input = el.elements[i++]); ) if (!input.disabled && (key = input.name || input.id)) {
|
|
1348
|
-
value = elVal(input, val != UNDEF ? val[key] : UNDEF)
|
|
1349
|
-
if (value !== UNDEF) {
|
|
1350
|
-
step = opts
|
|
1351
|
-
replace(key, /\[(.*?)\]/g, replacer)
|
|
1352
|
-
step[key || step.length] = value
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
return opts
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
if (val !== UNDEF) {
|
|
1359
|
-
if (opts) {
|
|
1360
|
-
for (value = (isArr(val) ? val : [ val ]).map(String); (input = opts[i++]); ) {
|
|
1361
|
-
input.selected = value.indexOf(input.value) > -1
|
|
1362
|
-
}
|
|
1363
|
-
} else if (el.val) {
|
|
1364
|
-
el.val(val)
|
|
1365
|
-
} else if (checkbox) {
|
|
1366
|
-
el.checked = !!val
|
|
1367
|
-
} else {
|
|
1368
|
-
el.value = val
|
|
1369
|
-
}
|
|
1370
|
-
return
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
if (opts) {
|
|
1374
|
-
if (type === "select-multiple") {
|
|
1375
|
-
for (val = []; (input = opts[i++]); ) {
|
|
1376
|
-
if (input.selected && !input.disabled) {
|
|
1377
|
-
val.push(input.valObject || input.value)
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
return val
|
|
1381
|
-
}
|
|
1382
|
-
// IE8 throws error when accessing to options[-1]
|
|
1383
|
-
value = el.selectedIndex
|
|
1384
|
-
el = value > -1 && opts[value] || el
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
return checkbox && !el.checked ?
|
|
1388
|
-
(type === "radio" ? UNDEF : NUL) :
|
|
1389
|
-
el.valObject !== UNDEF ? el.valObject : el.value
|
|
1390
|
-
|
|
1391
|
-
function replacer(_, _key, offset) {
|
|
1392
|
-
if (step == opts) key = key.slice(0, offset)
|
|
1393
|
-
step = step[key] || (step[key] = step[key] === NUL || _key && +_key != _key ? {} : [])
|
|
1394
|
-
key = _key
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
1370
|
|
|
1398
1371
|
function closestScope(node) {
|
|
1399
1372
|
for (; (node = node.parentNode); ) {
|
|
@@ -1411,7 +1384,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1411
1384
|
var el, next
|
|
1412
1385
|
, scope = node.$s || $s || closestScope(node)
|
|
1413
1386
|
|
|
1414
|
-
/***
|
|
1387
|
+
/*** ie9 ***/
|
|
1415
1388
|
if (ie678 && node.tagName === "SELECT") {
|
|
1416
1389
|
node.parentNode.insertBefore(node, node)
|
|
1417
1390
|
}
|
|
@@ -1425,34 +1398,40 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1425
1398
|
hydrate(node, "data-out", scope)
|
|
1426
1399
|
}
|
|
1427
1400
|
|
|
1401
|
+
// Reads binding expression from DOM attr (_b or data-out), compiles via makeFn, executes.
|
|
1402
|
+
// Caches expr on node[attr] to avoid re-reading DOM; true = no bindings (already processed).
|
|
1403
|
+
// Returns truthy if binding replaced the element (if/each), so render() skips children.
|
|
1428
1404
|
function hydrate(node, attr, scope) {
|
|
1429
1405
|
var fn
|
|
1430
1406
|
, expr = node[attr] || (node[attr] = setAttr(node, attr, "") || true)
|
|
1431
1407
|
if (expr !== true) try {
|
|
1432
1408
|
fn = fnCache[expr] || (fnCache[expr] = makeFn(expr))
|
|
1433
|
-
return fn(node, scope, attr, bindOnce)
|
|
1409
|
+
return fn(node, scope, attr, bindOnce, elScope)
|
|
1434
1410
|
} catch (e) {
|
|
1435
1411
|
throw e + "\n" + attr + ": " + expr
|
|
1436
1412
|
}
|
|
1437
1413
|
}
|
|
1414
|
+
// Compiles binding expression string (e.g. ";txt foo;cls 'active',bar") into a Function.
|
|
1415
|
+
// Extracts free variable names and aliases them from scope ($s.varName).
|
|
1416
|
+
// raw parameter bypasses the $s guard wrapper (used by i18n getExt).
|
|
1438
1417
|
function makeFn(fn, raw, i) {
|
|
1439
|
-
fn = raw || "$s&&(" + replace(
|
|
1418
|
+
fn = raw || "$s&&(" + replace(renderRe, function(match, name, op, args) {
|
|
1440
1419
|
return (
|
|
1441
1420
|
op ? "($el[$a]=$el[$a].replace($o[" + (i = bindOnce.indexOf(match), i < 0 ? bindOnce.push(match) - 1 : i)+ "],''),0)||" : ""
|
|
1442
|
-
) + "$b['" + (bindings[name] ? name + "'].call($s" + (name == "$s" ? "
|
|
1443
|
-
}) + "$r)"
|
|
1444
|
-
var vars = replace(
|
|
1421
|
+
) + "$b['" + (bindings[name] ? name + "'].call($s" + (name == "$s" ? "=$S($el,$el)": "") + ",$el" : "set']($el,'" + name + "'") + (args ? "," + args : "") + ")||"
|
|
1422
|
+
}, fn) + "$r)"
|
|
1423
|
+
var vars = replace(fnRe, "", fn).match(wordRe) || []
|
|
1445
1424
|
for (i = vars.length; i--; ) {
|
|
1446
|
-
if (vars.indexOf(vars[i]) !== i) vars.splice(i, 1)
|
|
1425
|
+
if (window[vars[i]] || vars.indexOf(vars[i]) !== i) vars.splice(i, 1)
|
|
1447
1426
|
else vars[i] += "=$s." + vars[i]
|
|
1448
1427
|
}
|
|
1449
|
-
fn = Function("$el,$s,$a,$o,$r", (vars[0] ? "var " + vars : "") + ";return " + fn)
|
|
1428
|
+
fn = Function("$el,$s,$a,$o,$S,$r", (vars[0] ? "var " + vars : "") + ";return " + fn)
|
|
1450
1429
|
return fn
|
|
1451
1430
|
}
|
|
1452
1431
|
|
|
1453
1432
|
/*** kb ***/
|
|
1454
1433
|
var kbMaps = []
|
|
1455
|
-
, kbMod = LiteJS.kbMod =
|
|
1434
|
+
, kbMod = LiteJS.kbMod = /\bMac|\biP/.test(navigator.userAgent) ? "metaKey" : "ctrlKey"
|
|
1456
1435
|
, kbCodes = LiteJS.kbCodes = ",,,,,,,,backspace,tab,,,,enter,,,shift,ctrl,alt,pause,caps,,,,,,,esc,,,,,,pgup,pgdown,end,home,left,up,right,down,,,,,ins,del,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,cmd,,,,,,,,,,,,,,,,,,,,,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12".split(splitRe)
|
|
1457
1436
|
|
|
1458
1437
|
El.addKb = addKb
|
|
@@ -1636,6 +1615,19 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1636
1615
|
}
|
|
1637
1616
|
/**/
|
|
1638
1617
|
|
|
1618
|
+
function bindingsIs(el, val, opts, prefix) {
|
|
1619
|
+
if (!isStr(prefix)) prefix = "is-"
|
|
1620
|
+
var match = pick(val, opts)
|
|
1621
|
+
cls(el, el[prefix + opts], 0)
|
|
1622
|
+
cls(el, el[prefix + opts] = match && prefix + match)
|
|
1623
|
+
}
|
|
1624
|
+
function pick(val, word) {
|
|
1625
|
+
for (var arr = replace(/([^;=,]+?)\?/g, "$1=$1;", word).split(/[;=,]/), i = 1|arr.length; i > 0; ) {
|
|
1626
|
+
if ((i-=2) < 0 || arr[i] && (arr[i] == "" + val || +arr[i] <= val)) {
|
|
1627
|
+
return arr[i + 1] ? replace("#", val, arr[i + 1]) : ""
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1639
1631
|
function closest(el, sel) {
|
|
1640
1632
|
return el && html.closest.call(el.nodeType < 2 ? el : el.parentNode, sel)
|
|
1641
1633
|
}
|
|
@@ -1651,6 +1643,9 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1651
1643
|
function nearest(el, sel) {
|
|
1652
1644
|
return el ? find(el, sel) || nearest(el.parentNode, sel) : NUL
|
|
1653
1645
|
}
|
|
1646
|
+
// Wraps fn to accept: space-separated names, object maps {name:val}, CSS selectors, delays.
|
|
1647
|
+
// prepareVal=1: wraps val as event delegate (string val→emit on view, fn+selector→delegation)
|
|
1648
|
+
// After arg normalization, selector is reused as element array, delay as loop counter.
|
|
1654
1649
|
function acceptMany(fn, prepareVal) {
|
|
1655
1650
|
return function f(el, name, val, selector, delay, data) {
|
|
1656
1651
|
if (el && name) {
|
|
@@ -1672,15 +1667,28 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1672
1667
|
}
|
|
1673
1668
|
return
|
|
1674
1669
|
}
|
|
1675
|
-
if (prepareVal) val =
|
|
1670
|
+
if (prepareVal) val = delegate(el, val, selector, data)
|
|
1676
1671
|
selector = !prepareVal && selector ? findAll(el, selector) : isArr(el) ? el : [ el ]
|
|
1677
1672
|
for (delay = 0; (el = selector[delay++]); ) {
|
|
1678
|
-
for (var arr = ("" + name).split(splitRe), i = 0, len = arr.length; i < len; ) {
|
|
1679
|
-
if (arr[i])
|
|
1673
|
+
for (var result, arr = ("" + name).split(splitRe), i = 0, len = arr.length; i < len; i++) {
|
|
1674
|
+
if (arr[i]) {
|
|
1675
|
+
result = fn(el, arr[i], isArr(val) ? val[i] : val, data)
|
|
1676
|
+
if (!prepareVal && data > 0) f(el, name, result, "", data)
|
|
1677
|
+
}
|
|
1680
1678
|
}
|
|
1681
1679
|
}
|
|
1682
1680
|
}
|
|
1683
1681
|
}
|
|
1682
|
+
function delegate(el, val, selector, data) {
|
|
1683
|
+
return isStr(val) ? function(e) {
|
|
1684
|
+
var target = selector ? closest(e.target, selector) : el
|
|
1685
|
+
if (target) emit.apply(target, [elScope(el).$ui, val, e, target].concat(data))
|
|
1686
|
+
} :
|
|
1687
|
+
selector ? function(e, touchEv, touchEl) {
|
|
1688
|
+
if (matches(touchEl = e.target, selector)) val(e, touchEv, touchEl, data)
|
|
1689
|
+
} :
|
|
1690
|
+
val
|
|
1691
|
+
}
|
|
1684
1692
|
}
|
|
1685
1693
|
function assignDeep(target, map) {
|
|
1686
1694
|
if (map) for (var k in map) if (hasOwn(map, k)) {
|
|
@@ -1695,9 +1703,6 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1695
1703
|
document.activeElement.blur()
|
|
1696
1704
|
} catch(e) {}
|
|
1697
1705
|
}
|
|
1698
|
-
function camelFn(_, a) {
|
|
1699
|
-
return a.toUpperCase()
|
|
1700
|
-
}
|
|
1701
1706
|
function each(arr, fn, scope, key) {
|
|
1702
1707
|
if (arr) {
|
|
1703
1708
|
if (isStr(arr)) arr = arr.split(splitRe)
|
|
@@ -1738,7 +1743,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1738
1743
|
return typeof str === "string"
|
|
1739
1744
|
}
|
|
1740
1745
|
function quote(str) {
|
|
1741
|
-
return "'" + replace(
|
|
1746
|
+
return "'" + replace(/\n/g, "\\n", replace(/'/g, "\\'", str || "")) + "'"
|
|
1742
1747
|
}
|
|
1743
1748
|
// Maximum call rate for Function with optional leading edge and trailing edge
|
|
1744
1749
|
function rate(fn, ms, onStart, onEnd) {
|
|
@@ -1760,11 +1765,8 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1760
1765
|
}
|
|
1761
1766
|
}
|
|
1762
1767
|
}
|
|
1763
|
-
function
|
|
1764
|
-
return window
|
|
1765
|
-
}
|
|
1766
|
-
function scrollTop() {
|
|
1767
|
-
return window.pageYOffset || html.scrollTop || body.scrollTop || 0
|
|
1768
|
+
function scrollPos(page, key) {
|
|
1769
|
+
return window[page] || html[key] || body[key] || 0
|
|
1768
1770
|
}
|
|
1769
1771
|
function step(num, factor, mid) {
|
|
1770
1772
|
var x = ("" + factor).split(".")
|
|
@@ -1780,7 +1782,7 @@ console.log("LiteJS is in debug mode, but it's fine for production")
|
|
|
1780
1782
|
elKill(el)
|
|
1781
1783
|
return el.src
|
|
1782
1784
|
}), function(res) {
|
|
1783
|
-
res = res.concat(sources, next && next.src && next.innerHTML)
|
|
1785
|
+
res = res.concat(sources, next && next.src && next.innerHTML)
|
|
1784
1786
|
if (res[sources.length = 0]) {
|
|
1785
1787
|
if (!parser) LiteJS.ui = LiteJS()
|
|
1786
1788
|
each(res, parser)
|