UNPKG

61.1 kBJavaScriptView Raw
1/*
2* @version 19.1.1
3* @author Lauri Rooden <lauri@rooden.ee>
4* @license MIT License
5*/
6
7
8
9!function(Date, proto) {
10 var Date$prototype = Date[proto]
11 , String$prototype = String[proto]
12 , Number$prototype = Number[proto]
13 , maskRe = /(\[)((?:\\?.)*?)\]|([YMD])\3\3\3?|([YMDHhmsWSZ])(\4?)|[uUASwoQ]|(["\\\n\r\u2028\u2029])/g
14 , dateRe = /(\d+)[-.\/](\d+)[-.\/](\d+)/
15 , timeRe = /(\d+):(\d+)(?::(\d+))?(\.\d+)?(?:\s*(?:(a)|(p))\.?m\.?)?(\s*(?:Z|GMT|UTC)?(?:([-+]\d\d):?(\d\d)?)?)?/i
16 , fns = Object.create(null)
17 , aliases = {
18 sec: "s",
19 second: "s",
20 seconds: "s",
21 min: "m",
22 minute: "m",
23 minutes: "m",
24 hr: "h",
25 hour: "h",
26 hours: "h",
27 day: "D",
28 days: "D",
29 week: "W",
30 weeks: "W",
31 month: "M",
32 months: "M",
33 year: "Y",
34 years: "Y"
35 }
36 , units = {
37 S: 1,
38 s: 1000,
39 m: 60000,
40 h: 3600000,
41 D: 86400000,
42 W: 604800000
43 }
44 , tmp1 = new Date()
45 , tmp2 = new Date()
46 , map = Date.fnMap = {
47 w: "Day()||7",
48 Y: "FullYear()%100",
49 M: "Month()+1",
50 D: "Date()",
51 h: "Hours()",
52 H: "Hours()%12||12",
53 m: "Minutes()",
54 s: "Seconds()",
55 S: "Milliseconds()"
56 }
57 , locales = Date.locales = {
58 en: {
59 am: "AM",
60 pm: "PM",
61 names: "JanFebMarAprMayJunJulAugSepOctNovDecJanuaryFebruaryMarchAprilMayJuneJulyAugustSeptemberOctoberNovemberDecemberSunMonTueWedThuFriSatSundayMondayTuesdayWednesdayThursdayFridaySaturday".match(/.[a-z]+/g),
62 masks: {
63 LT: "hh:mm",
64 LTS: "hh:mm:ss",
65 L: "DD/MM/YYYY",
66 LL: "D MMMM YYYY",
67 LLL: "D MMMM YYYY hh:mm",
68 LLLL: "DDDD, D MMMM YYYY hh:mm"
69 }
70 }
71 }
72 , masks = Date.masks = {
73 "iso": "UTC:YYYY-MM-DD[T]hh:mm:ss[Z]"
74 }
75
76
77 Date.makeStr = makeStr
78 function makeStr(mask, utc) {
79 var get = "d.get" + (utc ? "UTC" : "")
80 , setA = "a.setTime(+d+((4-(" + get + map.w + "))*864e5))"
81 return (utc ? mask.slice(4) : mask).replace(maskRe, function(match, quote, text, MD, single, pad, esc) {
82 var str = (
83 esc ? escape(esc).replace(/%u/g, "\\u").replace(/%/g, "\\x") :
84 quote ? text :
85 MD == "Y" ? get + "FullYear()" :
86 MD ? "l.names[" + get + (MD == "M" ? "Month" : "Day" ) + "()+" + (match == "DDD" ? 24 : MD == "D" ? 31 : match == "MMM" ? 0 : 12) + "]" :
87 match == "u" ? "(d/1000)>>>0" :
88 match == "U" ? "+d" :
89 match == "Q" ? "((" + get + "Month()/3)|0)+1" :
90 match == "A" ? "l[" + get + map.h + ">11?'pm':'am']" :
91 match == "o" ? setA + ",a" + get.slice(1) + "FullYear()" :
92 single == "Z" ? "(t=o)?(t<0?((t=-t),'-'):'+')+(t<600?'0':'')+(0|(t/60))" + (pad ? "" : "+':'") + "+((t%=60)>9?t:'0'+t):'Z'" :
93 single == "W" ? "Math.ceil(((" + setA + "-a.s" + get.slice(3) + "Month(0,1))/864e5+1)/7)" :
94 get + map[single || match]
95 )
96 return quote || esc ? str : '"+(' + (
97 match == "SS" ? "(t=" + str + ")>9?t>99?t:'0'+t:'00'+t" :
98 pad && single != "Z" ? "(t=" + str + ")>9?t:'0'+t" :
99 str
100 ) + ')+"'
101 })
102 }
103
104 Date$prototype.date = function(_mask, _zone) {
105 var offset, undef
106 , date = this
107 , locale = locales[date._locale || Date._locale || "en"] || locales.en
108 , mask = locale.masks && locale.masks[_mask] || masks[_mask] || _mask || masks.iso
109 , zone = _zone == undef ? date._tz || Date._tz : _zone
110 , utc = mask.slice(0, 4) == "UTC:"
111 if (zone != undef && !utc) {
112 offset = 60 * zone
113 tmp1.setTime(+date + offset * 6e4)
114 utc = mask = "UTC:" + mask
115 } else {
116 offset = utc ? 0 : -date.getTimezoneOffset()
117 tmp1.setTime(+date)
118 }
119 return isNaN(+date) ? "" + date : (
120 fns[mask] || (fns[mask] = Function("d,a,o,l", 'var t;return "' + makeStr(mask, utc) + '"')))(
121 tmp1,
122 tmp2,
123 offset,
124 locale
125 )
126 }
127
128 addFn("add", function(amount, _unit, mask) {
129 var date = this
130 , unit = aliases[_unit] || _unit
131 if (unit == "M" || unit == "Y" && (amount *= 12)) {
132 unit = date.getUTCDate()
133 date.setUTCMonth(date.getUTCMonth() + amount)
134 if (unit > (unit = date.getUTCDate())) {
135 date.add(-unit, "D")
136 }
137 } else if (amount) {
138 date.setTime(date.getTime() + (amount * (units[unit] || 1)))
139 }
140 return mask ? date.date(mask) : date
141 })
142
143 addFn("startOf", function(_unit, mask) {
144 var date = this
145 , unit = aliases[_unit] || _unit
146 if (unit == "Y") {
147 date.setUTCMonth(0, 1)
148 unit = "D"
149 } else if (unit == "M") {
150 date.setUTCDate(1)
151 unit = "D"
152 }
153 date.setTime(date - (date % (units[unit] || 1)))
154 return mask ? date.date(mask) : date
155 })
156
157 addFn("endOf", function(unit, mask) {
158 return this.startOf(unit).add(1, unit).add(-1, "S", mask)
159 })
160
161 addFn("since", function(from, _unit) {
162 var diff
163 , date = this
164 , unit = aliases[_unit] || _unit
165 if (typeof from == "string") {
166 from = aliases[from] ? (tmp2.setTime(+date), tmp2.startOf(from)) : from.date()
167 }
168 if (units[unit]) {
169 diff = (date - from) / units[unit]
170 } else {
171 diff = date.since("month", "S") - from.since("month", "S")
172 if (diff) {
173 tmp1.setTime(+date)
174 diff /= units.D * tmp1.endOf("M").getUTCDate()
175 }
176 diff += 12 * (date.getUTCFullYear() - from.getUTCFullYear()) + date.getUTCMonth() - from.getUTCMonth()
177 if (unit == "Y") {
178 diff /= 12
179 }
180 }
181
182 return diff
183 })
184
185 //*/
186
187
188 /*
189 * // In Chrome Date.parse("01.02.2001") is Jan
190 * num = +date || Date.parse(date) || ""+date;
191 */
192
193 String$prototype.date = function(mask, zoneOut, zoneIn) {
194 var undef, date, match, year, month
195 , str = this
196 if (isNaN(+str)) {
197 if (match = str.match(dateRe)) {
198 // Big endian date, starting with the year, eg. 2011-01-31
199 // Middle endian date, starting with the month, eg. 01/31/2011
200 // Little endian date, starting with the day, eg. 31.01.2011
201 year = match[1] > 99 ? 1 : 3
202 month = Date.middleEndian ? 4 - year : 2
203 date = new Date(match[year], match[month] - 1, match[6 - month - year])
204 } else {
205 date = new Date()
206 }
207
208 // Time
209 match = str.match(timeRe) || [0, 0, 0]
210 date.setHours(
211 match[6] && match[1] < 12 ? +match[1] + 12 :
212 match[5] && match[1] == 12 ? 0 : match[1],
213 match[2], match[3]|0, (1000 * match[4])|0
214 )
215
216 // Timezone
217 if (match[7]) {
218 zoneIn = (match[8]|0) + ((match[9]|0)/(match[8]<0?-60:60))
219 }
220
221 if (zoneIn != undef) {
222 date.setTime(date - (60 * zoneIn + date.getTimezoneOffset()) * 60000)
223 }
224 return mask ? date.date(mask, zoneOut) : date
225 }
226 return (+str).date(mask, zoneOut, zoneIn)
227 }
228
229 Number$prototype.date = function(mask, zoneOut, zoneIn) {
230 var date
231 , num = this
232 if (num < 4294967296) num *= 1000
233 date = new Date(
234 zoneIn != date ?
235 tmp1.setTime(num) - (60 * zoneIn + tmp1.getTimezoneOffset()) * 60000 :
236 num
237 )
238
239 return mask ? date.date(mask, zoneOut) : date
240 }
241
242 function addFn(method, fn) {
243 Date$prototype[method] = fn
244 String$prototype[method] = Number$prototype[method] = function(a, b, c) {
245 return this.date()[method](a, b, c)
246 }
247 }
248
249 function makeSetter(method) {
250 Date[method] = Date$prototype[method] = function(value, mask) {
251 var date = this
252 date["_" + method] = value
253 return mask ? date.date(mask) : date
254 }
255 }
256
257 makeSetter("tz")
258 makeSetter("locale")
259}(Date, "prototype")
260!function(exports) {
261 var pointerCache = {}
262 , hasOwn = pointerCache.hasOwnProperty
263
264 exports.clone = clone
265 exports.merge = merge
266 exports.mergePatch = mergePatch
267 exports.isObject = isObject
268
269 /**
270 * JSON Merge Patch
271 * @see https://tools.ietf.org/html/rfc7396
272 */
273
274 function mergePatch(target, patch, changed, previous, pointer) {
275 var undef, key, oldVal, val, len, nextPointer
276 if (isObject(patch)) {
277 if (!pointer) {
278 pointer = ""
279 }
280 if (!isObject(target)) {
281 target = {}
282 }
283 for (key in patch) if (
284 undef !== (oldVal = target[key], val = patch[key]) &&
285 hasOwn.call(patch, key) &&
286 (
287 undef == val ?
288 undef !== oldVal && delete target[key] :
289 target[key] !== val
290 )
291 ) {
292 nextPointer = pointer + "/" + key.replace(/~/g, "~0").replace(/\//g, "~1")
293 len = changed && isObject(target[key]) && changed.length
294 if (undef != val) {
295 target[key] = mergePatch(target[key], val, changed, previous, nextPointer)
296 }
297 if (len === false || changed && len != changed.length) {
298 changed.push(nextPointer)
299 if (previous && !isObject(oldVal)) {
300 previous[nextPointer] = oldVal
301 }
302 }
303 }
304 } else {
305 if (changed && isObject(target)) {
306 val = {}
307 for (key in target) if (hasOwn.call(target, key)) {
308 val[key] = null
309 }
310 mergePatch(target, val, changed, previous, pointer)
311 }
312 target = patch
313 }
314 return target
315 }
316
317 function merge(target) {
318 for (var key, source, a = arguments, i = 1, len = a.length; i < len; ) {
319 if (source = a[i++]) for (key in source) if (hasOwn.call(source, key)) {
320 target[key] = source[key]
321 }
322 }
323 return target
324 }
325
326 function clone(obj) {
327 var temp, key
328 if (obj && typeof obj == "object") {
329 // new Date().constructor() returns a string
330 temp = obj instanceof Date ? new Date(+obj) :
331 obj instanceof RegExp ? RegExp(obj.source, (""+obj).split("/").pop()) :
332 obj.constructor()
333 for (key in obj) if (hasOwn.call(obj, key)) {
334 temp[key] = clone(obj[key])
335 }
336 obj = temp
337 }
338 return obj
339 }
340
341 function isObject(obj) {
342 return !!obj && obj.constructor === Object
343 }
344
345// `this` refers to the `window` in browser and to the `exports` in Node.js.
346}(this.JSON || this)
347!function(F) {
348 // Time to live - Run *onTimeout* if Function not called on time
349 F.ttl = function(ms, onTimeout, scope) {
350 var fn = this
351 , tick = setTimeout(function() {
352 ms = 0
353 if (onTimeout) onTimeout()
354 }, ms)
355
356 return function() {
357 clearTimeout(tick)
358 if (ms) fn.apply(scope, arguments)
359 }
360 }
361
362 // Run Function one time after last call
363 F.once = function(ms, scope) {
364 var tick, args
365 , fn = this
366 return function() {
367 clearTimeout(tick)
368 args = arguments
369 tick = setTimeout(function() {
370 fn.apply(scope, args)
371 }, ms)
372 }
373 }
374
375 // Maximum call rate for Function
376 // leading edge, trailing edge
377 F.rate = function(ms, last_call, _scope) {
378 var tick, args
379 , fn = this
380 , scope = _scope
381 , next = 0
382 return function() {
383 var now = Date.now()
384 clearTimeout(tick)
385 if (_scope === void 0) scope = this
386 if (now >= next) {
387 next = now + ms
388 fn.apply(scope, arguments)
389 } else if (last_call) {
390 args = arguments
391 tick = setTimeout(function() {
392 fn.apply(scope, args)
393 }, next - now)
394 }
395 }
396 }
397}(Function.prototype)
398!function(exports, Object) {
399 var undef
400 , P = "prototype"
401 , A = Array[P]
402 , F = Function[P]
403 , S = String[P]
404 , N = Number[P]
405 , slice = F.call.bind(A.slice)
406 , fns = {}
407 , hasOwn = fns.hasOwnProperty
408 , fnRe = /('|")(?:\\?.)*?\1|\/(?:\\?.)+?\/[gim]*|\b(?:false|in|new|null|this|true|typeof|void)\b|\.\w+|\w+:/g
409 , formatRe = /{(?!\\)((?:("|')(?:\\?.)*?\2|[^}])*?)}/g
410 , numbersRe = /-?\d+\.?\d*/g
411 , wordRe = /\b[a-z_$][\w$]*/ig
412 , unescapeRe = /{\\/g
413
414
415 exports.Fn = Fn
416 Fn.hold = hold
417 Fn.wait = wait
418
419
420 // Function extensions
421 // -------------------
422
423 F.extend = function() {
424 var arg
425 , fn = this
426 , i = 0
427
428 function wrapper() {
429 return fn.apply(this, arguments)
430 }
431
432 for (wrapper[P] = Object.create(fn[P]); arg = arguments[i++]; ) {
433 JSON.merge(wrapper[P], arg)
434 }
435 wrapper[P].constructor = wrapper
436 return wrapper
437 }
438
439
440 // Non-standard
441 Object.each = function(obj, fn, scope, key) {
442 if (obj) for (key in obj) {
443 hasOwn.call(obj, key) && fn.call(scope, obj[key], key, obj)
444 }
445 }
446
447 Object.values = function(obj) {
448 return Object.keys(obj || {}).map(function(e) {
449 return obj[e]
450 })
451 }
452
453 // Non-standard
454 // IE<9 bug: [1,2].splice(0).join("") == "" but should be "12"
455 A.remove = arrayRemove
456 function arrayRemove() {
457 var arr = this
458 , len = arr.length
459 , o = slice(arguments)
460 , lastId = -1
461
462 for (; len--; ) if (~o.indexOf(arr[len])) {
463 arr.splice(lastId = len, 1)
464 }
465 return lastId
466 }
467
468 A.each = A.forEach
469 // uniq
470 // first item preserved
471 A.uniq = function() {
472 for (var a = this, i = a.length; i--; ) {
473 if (a.indexOf(a[i]) !== i) a.splice(i, 1)
474 }
475 return a
476 }
477
478 A.pushUniq = function(item) {
479 return this.indexOf(item) < 0 && this.push(item)
480 }
481
482 // THANKS: Oliver Steele - Functional Javascript [http://www.osteele.com/sources/javascript/functional/]
483 function Fn(expr /*, scope, mask1, ..maskN */) {
484 var args = []
485 , arr = expr.match(/[^"']+?->|.+$/g)
486 , scope = slice(arguments, 1)
487 , key = scope.length + ":" + expr
488 , fn = fns[key]
489
490 if (!fn) {
491 fn = expr.replace(fnRe, "").match(wordRe) || []
492 for (; arr.length > 1; ) {
493 expr = arr.pop()
494 args = arr.pop().match(/\w+/g) || []
495 arrayRemove.apply(fn, args)
496 if (arr.length) {
497 arr.push("function(" + args + "){return(" + expr + ")}" + (scope[0] ? ".bind(this)" : ""))
498 }
499 }
500 expr = "return(" + expr + ")"
501
502 if (scope[0]) {
503 arr = Object.keys(scope).map(Fn("a->'__'+a"))
504 arr[0] = "this"
505 expr = (
506 fn[0] ?
507 "var " + fn.uniq().join("='',") + "='';" :
508 ""
509 ) + "with(" + arr.join(")with(") + "){" + expr + "}"
510 args = arr.slice(1).concat(args)
511 }
512
513 fn = fns[key] = Function(args, expr)
514 }
515
516 return scope.length ? fn.bind.apply(fn, scope) : fn
517 }
518
519 Fn.keys = function(str) {
520 var i, tmp
521 , arr = []
522 , match = str.match(formatRe)
523 if (match) {
524 for (i = match.length; i--; ) {
525 if (tmp = match[i].replace(fnRe, "").match(wordRe)) {
526 arr.push.apply(arr, tmp)
527 }
528 }
529 }
530 return arr.uniq()
531 }
532
533 S.format = function() {
534 var args = A.slice.call(arguments)
535 args.unshift(0)
536 return this.replace(formatRe, function(_, arg) {
537 args[0] = arg
538 return Fn.apply(null, args)()
539 }).replace(unescapeRe, "{")
540 }
541
542 N.format = function(data) {
543 return "" + this
544 }
545
546 S.safe = function() {
547 return this
548 .replace(/&/g, "&amp;")
549 .replace(/</g, "&lt;")
550 .replace(/>/g, "&gt;")
551 .replace(/\"/g, "&quot;")
552 }
553
554 S.capitalize = function() {
555 return this.charAt(0).toUpperCase() + this.slice(1)
556 }
557
558 S.camelCase = function() {
559 return this.replace(/[ _-]+([a-z])/g, function(_, a) {
560 return a.toUpperCase()
561 })
562 }
563
564 S.lower = S.toLowerCase
565 S.upper = S.toUpperCase
566
567 N.step = function(a, add) {
568 var x = ("" + a).split(".")
569 , steps = this / a
570 , n = ~~(steps + ((steps < 0 ? -1 : 1) * (add == undef ? .5 : add === 1 && steps == (steps|0) ? 0 : +add))) * a
571 return "" + (1 in x ? n.toFixed(x[1].length) : n)
572 }
573
574 S.step = function(a, add) {
575 return this.replace(numbersRe, function(num) {
576 return (+num).step(a, add)
577 })
578 }
579
580 N.scale = words([1000, 1000, 1000], ["","k","M","G"], {"default": "{n}{u}"})
581
582 S.scale = function() {
583 return this.replace(numbersRe, function(num) {
584 return (+num).scale()
585 })
586 }
587
588 S.pick = N.pick = function() {
589 var val = this + "="
590 for (var s, a = arguments, i = 0, len = a.length; i < len;) {
591 s = a[i++]
592 if (s.indexOf(val) == 0) {
593 s = s.slice(val.length)
594 i = len
595 }
596 }
597 return s.replace("#", this)
598 }
599
600 S.plural = N.plural = function() {
601 // Plural-Forms: nplurals=2; plural=n != 1;
602 // http://www.gnu.org/software/gettext/manual/html_mono/gettext.html#Plural-forms
603 return arguments[ +Fn("n->" + (String.plural || "n!=1"))( parseFloat(this) ) ].replace("#", this)
604 }
605
606 A.pluck = function(name) {
607 for (var arr = this, i = arr.length, out = []; i--; ) {
608 out[i] = arr[i][name]
609 }
610 return out
611 }
612
613 function words(steps, units, strings, overflow) {
614 return function(input) {
615 var n = +(arguments.length ? input : this)
616 , i = 0
617 , s = strings || {"default": "{n} {u}{s}"}
618
619 for (; n>=steps[i]; ) {
620 n /= steps[i++]
621 }
622 if (i == steps.length && overflow) {
623 return overflow(this)
624 }
625 i = units[i]
626 return (s[n < 2 ? i : i + "s"] || s["default"]).format({n: n, u: i, s: n < 2 ? "" : "s"})
627 }
628 }
629 Fn.words = words
630
631 function wait(fn) {
632 var pending = 1
633 function resume() {
634 if (!--pending && fn) fn.call(this)
635 }
636 resume.wait = function() {
637 pending++
638 return resume
639 }
640 return resume
641 }
642
643 function hold(ignore) {
644 var k
645 , obj = this
646 , hooks = []
647 , hooked = []
648 , _resume = wait(resume)
649 ignore = ignore || obj.syncMethods || []
650
651 for (k in obj) if (typeof obj[k] == "function" && ignore.indexOf(k) == -1) !function(k) {
652 hooked.push(k, hasOwn.call(obj, k) && obj[k])
653 obj[k] = function() {
654 hooks.push(k, arguments)
655 return obj
656 }
657 }(k)
658
659 /**
660 * `wait` is already in hooked array,
661 * so override hooked method
662 * that will be cleared on resume.
663 */
664 obj.wait = _resume.wait
665
666 return _resume
667
668 function resume() {
669 for (var v, scope = obj, i = hooked.length; i--; i--) {
670 if (hooked[i]) obj[hooked[i-1]] = hooked[i]
671 else delete obj[hooked[i-1]]
672 }
673 // i == -1 from previous loop
674 for (; v = hooks[++i]; ) {
675 scope = scope[v].apply(scope, hooks[++i]) || scope
676 }
677 hooks = hooked = null
678 }
679 }
680
681}(this, Object)
682!function(exports) {
683 var empty = []
684
685 exports.Emitter = EventEmitter
686 exports.asEmitter = asEmitter
687
688 function EventEmitter() {}
689
690 function asEmitter(obj) {
691 obj.on = on
692 obj.off = off
693 obj.one = one
694 obj.emit = emit
695 obj.listen = listen
696 obj.unlisten = unlisten
697 }
698 asEmitter(EventEmitter.prototype)
699
700 function on(type, fn, scope, _origin) {
701 var emitter = this === exports ? empty : this
702 , events = emitter._e || (emitter._e = Object.create(null))
703 if (type && fn) {
704 emit.call(emitter, "newListener", type, fn, scope, _origin)
705 ;(events[type] || (events[type] = [])).unshift(scope, _origin, fn)
706 }
707 return emitter
708 }
709
710 function off(type, fn, scope) {
711 var i, args
712 , emitter = this === exports ? empty : this
713 , events = emitter._e && emitter._e[type]
714 if (events) {
715 for (i = events.length - 2; i > 0; i -= 3) {
716 if ((events[i + 1] === fn || events[i] === fn) && events[i - 1] == scope) {
717 args = events.splice(i - 1, 3)
718 emit.call(emitter, "removeListener", type, args[2], args[0], args[1])
719 if (fn) break
720 }
721 }
722 }
723 return emitter
724 }
725
726 function one(type, fn, scope) {
727 var emitter = this === exports ? empty : this
728 function remove() {
729 emitter.off(type, fn, scope).off(type, remove, scope)
730 }
731 return emitter.on(type, remove, scope).on(type, fn, scope)
732 }
733
734 // emitNext
735 // emitLate
736
737 function emit(type) {
738 var args, i
739 , emitter = this === exports ? empty : this
740 , _e = emitter._e
741 , arr = _e ? (_e[type] || empty).concat(_e["*"] || empty) : empty
742 _e = 0
743 if (i = arr.length) {
744 for (args = arr.slice.call(arguments, 1); i--; ) {
745 arr[i--].apply(arr[--i] || emitter, args)
746 _e++
747 }
748 }
749 return _e
750 }
751
752 function listen(emitter, ev, fn, scope, _origin) {
753 if (emitter) {
754 emitter.on(ev, fn, scope)
755 ;(this._l || (this._l = [])).push([emitter, ev, fn, scope, _origin])
756 }
757 return this
758 }
759
760 function unlisten(key) {
761 var a, i
762 , listening = this._l
763 if (listening) for (i = listening.length; i--; ) {
764 a = listening[i]
765 if (key === "*" || a.indexOf(key) > -1) {
766 listening.splice(i, 1)
767 a[0].off(a[1], a[2], a[3])
768 }
769 }
770 return this
771 }
772
773// `this` refers to the `window` in browser and to the `exports` in Node.js.
774}(this.Event || this)
775/* litejs.com/MIT-LICENSE.txt */
776
777
778
779!function(window, document, history, location) {
780 var cb, base, lastRoute, iframe, tick, last
781 , cleanRe = /^[#\/\!]+|[\s\/]+$/g
782
783 // The JScript engine used in IE doesn't recognize vertical tabulation character
784 // http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
785 // oldIE = "\v" == "v"
786 //
787 // The documentMode is an IE only property, supported in IE8+.
788 //
789 // Starting in Internet Explorer 9 standards mode, Internet Explorer 10 standards mode,
790 // and win8_appname_long apps, you cannot identify the browser as Internet Explorer
791 // by testing for the equivalence of the vertical tab (\v) and the "v".
792 // In earlier versions, the expression "\v" === "v" returns true.
793 // In Internet Explorer 9 standards mode, Internet Explorer 10 standards mode,
794 // and win8_appname_long apps, the expression returns false.
795 , ie6_7 = !+"\v1" && (document.documentMode | 0) < 8
796
797 function getUrl(_loc) {
798 var url
799 //** PUSH
800 if (base) {
801 url = location.pathname.slice(base.length)
802 } else {
803 //*/
804 // bug in Firefox where location.hash is decoded
805 // bug in Safari where location.pathname is decoded
806
807 // var hash = location.href.split('#')[1] || '';
808 // https://bugs.webkit.org/show_bug.cgi?id=30225
809 // https://github.com/documentcloud/backbone/pull/967
810 url = (_loc || location).href.split("#")[1] || ""
811 //** PUSH
812 }
813 //*/
814 return url.replace(cleanRe, "")
815 }
816
817 function setUrl(url, replace) {
818 //** PUSH
819 if (base) {
820 history[replace ? "replaceState" : "pushState"](null, null, base + url)
821 } else {
822 //*/
823 location[replace ? "replace" : "assign"]("#" + url)
824 // Opening and closing the iframe tricks IE7 and earlier
825 // to push a history entry on hash-tag change.
826 if (iframe && getUrl() !== getUrl(iframe.location) ) {
827 iframe.location[replace ? "replace" : iframe.document.open().close(), "assign"]("#" + url)
828 }
829 //** PUSH
830 }
831 //*/
832 checkUrl()
833 }
834
835 function checkUrl() {
836 if (lastRoute != (lastRoute = getUrl()) && cb) {
837 cb(lastRoute)
838 }
839 }
840
841 history.getUrl = getUrl
842 history.setUrl = setUrl
843
844 history.start = function(_cb, _base, url) {
845 cb = _cb
846 //** PUSH
847 // Chrome5, Firefox4, IE10, Safari5, Opera11.50
848 if (_base && !history.pushState) {
849 url = location.pathname.slice(_base.length)
850 if (url) {
851 location.replace(_base + "#" + url)
852 }
853 }
854 if (_base && history.pushState) {
855 base = _base
856
857 url = location.href.split("#")[1]
858 if (url && !getUrl()) {
859 setUrl(url, 1)
860 }
861
862 // Chrome and Safari emit a popstate event on page load, Firefox doesn't.
863 // Firing popstate after onload is as designed.
864 //
865 // See the discussion on https://bugs.webkit.org/show_bug.cgi?id=41372,
866 // https://code.google.com/p/chromium/issues/detail?id=63040
867 // and the change to the HTML5 spec that was made:
868 // http://html5.org/tools/web-apps-tracker?from=5345&to=5346.
869 window.onpopstate = checkUrl
870 } else
871 //*/
872 if ("onhashchange" in window && !ie6_7) {
873 // There are onhashchange in IE7 but its not get emitted
874 //
875 // Basic support:
876 // Chrome 5.0, Firefox 3.6, IE 8, Opera 10.6, Safari 5.0
877 window.onhashchange = checkUrl
878 } else {
879 if (ie6_7 && !iframe) {
880 // IE<9 encounters the Mixed Content warning when the URI javascript: is used.
881 // IE5/6 additionally encounters the Mixed Content warning when the URI about:blank is used.
882 // src="//:"
883 iframe = document.body.appendChild(document.createElement('<iframe class="hide" tabindex="-1">')).contentWindow
884 }
885 clearInterval(tick)
886 tick = setInterval(function(){
887 var cur = getUrl()
888 if (iframe && last === cur) cur = getUrl(iframe.location)
889 if (last !== cur) {
890 last = cur
891 iframe ? setUrl(cur) : checkUrl()
892 }
893 }, 60)
894 }
895 checkUrl()
896 }
897}(this, document, history, location)
898/* litejs.com/MIT-LICENSE.txt */
899
900
901
902!function(window) {
903 var fn, lastView, lastParams, lastStr, lastUrl, syncResume
904 , fnStr = ""
905 , reStr = ""
906 , views = View.views = {}
907 , groupsCount = 1
908 , escapeRe = /[.*+?^=!:${}()|\[\]\/\\]/g
909 , parseRe = /\{([\w%.]+?)\}|.[^{\\]*?/g
910
911 window.View = View
912
913 function View(route, el, parent) {
914 var view = views[route]
915 if (view) {
916 if (el) {
917 view.el = el
918 view.parent = parent && View(parent)
919 }
920 return view
921 }
922 view = this
923 if (!(view instanceof View)) return new View(route, el, parent)
924 views[view.route = route] = view
925 view.el = el
926 view.parent = parent && View(parent)
927
928 if (route.charAt(0) != "#") {
929 var params = "u[" + (view.seq = groupsCount++) + "]?("
930 , _re = route.replace(parseRe, function(_, key) {
931 return key ?
932 (params += "o['" + key + "']=u[" + (groupsCount++) + "],") && "([^/]+?)" :
933 _.replace(escapeRe, "\\$&")
934 })
935
936 fnStr += params + "'" + route + "'):"
937 reStr += (reStr ? "|(" : "(") + _re + ")"
938 fn = 0
939 }
940 }
941
942 View.prototype = {
943 show: function(_params) {
944 var parent
945 , params = lastParams = _params || {}
946 , view = lastView = this
947 , tmp = params._v || view
948 , close = view.isOpen && view
949
950 View.active = view.route
951
952 for (; tmp; tmp = parent) {
953 syncResume = params._v = tmp
954 tmp.emit("ping", params)
955 View.emit("ping", params, tmp)
956 syncResume = null
957 if (lastParams != params) return
958 if (parent = tmp.parent) {
959 if (parent.child && parent.child != tmp) {
960 close = parent.child
961 }
962 parent.child = tmp
963 }
964 if (!tmp.el) {
965 if (tmp.file) {
966 xhr.load(
967 tmp.file
968 .replace(/^|,/g, "$&" + (View.base || ""))
969 .split(","),
970 view.wait()
971 )
972 tmp.file = null
973 } else {
974 View("404").show(JSON.merge({}, params))
975 }
976 return
977 }
978 }
979
980 for (tmp in params) if (tmp.charAt(0) != "_") {
981 if (syncResume = param[tmp] || param["*"]) {
982 syncResume.call(view, params[tmp], tmp, params)
983 syncResume = null
984 }
985 }
986
987 bubbleDown(params, close)
988 },
989 wait: function() {
990 var params = lastParams
991 params._p = 1 + (params._p | 0)
992 return function() {
993 if (--params._p || lastParams != params || syncResume) return
994 if (params._d) {
995 bubbleDown(params)
996 } else if (params._v) {
997 lastView.show(params)
998 }
999 }
1000 }
1001 }
1002
1003 function bubbleDown(params, close) {
1004 var tmp
1005 , view = params._v
1006 , parent = view && view.parent
1007 if (!view || params._p && /{/.test(view.route)) {
1008 return closeView(close)
1009 }
1010 if (parent && !view.isOpen || view === close) {
1011 closeView(close, view)
1012 El.scope(
1013 view.isOpen = view.el.cloneNode(true),
1014 El.scope(tmp = parent.isOpen || parent.el)
1015 )
1016 El.append(tmp, view.isOpen)
1017 El.render(view.isOpen)
1018 parent.emit("openChild", view, close)
1019 view.emit("open", params)
1020 View.emit("open", params, view)
1021 if (view.kb) El.addKb(view.kb)
1022 close = null
1023 }
1024 if (params._d = params._v = view.child) {
1025 bubbleDown(params, close)
1026 }
1027 if (lastView == view) {
1028 view.emit("show", params)
1029 View.emit("show", params, view)
1030 blur()
1031 }
1032 }
1033
1034 function closeView(view, open) {
1035 if (view && view.isOpen) {
1036 view.parent.emit("closeChild", view, open)
1037 closeView(view.child)
1038 El.kill(view.isOpen)
1039 view.isOpen = null
1040 if (view.kb) El.rmKb(view.kb)
1041 view.emit("close")
1042 }
1043 }
1044
1045 Event.asEmitter(View)
1046 Event.asEmitter(View.prototype)
1047
1048 View.base = "view/"
1049 View.home = "home"
1050
1051 View.get = get
1052 function get(url, params) {
1053 if (!fn) {
1054 fn = Function(
1055 "u,o,r",
1056 "return (u=/^\\/?(?:" + reStr + ")[\\/\\s]*$/.exec(u))?(" + fnStr + "r):r"
1057 )
1058 }
1059 return View(fn(url || View.home, params || {}, "404"))
1060 }
1061
1062 View.show = function(url, _params) {
1063 if (url === true) {
1064 url = lastUrl
1065 lastUrl = 0
1066 }
1067 var params = _params || {}
1068 , view = get(url, params)
1069 if (!view.isOpen || lastUrl != url) {
1070 params._u = lastUrl = url
1071 view.show(El.data.route = params)
1072 }
1073 }
1074
1075 View.param = param
1076 function param(name, cb) {
1077 [].concat(name).forEach(function(n) {
1078 param[n] = cb
1079 })
1080 }
1081
1082 View.def = function(str) {
1083 for (var match, re = /(\S+) (\S+)/g; match = re.exec(str);) {
1084 match[1].split(",").map(function(view) {
1085 view = View(defMap(view, lastStr))
1086 view.file = (view.file ? view.file + "," : "") +
1087 match[2].split(",").map(function(file) {
1088 return views[file] ? views[file].file : defMap(file, lastStr)
1089 })
1090 })
1091 }
1092 }
1093
1094 View.blur = blur
1095 function blur() {
1096 // When a View completes, blur focused link
1097 // IE8 can throw an exception for document.activeElement.
1098 try {
1099 var el = document.activeElement
1100 , tag = el && el.tagName
1101 if (tag === "A" || tag === "BUTTON") el.blur()
1102 } catch(e) {}
1103 }
1104
1105 View.url = defMap
1106 function defMap(str, _last) {
1107 var chr = str.charAt(0)
1108 , slice = str.slice(1)
1109 , last = _last || lastUrl
1110 return (
1111 chr === "+" ? last + slice :
1112 chr === "%" ? ((chr = last.lastIndexOf(slice.charAt(0))), (chr > 0 ? last.slice(0, chr) : last)) + slice :
1113 (lastStr = str)
1114 )
1115 }
1116
1117}(this)
1118/* litejs.com/MIT-LICENSE.txt */
1119
1120
1121
1122!function(window, document, Object, Event, protoStr) {
1123 var currentLang, styleNode
1124 , seq = 0
1125 , elCache = El.cache = {}
1126 , wrapProto = []
1127 , slice = wrapProto.slice
1128 , hasOwn = elCache.hasOwnProperty
1129 , body = document.body
1130 , root = document.documentElement
1131 , txtAttr = "textContent" in body ? "textContent" : "innerText"
1132 , templateRe = /^([ \t]*)(@?)((?:("|')(?:\\?.)*?\4|[-\w:.#[\]=])*)[ \t]*(([\])}]?).*?([[({]?))$/gm
1133 , renderRe = /[;\s]*(\w+)(?:\s*(:?):((?:(["'\/])(?:\\?.)*?\3|[^;])*))?/g
1134 , splitRe = /[,\s]+/
1135 , bindings = El.bindings = {
1136 attr: setAttr,
1137 css: El.css = acceptMany(function(el, key, val) {
1138 el.style[key.camelCase()] = "" + val || ""
1139 }),
1140 "class": function(el, name, fn) {
1141 ;(arguments.length < 3 || fn ? addClass : rmClass)(el, name)
1142 },
1143 data: function(el, key, val) {
1144 setAttr(el, "data-" + key, val)
1145 },
1146 html: function(el, html) {
1147 el.innerHTML = html
1148 },
1149 ref: function(el, name) {
1150 this[name] = el
1151 },
1152 txt: function(el, txt) {
1153 el[txtAttr] = txt
1154 },
1155 val: function(el, txt) {
1156 valFn(el, txt)
1157 },
1158 "with": function(el, map) {
1159 var scope = elScope(el, this)
1160 Object.assign(scope, map)
1161 if (scope !== this) {
1162 render(el)
1163 return true
1164 }
1165 }
1166 }
1167 , bindMatch = []
1168 , scopeData = El.data = {
1169 _: i18n,
1170 _b: bindings,
1171 El: El,
1172 history: history,
1173 View: View
1174 }
1175 , addClass = El.addClass = acceptMany(_addClass)
1176 , rmClass = El.rmClass = acceptMany(_rmClass)
1177
1178 //** modernBrowser
1179
1180 // JScript engine in IE<9 does not recognize vertical tabulation character
1181 , ie678 = !+"\v1"
1182 , ie67 = ie678 && (document.documentMode | 0) < 8
1183
1184 , matches = El.matches = body.matches ?
1185 function(el, sel) {
1186 return el.matches(sel)
1187 } :
1188 function(el, sel) {
1189 return !!selectorFn(sel)(el)
1190 }
1191 , closest = El.closest = body.closest ?
1192 function(el, sel) {
1193 return (el.closest ? el : el.parentNode).closest(sel)
1194 } :
1195 function(el, sel) {
1196 return walk("parentNode", 1, el, sel)
1197 }
1198
1199
1200 , selectorRe = /([.#:[])([-\w]+)(?:\((.+?)\)|([~^$*|]?)=(("|')(?:\\?.)*?\6|[-\w]+))?]?/g
1201 , selectorLastRe = /([~\s>+]*)(?:("|')(?:\\?.)*?\2|\(.+?\)|[^\s+>])+$/
1202 , selectorSplitRe = /\s*,\s*(?=(?:[^'"()]|"(?:\\?.)*?"|'(?:\\?.)*?'|\(.+?\))+$)/
1203 , selectorCache = {}
1204 , selectorMap = {
1205 "first-child": "(a=_.parentNode)&&a.firstChild==_",
1206 "last-child": "(a=_.parentNode)&&a.lastChild==_",
1207 ".": "~_.className.split(/\\s+/).indexOf(a)",
1208 "#": "_.id==a",
1209 "^": "!a.indexOf(v)",
1210 "|": "a.split('-')[0]==v",
1211 "$": "a.slice(-v.length)==v",
1212 "~": "~a.split(/\\s+/).indexOf(v)",
1213 "*": "~a.indexOf(v)"
1214 }
1215
1216 function selectorFn(str) {
1217 // jshint evil:true
1218 return selectorCache[str] ||
1219 (selectorCache[str] = Function("m,c", "return function(_,v,a,b){return " +
1220 str.split(selectorSplitRe).map(function(sel) {
1221 var relation, from
1222 , rules = ["_&&_.nodeType==1"]
1223 , parentSel = sel.replace(selectorLastRe, function(_, _rel, a, start) {
1224 from = start + _rel.length
1225 relation = _rel.trim()
1226 return ""
1227 })
1228 , tag = sel.slice(from).replace(selectorRe, function(_, op, key, subSel, fn, val, quotation) {
1229 rules.push(
1230 "((v='" +
1231 (subSel || (quotation ? val.slice(1, -1) : val) || "").replace(/'/g, "\\'") +
1232 "'),(a='" + key + "'),1)"
1233 ,
1234 selectorMap[op == ":" ? key : op] ||
1235 "(a=_.getAttribute(a))" +
1236 (fn ? "&&" + selectorMap[fn] : val ? "==v" : "")
1237 )
1238 return ""
1239 })
1240
1241 if (tag && tag != "*") rules[0] += "&&_.tagName=='" + tag.toUpperCase() + "'"
1242 if (parentSel) rules.push("(v='" + parentSel + "')", selectorMap[relation + relation])
1243 return rules.join("&&")
1244 }).join("||") + "}"
1245 )(matches, closest))
1246 }
1247
1248 function walk(next, first, el, sel, nextFn) {
1249 var out = []
1250 if (typeof sel !== "function") sel = selectorFn(sel)
1251 for (; el; el = el[next] || nextFn && nextFn(el)) if (sel(el)) {
1252 if (first) return el
1253 out.push(el)
1254 }
1255 return first ? null : out
1256 }
1257
1258 function find(node, sel, first) {
1259 return walk("firstChild", first, node.firstChild, sel, function(el) {
1260 var next = el.nextSibling
1261 while (!next && ((el = el.parentNode) !== node)) next = el.nextSibling
1262 return next
1263 })
1264 }
1265
1266 // Note: querySelector in IE8 supports only CSS 2.1 selectors
1267 if (!ie678 && body.querySelector) {
1268 El.find = function(el, sel) {
1269 return el.querySelector(sel)
1270 }
1271 El.findAll = function(el, sel) {
1272 return new ElWrap(el.querySelectorAll(sel))
1273 }
1274 } else {
1275 El.find = function(el, sel) {
1276 return find(el, sel, true)
1277 }
1278 El.findAll = function(el, sel) {
1279 return new ElWrap(find(el, sel))
1280 }
1281 }
1282
1283 /*/
1284 , closest = proto.closest
1285
1286 proto.find = proto.querySelector
1287 proto.findAll = function(sel) {
1288 return new ElWrap(this.querySelectorAll(sel))
1289 }
1290 //*/
1291
1292 /**
1293 * Turns CSS selector like syntax to DOM Node
1294 * @returns {Node}
1295 *
1296 * @example
1297 * El("input#12.nice[type=checkbox]:checked:disabled[data-lang=en].class")
1298 * <input id="12" class="nice class" type="checkbox" checked="checked" disabled="disabled" data-lang="en">
1299 */
1300
1301 window.El = El
1302
1303 function El(name) {
1304 if (typeof name != "string") {
1305 return new ElWrap(name)
1306 }
1307 var el, pres
1308 , pre = {}
1309 name = name.replace(selectorRe, function(_, op, key, _sub, fn, val, quotation) {
1310 pres = 1
1311 val = quotation ? val.slice(1, -1) : val || key
1312 pre[op =
1313 op == "." ?
1314 (fn = "~", "class") :
1315 op == "#" ?
1316 "id" :
1317 key
1318 ] = fn && pre[op] ?
1319 fn == "^" ? val + pre[op] :
1320 pre[op] + (fn == "~" ? " " : "") + val :
1321 val
1322 return ""
1323 }) || "div"
1324
1325 // NOTE: IE-s cloneNode consolidates the two text nodes together as one
1326 // http://brooknovak.wordpress.com/2009/08/23/ies-clonenode-doesnt-actually-clone/
1327 el = (elCache[name] || (elCache[name] = document.createElement(name))).cloneNode(true)
1328
1329 if (pres) {
1330 setAttr(el, pre)
1331 }
1332
1333 return el
1334 }
1335
1336 function ElWrap(nodes) {
1337 var wrap = this
1338 , i = nodes.length
1339 /**
1340 * 1. Extended array size will not updated
1341 * when array elements set directly in Android 2.2.
1342 */
1343 if (i) {
1344 wrap.length = i /* 1 */
1345 for (; i--; ) {
1346 wrap[i] = nodes[i]
1347 }
1348 } else if (i == null) {
1349 wrap.length = 1 /* 1 */
1350 wrap[0] = nodes
1351 }
1352 }
1353
1354 ElWrap[protoStr] = wrapProto
1355
1356 wrapProto.append = function(el) {
1357 var elWrap = this
1358 if (elWrap._childId != void 0) {
1359 append(elWrap[elWrap._childId], el)
1360 } else {
1361 elWrap.push(el)
1362 }
1363 return elWrap
1364 }
1365
1366 wrapProto.cloneNode = function(deep) {
1367 var clone = new ElWrap(this.map(function(el) {
1368 return el.cloneNode(deep)
1369 }))
1370 clone._childId = this._childId
1371 return clone
1372 }
1373
1374
1375 El.attr = function(el, key, val) {
1376 return arguments.length < 3 && key.constructor != Object ? getAttr(el, key) : setAttr(el, key, val)
1377 }
1378
1379 function getAttr(el, key) {
1380 return el && el.getAttribute && el.getAttribute(key)
1381 }
1382
1383 function setAttr(el, key, val) {
1384 var current
1385
1386 if (key && key.constructor == Object) {
1387 for (current in key) {
1388 setAttr(el, current, key[current])
1389 }
1390 return
1391 }
1392
1393 /* Accept namespaced arguments
1394 var namespaces = {
1395 xlink: "http://www.w3.org/1999/xlink",
1396 svg: "http://www.w3.org/2000/svg"
1397 }
1398
1399 current = key.split("|")
1400 if (current[1]) {
1401 el.setAttributeNS(namespaces[current[0]], current[1], val)
1402 return
1403 }
1404 */
1405
1406 current = el.getAttribute(key)
1407
1408 // Note: IE5-7 doesn't set styles and removes events when you try to set them.
1409 //
1410 // in IE6, a label with a for attribute linked to a select list
1411 // will cause a re-selection of the first option instead of just giving focus.
1412 // http://webbugtrack.blogspot.com/2007/09/bug-116-for-attribute-woes-in-ie6.html
1413
1414 // there are bug in IE<9 where changed 'name' param not accepted on form submit
1415 // IE8 and below support document.createElement('<P>')
1416 //
1417 // http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
1418 // http://msdn.microsoft.com/en-us/library/ms536614(VS.85).aspx
1419
1420 //** modernBrowser
1421 // istanbul ignore next: IE fix
1422 if (ie67 && (key == "id" || key == "name" || key == "checked")) {
1423 el.mergeAttributes(document.createElement('<INPUT ' + key + '="' + val + '">'), false)
1424 } else
1425 //*/
1426 if (key == "class") {
1427 addClass(el, val)
1428 } else if (val || val === 0) {
1429 if (current != val) {
1430 el.setAttribute(key, val)
1431 }
1432 } else if (current) {
1433 el.removeAttribute(key)
1434 }
1435 }
1436
1437 // In Safari 2.x, innerText functions properly only
1438 // if an element is neither hidden (via style.display == "none")
1439 // nor orphaned from the document.
1440 // Otherwise, innerText results in an empty string.
1441 //
1442 // textContent is suported from IE9
1443 // Opera 9-10 have Node.text so we use Node.txt
1444
1445 El.txt = function(el, newText) {
1446 return arguments.length > 1 && el[txtAttr] != newText ? (
1447 //** modernBrowser
1448 // Fix for IE5-7
1449 //(ie67 && el.tagName == "OPTION" && (el.label = newText)),
1450 //*/
1451 el[txtAttr] = newText
1452 ) : el[txtAttr]
1453 }
1454
1455 El.val = valFn
1456 function valFn(el, val) {
1457 var input, step, key, value
1458 , i = 0
1459 , type = el.type
1460 , opts = el.options
1461 , checkbox = type === "checkbox" || type === "radio"
1462
1463 if (el.tagName === "FORM") {
1464 opts = {}
1465
1466 // Disabled controls do not receive focus,
1467 // are skipped in tabbing navigation, cannot be successfully posted.
1468 //
1469 // Read-only elements receive focus but cannot be modified by the user,
1470 // are included in tabbing navigation, are successfully posted.
1471 //
1472 // Read-only checkboxes can be changed by the user
1473
1474 for (; input = el.elements[i++]; ) if (!input.disabled && (key = input.name || input.id)) {
1475 value = valFn(input)
1476 if (value !== void 0) {
1477 step = opts
1478 key.replace(/\[(.*?)\]/g, function(_, _key, offset) {
1479 if (step == opts) key = key.slice(0, offset)
1480 step = step[key] || (step[key] = _key && +_key != _key ? {} : [])
1481 key = _key
1482 })
1483 step[key || step.length] = value
1484 }
1485 }
1486
1487 return opts
1488 }
1489
1490 if (arguments.length > 1) {
1491 if (opts) {
1492 value = (Array.isArray(val) ? val : [ val ]).map(String)
1493 for (; input = opts[i++]; ) {
1494 input.selected = value.indexOf(input.value) > -1
1495 }
1496 } else {
1497 checkbox ? (el.checked = !!val) : (el.value = val)
1498 }
1499 return
1500 }
1501
1502 if (opts) {
1503 if (type === "select-multiple") {
1504 for (val = []; input = opts[i++]; ) {
1505 if (input.selected && !input.disabled) {
1506 val.push(input.valObject || input.value)
1507 }
1508 }
1509 return val
1510 }
1511 // IE8 throws error when accessing to options[-1]
1512 value = el.selectedIndex
1513 el = value > -1 && opts[value] || el
1514 }
1515
1516 return checkbox && !el.checked ?
1517 (type === "radio" ? void 0 : null) :
1518 el.valObject || el.value
1519 }
1520
1521 function append(el, child, before) {
1522 if (!el.nodeType) {
1523 return el.append ? el.append(child, before) : el
1524 }
1525 var fragment
1526 , i = 0
1527 , tmp = typeof child
1528 if (child) {
1529 if (tmp == "string" || tmp == "number") child = document.createTextNode(child)
1530 else if ( !("nodeType" in child) && "length" in child ) {
1531 // document.createDocumentFragment is unsupported in IE5.5
1532 // fragment = "createDocumentFragment" in document ? document.createDocumentFragment() : El("div")
1533 for (
1534 tmp = child.length
1535 , fragment = document.createDocumentFragment();
1536 i < tmp; ) append(fragment, child[i++])
1537 child = fragment
1538 }
1539
1540 if (child.nodeType) {
1541 tmp = el.insertBefore ? el : el[el.length - 1]
1542 if (i = getAttr(tmp, "data-child")) {
1543 before = find(tmp, Fn("v->n->n.nodeType===8&&n.nodeValue==v")(i), 1) || tmp
1544 tmp = before.parentNode
1545 // TODO:2016-07-05:lauri:handle numeric befores
1546 }
1547 tmp.insertBefore(child,
1548 (before === true ? tmp.firstChild :
1549 typeof before == "number" ? tmp.childNodes[
1550 before < 0 ? tmp.childNodes.length - before - 2 : before
1551 ] : before) || null
1552 )
1553 }
1554 }
1555 return el
1556 }
1557
1558 function acceptMany(fn) {
1559 return function(el, name, val) {
1560 if (typeof name === "string" && name !== "") {
1561 var names = name.split(splitRe)
1562 , i = 0
1563 , len = names.length
1564
1565 if (len > 1) {
1566 /*
1567 if (Array.isArray(val)) {
1568 for (; i < len; ) fn(el, names[i], val[i++])
1569 } else {
1570 for (; i < len; ) fn(el, names[i++], val)
1571 }
1572 /*/
1573 for (; i < len; ) {
1574 fn(el, names[i++], Array.isArray(val) ? val[i - 1] : val)
1575 }
1576 //*/
1577 } else {
1578 fn(el, name, val)
1579 }
1580 }
1581 }
1582 }
1583
1584 // setAttribute("class") is broken in IE7
1585 // className is object in SVGElements
1586
1587 El.hasClass = hasClass
1588 function hasClass(el, name) {
1589 var current = el.className || ""
1590
1591 if (typeof current !== "string") {
1592 current = el.getAttribute("class") || ""
1593 }
1594
1595 return !!current && current.split(splitRe).indexOf(name) > -1
1596 }
1597
1598 function _addClass(el, name) {
1599 var current = el.className || ""
1600 , useAttr = typeof current !== "string"
1601
1602 if (useAttr) {
1603 current = el.getAttribute("class") || ""
1604 }
1605
1606 if (current) {
1607 name = current.split(splitRe).indexOf(name) > -1 ? current : current + " " + name
1608 }
1609
1610 if (current != name) {
1611 if (useAttr) {
1612 el.setAttribute("class", name)
1613 } else {
1614 el.className = name
1615 }
1616 }
1617 }
1618
1619 function _rmClass(el, name) {
1620 var current = el.className || ""
1621 , useAttr = typeof current != "string"
1622
1623 if (useAttr) {
1624 current = el.getAttribute("class") || ""
1625 }
1626
1627 if (current) {
1628 name = (" " + current + " ").replace(" " + name + " ", " ").trim()
1629 if (current != name) {
1630 if (useAttr) {
1631 el.setAttribute("class", name)
1632 } else {
1633 el.className = name
1634 }
1635 }
1636 }
1637
1638 }
1639
1640 // The addEventListener is supported in Internet Explorer from version 9.
1641 // https://developer.mozilla.org/en-US/docs/Web/Reference/Events/wheel
1642 // - IE8 always prevents the default of the mousewheel event.
1643
1644 var wheelDiff = 120
1645 , addEv = "addEventListener"
1646 , remEv = "removeEventListener"
1647 , prefix = window[addEv] ? "" : (addEv = "attachEvent", remEv = "detachEvent", "on")
1648 , fixEv = Event.fixEv = {
1649 wheel:
1650 "onwheel" in document ? "wheel" : // Modern browsers
1651 "onmousewheel" in document ? "mousewheel" : // Webkit and IE
1652 "DOMMouseScroll" // older Firefox
1653 }
1654 , fixFn = Event.fixFn = {
1655 wheel: function(el, _fn) {
1656 return function(e) {
1657 var delta = (e.wheelDelta || -e.detail || -e.deltaY) / wheelDiff
1658 if (delta) {
1659 if (delta < 1 && delta > -1) {
1660 var diff = (delta < 0 ? -1 : 1)/delta
1661 delta *= diff
1662 wheelDiff /= diff
1663 }
1664 //TODO: fix event
1665 // e.deltaY =
1666 // e.deltaX = - 1/40 * e.wheelDeltaX|0
1667 // e.target = e.target || e.srcElement
1668 _fn.call(el, e, delta)
1669 }
1670 }
1671 }
1672 }
1673
1674 var emitter = new Event.Emitter
1675
1676 function addEvent(el, ev, _fn) {
1677 var fn = fixFn[ev] && fixFn[ev](el, _fn) || _fn
1678 , fix = prefix ? function() {
1679 var e = window.event
1680 if (e) {
1681 e.target = e.srcElement
1682 e.preventDefault = preventDefault
1683 e.stopPropagation = stopPropagation
1684 }
1685 fn.call(el, e)
1686 } : fn
1687
1688 el[addEv](prefix + (fixEv[ev] || ev), fix, false)
1689
1690 emitter.on.call(el, ev, fix, el, _fn)
1691 }
1692
1693 function rmEvent(el, ev, fn) {
1694 var evs = el._e && el._e[ev]
1695 , id = evs && evs.indexOf(fn)
1696 if (id > -1) {
1697 el[remEv](prefix + (fixEv[ev] || ev), evs[id + 1])
1698 evs.splice(id - 1, 3)
1699 }
1700 }
1701
1702 function preventDefault() {
1703 this.returnValue = false
1704 }
1705 function stopPropagation() {
1706 this.cancelBubble = this.cancel = true
1707 }
1708
1709 Event.stop = function(e) {
1710 if (e.preventDefault) {
1711 e.stopPropagation()
1712 e.preventDefault()
1713 }
1714 return false
1715 }
1716
1717 El.on = acceptMany(addEvent)
1718 El.off = acceptMany(rmEvent)
1719
1720 El.one = function(el, ev, fn) {
1721 function remove() {
1722 rmEvent(el, ev, fn)
1723 rmEvent(el, ev, remove)
1724 }
1725 addEvent(el, ev, fn)
1726 addEvent(el, ev, remove)
1727 return el
1728 }
1729
1730 El.emit = function(el, ev) {
1731 emitter.emit.apply(el, slice.call(arguments, 1))
1732 }
1733
1734 function empty(el) {
1735 for (var node; node = el.firstChild; ) {
1736 kill(node)
1737 }
1738 return el
1739 }
1740
1741 function kill(el) {
1742 var id
1743 if (el) {
1744 if (el._e) {
1745 emitter.emit.call(el, "kill")
1746 for (id in el._e) rmEvent(el, id)
1747 }
1748 if (el.parentNode) {
1749 el.parentNode.removeChild(el)
1750 }
1751 if (el.nodeType != 1) {
1752 return el.kill && el.kill()
1753 }
1754 empty(el)
1755 if (id = el._scope) {
1756 delete elScope[id]
1757 }
1758 if (el.valObject) {
1759 el.valObject = null
1760 }
1761 }
1762 }
1763
1764 function elScope(node, parent, fb) {
1765 return elScope[node._scope] ||
1766 fb ||
1767 (parent ?
1768 (((fb = elScope[node._scope = ++seq] = Object.create(parent))._super = parent), fb) :
1769 closestScope(node)
1770 ) ||
1771 scopeData
1772
1773 }
1774
1775 function closestScope(node) {
1776 for (; node = node.parentNode; ) {
1777 if (node._scope) return elScope[node._scope]
1778 }
1779 }
1780
1781 function render(node, scope) {
1782 var bind, fn
1783 , i = 0
1784
1785 if (node.nodeType != 1) {
1786 node.render ? node.render(scope) : node
1787 return
1788 }
1789
1790 scope = elScope(node, 0, scope)
1791
1792 if (bind = getAttr(node, "data-bind")) {
1793 scope._m = bindMatch
1794 scope._t = bind
1795 // i18n(bind, lang).format(scope)
1796 // document.documentElement.lang
1797 // document.getElementsByTagName('html')[0].getAttribute('lang')
1798
1799 fn = "data b s r->data&&(" + bind.replace(renderRe, function(match, name, op, args) {
1800 scope._m[i] = match
1801 var fn = bindings[name]
1802 return (
1803 (op == ":" || fn && hasOwn.call(fn, "once")) ?
1804 "s(this,'data-bind',data._t=data._t.replace(data._m[" + (i++)+ "],''))||" :
1805 ""
1806 ) + (
1807 fn ?
1808 "b['" + name + "'].call(data,this" + (fn.raw ? ",'" + args + "'" : args ? "," + args : "") + ")||" :
1809 "s(this,'" + name + "'," + args + ")||"
1810 )
1811 }) + "r)"
1812
1813 try {
1814 if (Fn(fn, node, scope)(scope, bindings, setAttr)) {
1815 return
1816 }
1817 } catch (e) {
1818 //** debug
1819 e.message += "\nBINDING: " + bind
1820 console.error(e, node)
1821 //*/
1822 if (window.onerror) {
1823 window.onerror(e.message, e.fileName, e.lineNumber)
1824 }
1825 }
1826 }
1827
1828 for (bind = node.firstChild; bind; bind = fn) {
1829 fn = bind.nextSibling
1830 render(bind, scope)
1831 }
1832 //** modernBrowser
1833 if (ie678 && node.nodeName == "SELECT") {
1834 node.parentNode.insertBefore(node, node)
1835 }
1836 //*/
1837 }
1838
1839 El.empty = empty
1840 El.kill = kill
1841 El.render = render
1842
1843 Object.each(El, function(fn, key) {
1844 if (!wrapProto[key]) {
1845 wrapProto[key] = function wrap() {
1846 var i = 0
1847 , self = this
1848 , len = self.length
1849 , arr = slice.call(arguments)
1850 arr.unshift(1)
1851 for (; i < len; ) {
1852 arr[0] = self[i++]
1853 fn.apply(null, arr)
1854 }
1855 return self
1856 }
1857 }
1858 })
1859
1860 El.append = append
1861 El.scope = elScope
1862
1863 //** templates
1864
1865 function parseTemplate(str) {
1866 var parent = El("div")
1867 , stack = [-1]
1868 , parentStack = []
1869
1870 function work(all, indent, plugin, name, q, text, mapEnd, mapStart, offset) {
1871 if (offset && all === indent) return
1872
1873 for (q = indent.length; q <= stack[0]; ) {
1874 if (parent.plugin) {
1875 parent.plugin.done()
1876 }
1877 parent = parentStack.pop()
1878 stack.shift()
1879 }
1880
1881 if (parent.txtMode) {
1882 parent.txt += all + "\n"
1883 } else if (plugin || mapStart && (name = "map")) {
1884 if (El.plugins[name]) {
1885 parentStack.push(parent)
1886 stack.unshift(q)
1887 parent = (new El.plugins[name](parent, text, mapEnd ? "" : ";")).el
1888 } else {
1889 append(parent, all)
1890 }
1891 } else if (mapEnd) {
1892 appendBind(parent, text, "")
1893 } else {
1894 if (name) {
1895 parentStack.push(parent)
1896 stack.unshift(q)
1897 q = El(name, 0, 1)
1898 append(parent, q)
1899 parent = q
1900 }
1901 if (text) {
1902 q = text.charAt(0)
1903 name = text.slice(1)
1904 if (q == ">") {
1905 (indent + " " + name).replace(templateRe, work)
1906 } else if (q == "|" || q == "\\") {
1907 append(parent, name) // + "\n")
1908 } else if (q != "/") {
1909 if (q != "&") {
1910 name = (parent.tagName == "INPUT" ? "val" : "txt")
1911 + ":_('" + text.replace(/'/g, "\\'") + "').format(data)"
1912 }
1913 appendBind(parent, name, ";")
1914 }
1915 }
1916 }
1917 }
1918 str.replace(templateRe, work)
1919 work("", "")
1920 }
1921
1922 function appendBind(el, val, sep) {
1923 var current = getAttr(el, "data-bind")
1924 setAttr(el, "data-bind", (current ? current + sep + val : val))
1925 }
1926
1927 function plugin(parent, name) {
1928 var t = this
1929 t.name = name
1930 t.parent = parent
1931 t.el = El("div")
1932 t.el.plugin = t
1933 }
1934
1935 plugin[protoStr] = {
1936 _done: function() {
1937 var el, childId
1938 , t = this
1939 , childNodes = t.el.childNodes
1940 , i = childNodes.length
1941
1942 for (; i--; ) {
1943 el = childNodes[i]
1944 if (el._childKey) {
1945 childId = i
1946 setAttr(el, "data-child", el._childKey)
1947 break
1948 }
1949 }
1950
1951 if (childNodes[1]) {
1952 el = new ElWrap(childNodes)
1953 el._childId = childId
1954 } else {
1955 el = childNodes[0]
1956 }
1957
1958 t.el.plugin = t.el = t.parent = null
1959 return el
1960 },
1961 done: function() {
1962 var t = this
1963 , parent = t.parent
1964 elCache[t.name] = t._done()
1965 return parent
1966 }
1967 }
1968
1969 function js(parent, params, attr1) {
1970 var t = this
1971 t.txtMode = t.parent = parent
1972 t.txt = ""
1973 t.plugin = t.el = t
1974 t.params = params
1975 t.a = attr1
1976 }
1977
1978 js[protoStr].done = Fn("Function(this.txt)()")
1979
1980 El.plugins = {
1981 binding: js.extend({
1982 done: function() {
1983 JSON.merge(bindings, Function("return({" + this.txt + "})")())
1984 }
1985 }),
1986 child: plugin.extend({
1987 done: function() {
1988 var key = "@child-" + (++seq)
1989 , root = this.parent
1990 for (; (root.parentNode.parentNode || key).nodeType == 1; ) {
1991 root = root.parentNode
1992 }
1993 root._childKey = key
1994 append(this.parent, document.createComment(key))
1995 }
1996 }),
1997 css: js.extend({
1998 done: Fn("xhr.css(this.txt)")
1999 }),
2000 def: js.extend({
2001 done: Fn("View.def(this.params||this.txt)")
2002 }),
2003 each: js.extend({
2004 done: function() {
2005 var txt = this.txt
2006
2007 JSON.parse(this.params)
2008 .each(function(val) {
2009 if (!val || val.constructor != Object) {
2010 val = { item: val }
2011 }
2012 parseTemplate(txt.format(val))
2013 })
2014 }
2015 }),
2016 el: plugin,
2017 js: js,
2018 map: js.extend({
2019 done: function() {
2020 var self = this
2021 , txt = (self.params + self.txt).replace(/\n+/g, "")
2022 appendBind(
2023 self.parent,
2024 self.a ? txt.slice(1) : txt,
2025 self.a
2026 )
2027 }
2028 }),
2029 template: plugin,
2030 view: plugin.extend({
2031 done: function() {
2032 var fn
2033 , t = this
2034 , arr = t.name.split(splitRe)
2035 , bind = getAttr(t.el, "data-bind")
2036 , view = View(arr[0], t._done(), arr[1], arr[2])
2037 if (bind) {
2038 fn = bind.replace(renderRe, function(match, name, op, args) {
2039 return "(this['" + name + "']" + (
2040 typeof view[name] == "function" ?
2041 "(" + (args || "") + "))," :
2042 "=" + args + "),"
2043 )
2044 }) + "1"
2045 Fn(fn, view, scopeData)()
2046 }
2047 }
2048 }),
2049 "view-link": plugin.extend({
2050 done: function() {
2051 var t = this
2052 , arr = t.name.split(splitRe)
2053 View(arr[0], null, arr[2])
2054 .on("ping", function(opts) {
2055 View.show(arr[1].format(opts))
2056 })
2057 }
2058 })
2059 }
2060
2061 xhr.view = xhr.tpl = El.tpl = parseTemplate
2062 xhr.css = function(str) {
2063 if (!styleNode) {
2064 // Safari and IE6-8 requires dynamically created
2065 // <style> elements to be inserted into the <head>
2066 append(document.getElementsByTagName("head")[0], styleNode = El("style"))
2067 }
2068 if (styleNode.styleSheet) styleNode.styleSheet.cssText += str
2069 else append(styleNode, str)
2070 }
2071
2072 //*/
2073
2074 El.scrollLeft = scrollLeft
2075 function scrollLeft() {
2076 return window.pageXOffset || root.scrollLeft || body.scrollLeft || 0
2077 }
2078
2079 El.scrollTop = scrollTop
2080 function scrollTop() {
2081 return window.pageYOffset || root.scrollTop || body.scrollTop || 0
2082 }
2083
2084 El.mouse = function(e) {
2085 if (e.changedTouches) e = e.changedTouches[0]
2086 return {
2087 left: e.pageX || e.clientX + scrollLeft(),
2088 top: e.pageY || e.clientY + scrollTop()
2089 }
2090 }
2091
2092 //** kb
2093 var kbMaps = []
2094 , kbKeys = {
2095 8: "backspace", 9: "tab",
2096 13: "enter", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
2097 20: "caps", 27: "esc",
2098 33: "pgup", 34: "pgdown",
2099 35: "end", 36: "home",
2100 37: "left", 38: "up", 39: "right", 40: "down",
2101 45: "ins", 46: "del",
2102 91: "cmd",
2103 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6",
2104 118: "f7", 119: "f8", 120: "f9", 121: "f10", 122: "f11", 123: "f12"
2105 }
2106 , kbMod = El.kbMod = /Mac|iPod|iPhone|iPad|Pike/.test(navigator.platform) ? "metaKey" : "ctrlKey"
2107
2108 function kbRun(e, code, chr) {
2109 var fn, map
2110 , i = 0
2111 , el = e.target || e.srcElement
2112 , input = /INPUT|TEXTAREA|SELECT/i.test((el.nodeType == 3 ? el.parentNode : el).tagName)
2113
2114 for (; map = kbMaps[i++]; ) {
2115 if (!input || map.input) {
2116 fn = map[code] ||
2117 map[chr] ||
2118 map.num && code > 47 && code < 58 && (chr|=0, map.num) ||
2119 map.all
2120 }
2121 if (fn || !map.bubble) break
2122 }
2123 if (fn) {
2124 typeof fn === "string" ? View.emit(fn, e, chr, el) : fn(e, chr, el)
2125 }
2126 }
2127
2128 function kbDown(e) {
2129 if (kbMaps[0]) {
2130 var c = e.keyCode || e.which
2131 , numpad = c > 95 && c < 106
2132 , code = numpad ? c - 48 : c
2133 , key = kbKeys[code] || String.fromCharCode(code).toLowerCase() || code
2134
2135 // Otherwise IE backspace navigates back
2136 if (code == 8 && kbMaps[0].backspace) {
2137 Event.stop(e)
2138 }
2139 kbRun(e, code, key)
2140 if (e.shiftKey && code != 16) kbRun(e, code, "shift+" + key)
2141 if (e.ctrlKey && code != 17) kbRun(e, code, "ctrl+" + key)
2142 if (e.altKey && code != 18) kbRun(e, code, "alt+" + key)
2143 if (e[kbMod] && code != 17 && code != 91) kbRun(e, code, "mod+" + key)
2144 }
2145 }
2146
2147 El.addKb = kbMaps.unshift.bind(kbMaps)
2148 El.rmKb = function(map) {
2149 var i = kbMaps.indexOf(map||kbMaps[0])
2150 if (i > -1) kbMaps.splice(i, 1)
2151 }
2152
2153 addEvent(document, "keydown", kbDown)
2154 //*/
2155
2156
2157 //** responsive
2158 var lastSize, lastOrient
2159 , breakpoints = {
2160 sm: 0,
2161 md: 601,
2162 lg: 1025
2163 }
2164 , setBreakpointsRated = function() {
2165 setBreakpoints()
2166 }.rate(100, true)
2167
2168 function setBreakpoints(_breakpoints) {
2169 // document.documentElement.clientWidth is 0 in IE5
2170 var key, next
2171 , width = root.offsetWidth
2172 , map = breakpoints = _breakpoints || breakpoints
2173
2174 for (key in map) {
2175 if (map[key] > width) break
2176 next = key
2177 }
2178
2179 if ( next != lastSize ) {
2180 _rmClass(root, lastSize)
2181 _addClass(root, lastSize = next)
2182 }
2183
2184 next = width > root.offsetHeight ? "landscape" : "portrait"
2185
2186 if ( next != lastOrient) {
2187 _rmClass(root, lastOrient)
2188 _addClass(root, lastOrient = next)
2189 }
2190
2191 next = window.View
2192 if (next) next.emit("resize")
2193 }
2194 El.setBreakpoints = setBreakpoints
2195
2196 setBreakpointsRated()
2197
2198 addEvent(window, "resize", setBreakpointsRated)
2199 addEvent(window, "orientationchange", setBreakpointsRated)
2200 addEvent(window, "load", setBreakpointsRated)
2201 //*/
2202
2203
2204 //** i18n
2205 function i18n(text, lang) {
2206 lang = i18n[i18nGet(lang) || currentLang]
2207 return (
2208 lang[text] ||
2209 typeof text === "string" && lang[text = text.slice(text.indexOf(":") + 1) || text] ||
2210 text || ""
2211 )
2212 }
2213 El.i18n = i18n
2214
2215 function i18nGet(lang) {
2216 return lang && (
2217 i18n[lang = ("" + lang).toLowerCase()] ||
2218 i18n[lang = lang.split("-")[0]]
2219 ) && lang
2220 }
2221
2222 function i18nUse(lang) {
2223 lang = i18nGet(lang)
2224 if (lang && currentLang != lang) {
2225 i18n[currentLang = i18n.current = lang] = i18n[currentLang] || {}
2226 }
2227 return currentLang
2228 }
2229
2230 function i18nAdd(lang, texts) {
2231 if (i18n.list.indexOf(lang) == -1) i18n.list.push(lang)
2232 JSON.merge(i18n[lang] || (i18n[lang] = {}), texts)
2233 if (!currentLang) i18nUse(lang)
2234 }
2235
2236 i18n.list = []
2237 i18n.get = i18nGet
2238 i18n.use = i18nUse
2239 i18n.add = i18nAdd
2240 i18n.def = function(map, key) {
2241 for (key in map) {
2242 i18nAdd(key, map)
2243 }
2244 }
2245 // navigator.userLanguage for IE, navigator.language for others
2246 // var lang = navigator.language || navigator.userLanguage;
2247 // i18nUse("en")
2248 //*/
2249
2250}(window, document, Object, Event, "prototype")
2251/* litejs.com/MIT-LICENSE.txt */
2252
2253
2254
2255!function(bindings) {
2256 var hasOwn = Object.prototype.hasOwnProperty
2257 , slice = Array.prototype.slice
2258
2259 bindingEvery.once =
2260 emitForm.once =
2261 bindingFn.once =
2262 bindingOn.once =
2263 bindingsEach.raw = bindingsEach.once =
2264 true
2265
2266 bindings.every = bindingEvery
2267 function bindingEvery(el, list, attrName) {
2268 var len = 0
2269 , data = this
2270 , parent = el.parentNode
2271 , comm = document.createComment("every " + (list.name || list.length))
2272
2273 parent.replaceChild(comm, el)
2274
2275 if (list) {
2276 if (typeof list === "string") {
2277 data.model.on("change:" + list, render)
2278 render()
2279 } else if (list.eachLive) {
2280 list.eachLive(add, remove)
2281 } else {
2282 comm.render = render
2283 render()
2284 }
2285 }
2286 return true
2287
2288 function render() {
2289 for (; len; len--) {
2290 El.kill(comm.previousSibling)
2291 }
2292 Object.each(typeof list === "string" ? data.model.get(list) : list, add)
2293 }
2294
2295 function add(item, i) {
2296 len++
2297 var up
2298 , clone = el.cloneNode(true)
2299 , scope = El.scope(clone, data)
2300 scope.i = i
2301 scope[attrName || "item"] = item
2302 El.append(parent, clone, comm)
2303 El.render(clone, scope)
2304 if (typeof item.on === "function") {
2305 item.on("change", up = El.render.bind(clone, clone))
2306 El.on(clone, "kill", function() {
2307 item.off("change", up)
2308 })
2309 }
2310 }
2311
2312 function remove(pos) {
2313 for (var el = comm, i = pos + 1; i--; ) {
2314 el = el.previousSibling
2315 }
2316 El.kill(el)
2317 }
2318 }
2319
2320 bindings.fn = bindingFn
2321 function bindingFn(el, fn) {
2322 return fn.apply(el, slice.call(arguments, 3))
2323 }
2324
2325 bindings["if"] = bindingsIf
2326 function bindingsIf(el, enabled) {
2327 var parent = el.parentNode
2328 , scope = this
2329 if (enabled) {
2330 parent || el._ifComm && el._ifComm.parentNode.replaceChild(el, el._ifComm)
2331 } else {
2332 if (parent) {
2333 if (!el._ifComm) {
2334 El.on(el, "kill", El.kill.bind(el, el._ifComm = document.createComment("if")))
2335 el._ifComm.render = function() {
2336 El.render(el, scope)
2337 }
2338 }
2339 parent.replaceChild(el._ifComm, el)
2340 }
2341 return true
2342 }
2343 }
2344
2345 bindings.is = function bindingIs(node, model, path, list) {
2346 var i, match, val
2347 , scope = this
2348 if (typeof model === "string") {
2349 list = path
2350 path = model
2351 model = scope.model
2352 }
2353 if (model && path) {
2354 match = val = model.get(path)
2355 if (list) {
2356 if (!Array.isArray(list)) {
2357 list = list.split(",")
2358 }
2359 i = list.length & -2
2360
2361 for (; i > -1; i -= 2) {
2362 if (i == 0 || list[i - 1] == "" + val || +list[i - 1] <= val) {
2363 match = list[i]
2364 break
2365 }
2366 }
2367 }
2368 El.rmClass(node, scope["_is-" + path])
2369 El.addClass(node, scope["_is-" + path] = match && "is-" + match)
2370 }
2371 }
2372
2373 bindings.on = bindingOn
2374 function bindingOn(el, ev, fn, a1, a2, a3, a4, a5) {
2375 El.on(el, ev, typeof fn == "string" ? function(e) {
2376 View.emit(fn, e, el, a1, a2, a3, a4, a5)
2377 } : fn)
2378 }
2379
2380 bindings.emitForm = emitForm
2381 function emitForm(el, ev, a1, a2, a3, a4) {
2382 El.on(el, "submit", function(e) {
2383 var data = El.val(el)
2384 View.emit(ev, e, data, a1, a2, a3, a4)
2385 return Event.stop(e)
2386 })
2387 }
2388
2389 function getChilds(node) {
2390 var child
2391 , childs = node._childs
2392 if (!childs) {
2393 for (node._childs = childs = []; child = node.firstChild;) {
2394 childs.push(child);
2395 node.removeChild(child)
2396 }
2397 }
2398 return childs
2399 }
2400
2401 bindings.each = bindingsEach
2402
2403 function bindingsEach(el, expr) {
2404 var node = el
2405 , child = getChilds(node)[0]
2406 , match = /^\s*(\w+) in (\w*)(.*)/.exec(expr)
2407 , fn = "with(data){var out=[],loop={i:0,offset:0},_1,_2=" + match[2]
2408 + match[3].replace(/ (limit|offset):\s*(\d+)/ig, ";loop.$1=$2")
2409 + ";if(_2)for(_1 in _2)if(hasOwn.call(_2,_1)&&!(loop.offset&&loop.offset--)){"
2410 + "loop.i++;"
2411 + "if(loop.limit&&loop.i-loop.offset>loop.limit)break;"
2412 + "var clone=el.cloneNode(true)"
2413 + ",scope=El.scope(clone,data);"
2414 + "scope.loopKey=loop.key=_1;"
2415 + "scope.loop=loop;"
2416 + "scope." + match[1] + "=_2[_1];"
2417 + "out.push(clone);"
2418 + "};return out}"
2419
2420 var childs = Function("hasOwn,el,data", fn)(hasOwn, child, this)
2421
2422 El.append(El.empty(node), childs)
2423 El.render(node)
2424 return node
2425 }
2426
2427 bindings.focus = function(el) {
2428 el.focus()
2429 }
2430
2431 bindings.href = function(el, url) {
2432 if (url) {
2433 var chr = url.charAt(0)
2434 el.href = chr === "+" || chr === "%" ? "#" + View.url(url) : url
2435 }
2436 }
2437}(El.bindings)
2438/* litejs.com/MIT-LICENSE.txt */
2439
2440
2441
2442El.bindings.list = function(node, list, extra, val) {
2443 var child = node._child
2444 , data = this
2445 , extraLen = 0
2446
2447 if (!child) {
2448 child = node._child = node.removeChild(node.firstChild)
2449 }
2450
2451 if (!list || node._list == list) return
2452
2453 if (node._list) clear()
2454
2455 node._list = data.list = list
2456
2457 El.on(node, "kill", clear)
2458
2459 El.addClass(node, "loading")
2460
2461 if (extra) {
2462 extra.each(clone)
2463 extraLen = extra.length
2464 }
2465
2466 list
2467 .each(clone)
2468 .on("add", clone).on("remove", remove)
2469 .then(function() {
2470 if (val !== void 0 && El.val(node) !== val) {
2471 if (!this.get(val)) {
2472 clone({id:val,name:val}, extraLen)
2473 extraLen++
2474 }
2475 El.val(node, val)
2476 }
2477 El.rmClass(node, "loading")
2478 })
2479
2480 // Do not render childs when list initialized
2481 return true
2482
2483 function clone(item, pos) {
2484 var clone = child.cloneNode(true)
2485 , scope = El.scope(clone, data)
2486 scope.item = item.data || item || {id:item,name:item}
2487 scope.model = item
2488 scope.pos = pos
2489 function up() {
2490 El.render(clone, scope)
2491 }
2492 if (item.on) {
2493 item.on("change", up)
2494 El.on(clone, "kill", function(){
2495 item.off("change", up)
2496 })
2497 }
2498 El.append(node, clone, extraLen + pos)
2499 return El.render(clone, scope)
2500 }
2501
2502 function remove(item, pos) {
2503 El.kill(node.childNodes[extraLen + pos])
2504 }
2505
2506 function clear() {
2507 var list = node._list
2508 El.empty(node)
2509 if (list) {
2510 node._list = null
2511 list.off("add", clone).off("remove", remove)
2512 }
2513 }
2514}
\No newline at end of file