litejs
Version:
Single-page application framework
2,001 lines (1,787 loc) • 62.6 kB
JavaScript
/*
* @version 19.7.1
* @author Lauri Rooden <lauri@rooden.ee>
* @license MIT License
*/
!function(Date, proto) {
var Date$prototype = Date[proto]
, String$prototype = String[proto]
, Number$prototype = Number[proto]
, maskRe = /(\[)((?:\\?.)*?)\]|([YMD])\3\3\3?|([YMDHhmsWSZ])(\4?)|[uUASwoQ]|(["\\\n\r\u2028\u2029])/g
, dateRe = /(\d+)[-.\/](\d+)[-.\/](\d+)/
, timeRe = /(\d+):(\d+)(?::(\d+))?(\.\d+)?(?:\s*(?:(a)|(p))\.?m\.?)?(\s*(?:Z|GMT|UTC)?(?:([-+]\d\d):?(\d\d)?)?)?/i
, fns = Object.create(null)
, aliases = {
sec: "s",
second: "s",
seconds: "s",
min: "m",
minute: "m",
minutes: "m",
hr: "h",
hour: "h",
hours: "h",
day: "D",
days: "D",
week: "W",
weeks: "W",
month: "M",
months: "M",
year: "Y",
years: "Y"
}
, units = {
S: 1,
s: 1000,
m: 60000,
h: 3600000,
D: 86400000,
W: 604800000
}
, tmp1 = new Date()
, tmp2 = new Date()
, map = Date.fnMap = {
w: "Day()||7",
Y: "FullYear()%100",
M: "Month()+1",
D: "Date()",
h: "Hours()",
H: "Hours()%12||12",
m: "Minutes()",
s: "Seconds()",
S: "Milliseconds()"
}
, locales = Date.locales = {
en: {
am: "AM",
pm: "PM",
names: "JanFebMarAprMayJunJulAugSepOctNovDecJanuaryFebruaryMarchAprilMayJuneJulyAugustSeptemberOctoberNovemberDecemberSunMonTueWedThuFriSatSundayMondayTuesdayWednesdayThursdayFridaySaturday".match(/.[a-z]+/g),
masks: {
LT: "hh:mm",
LTS: "hh:mm:ss",
L: "DD/MM/YYYY",
LL: "D MMMM YYYY",
LLL: "D MMMM YYYY hh:mm",
LLLL: "DDDD, D MMMM YYYY hh:mm"
}
}
}
, masks = Date.masks = {
"iso": "UTC:YYYY-MM-DD[T]hh:mm:ss[Z]"
}
Date.makeStr = makeStr
function makeStr(mask, utc) {
var get = "d.get" + (utc ? "UTC" : "")
, setA = "a.setTime(+d+((4-(" + get + map.w + "))*864e5))"
return (utc ? mask.slice(4) : mask).replace(maskRe, function(match, quote, text, MD, single, pad, esc) {
var str = (
esc ? escape(esc).replace(/%u/g, "\\u").replace(/%/g, "\\x") :
quote ? text :
MD == "Y" ? get + "FullYear()" :
MD ? "l.names[" + get + (MD == "M" ? "Month" : "Day" ) + "()+" + (match == "DDD" ? 24 : MD == "D" ? 31 : match == "MMM" ? 0 : 12) + "]" :
match == "u" ? "(d/1000)>>>0" :
match == "U" ? "+d" :
match == "Q" ? "((" + get + "Month()/3)|0)+1" :
match == "A" ? "l[" + get + map.h + ">11?'pm':'am']" :
match == "o" ? setA + ",a" + get.slice(1) + "FullYear()" :
single == "Z" ? "(t=o)?(t<0?((t=-t),'-'):'+')+(t<600?'0':'')+(0|(t/60))" + (pad ? "" : "+':'") + "+((t%=60)>9?t:'0'+t):'Z'" :
single == "W" ? "Math.ceil(((" + setA + "-a.s" + get.slice(3) + "Month(0,1))/864e5+1)/7)" :
get + map[single || match]
)
return quote || esc ? str : '"+(' + (
match == "SS" ? "(t=" + str + ")>9?t>99?t:'0'+t:'00'+t" :
pad && single != "Z" ? "(t=" + str + ")>9?t:'0'+t" :
str
) + ')+"'
})
}
Date$prototype.date = function(_mask, _zone) {
var offset, undef
, date = this
, locale = locales[date._locale || Date._locale || "en"] || locales.en
, mask = locale.masks && locale.masks[_mask] || masks[_mask] || _mask || masks.iso
, zone = _zone == undef ? date._tz || Date._tz : _zone
, utc = mask.slice(0, 4) == "UTC:"
if (zone != undef && !utc) {
offset = 60 * zone
tmp1.setTime(+date + offset * 6e4)
utc = mask = "UTC:" + mask
} else {
offset = utc ? 0 : -date.getTimezoneOffset()
tmp1.setTime(+date)
}
return isNaN(+date) ? "" + date : (
fns[mask] || (fns[mask] = Function("d,a,o,l", 'var t;return "' + makeStr(mask, utc) + '"')))(
tmp1,
tmp2,
offset,
locale
)
}
addFn("add", function(amount, _unit, mask) {
var date = this
, unit = aliases[_unit] || _unit
if (unit == "M" || unit == "Y" && (amount *= 12)) {
unit = date.getUTCDate()
date.setUTCMonth(date.getUTCMonth() + amount)
if (unit > (unit = date.getUTCDate())) {
date.add(-unit, "D")
}
} else if (amount) {
date.setTime(date.getTime() + (amount * (units[unit] || 1)))
}
return mask ? date.date(mask) : date
})
addFn("startOf", function(_unit, mask) {
var date = this
, unit = aliases[_unit] || _unit
if (unit == "Y") {
date.setUTCMonth(0, 1)
unit = "D"
} else if (unit == "M") {
date.setUTCDate(1)
unit = "D"
}
date.setTime(date - (date % (units[unit] || 1)))
return mask ? date.date(mask) : date
})
addFn("endOf", function(unit, mask) {
return this.startOf(unit).add(1, unit).add(-1, "S", mask)
})
addFn("since", function(from, _unit) {
var diff
, date = this
, unit = aliases[_unit] || _unit
if (typeof from == "string") {
from = aliases[from] ? (tmp2.setTime(+date), tmp2.startOf(from)) : from.date()
}
if (units[unit]) {
diff = (date - from) / units[unit]
} else {
diff = date.since("month", "S") - from.since("month", "S")
if (diff) {
tmp1.setTime(+date)
diff /= units.D * tmp1.endOf("M").getUTCDate()
}
diff += 12 * (date.getUTCFullYear() - from.getUTCFullYear()) + date.getUTCMonth() - from.getUTCMonth()
if (unit == "Y") {
diff /= 12
}
}
return diff
})
//*/
/*
* // In Chrome Date.parse("01.02.2001") is Jan
* num = +date || Date.parse(date) || ""+date;
*/
String$prototype.date = function(mask, zoneOut, zoneIn) {
var undef, date, match, year, month
, str = this
if (isNaN(+str)) {
if (match = str.match(dateRe)) {
// Big endian date, starting with the year, eg. 2011-01-31
// Middle endian date, starting with the month, eg. 01/31/2011
// Little endian date, starting with the day, eg. 31.01.2011
year = match[1] > 99 ? 1 : 3
month = Date.middleEndian ? 4 - year : 2
date = new Date(match[year], match[month] - 1, match[6 - month - year])
} else {
date = new Date()
}
// Time
match = str.match(timeRe) || [0, 0, 0]
date.setHours(
match[6] && match[1] < 12 ? +match[1] + 12 :
match[5] && match[1] == 12 ? 0 : match[1],
match[2], match[3]|0, (1000 * match[4])|0
)
// Timezone
if (match[7]) {
zoneIn = (match[8]|0) + ((match[9]|0)/(match[8]<0?-60:60))
}
if (zoneIn != undef) {
date.setTime(date - (60 * zoneIn + date.getTimezoneOffset()) * 60000)
}
return mask ? date.date(mask, zoneOut) : date
}
return (+str).date(mask, zoneOut, zoneIn)
}
Number$prototype.date = function(mask, zoneOut, zoneIn) {
var date
, num = this
if (num < 4294967296) num *= 1000
date = new Date(
zoneIn != date ?
tmp1.setTime(num) - (60 * zoneIn + tmp1.getTimezoneOffset()) * 60000 :
num
)
return mask ? date.date(mask, zoneOut) : date
}
function addFn(method, fn) {
Date$prototype[method] = fn
String$prototype[method] = Number$prototype[method] = function(a, b, c) {
return this.date()[method](a, b, c)
}
}
function makeSetter(method) {
Date[method] = Date$prototype[method] = function(value, mask) {
var date = this
date["_" + method] = value
return mask ? date.date(mask) : date
}
}
makeSetter("tz")
makeSetter("locale")
}(Date, "prototype")
!function(exports) {
var pointerCache = {}
, hasOwn = pointerCache.hasOwnProperty
exports.clone = clone
exports.mergePatch = mergePatch
exports.isObject = isObject
/**
* JSON Merge Patch
* @see https://tools.ietf.org/html/rfc7396
*/
function mergePatch(target, patch, changed, previous, pointer) {
var undef, key, oldVal, val, len, nextPointer
if (isObject(patch)) {
if (!pointer) {
pointer = ""
}
if (!isObject(target)) {
target = {}
}
for (key in patch) if (
undef !== (oldVal = target[key], val = patch[key]) &&
hasOwn.call(patch, key) &&
(
undef == val ?
undef !== oldVal && delete target[key] :
target[key] !== val
)
) {
nextPointer = pointer + "/" + key.replace(/~/g, "~0").replace(/\//g, "~1")
len = changed && isObject(target[key]) && changed.length
if (undef != val) {
target[key] = mergePatch(target[key], val, changed, previous, nextPointer)
}
if (len === false || changed && len != changed.length) {
changed.push(nextPointer)
if (previous && !isObject(oldVal)) {
previous[nextPointer] = oldVal
}
}
}
} else {
if (changed && isObject(target)) {
val = {}
for (key in target) if (hasOwn.call(target, key)) {
val[key] = null
}
mergePatch(target, val, changed, previous, pointer)
}
target = patch
}
return target
}
function clone(obj) {
var temp, key
if (obj && typeof obj == "object") {
// new Date().constructor() returns a string
temp = obj instanceof Date ? new Date(+obj) :
obj instanceof RegExp ? RegExp(obj.source, (""+obj).split("/").pop()) :
obj.constructor()
for (key in obj) if (hasOwn.call(obj, key)) {
temp[key] = clone(obj[key])
}
obj = temp
}
return obj
}
function isObject(obj) {
return !!obj && obj.constructor === Object
}
// `this` refers to the `window` in browser and to the `exports` in Node.js.
}(this.JSON || this)
!function(F) {
// Time to live - Run *onTimeout* if Function not called on time
F.ttl = function(ms, onTimeout, scope) {
var fn = this
, tick = setTimeout(function() {
ms = 0
if (onTimeout) onTimeout()
}, ms)
return function() {
clearTimeout(tick)
if (ms) fn.apply(scope, arguments)
}
}
// Run Function one time after last call
F.once = function(ms, scope) {
var tick, args
, fn = this
return function() {
clearTimeout(tick)
args = arguments
tick = setTimeout(function() {
fn.apply(scope, args)
}, ms)
}
}
// Maximum call rate for Function
// leading edge, trailing edge
F.rate = function(ms, last_call, _scope) {
var tick, args
, fn = this
, scope = _scope
, next = 0
return function() {
var now = Date.now()
clearTimeout(tick)
if (_scope === void 0) scope = this
if (now >= next) {
next = now + ms
fn.apply(scope, arguments)
} else if (last_call) {
args = arguments
tick = setTimeout(function() {
fn.apply(scope, args)
}, next - now)
}
}
}
}(Function.prototype)
!function(exports, Object) {
var undef
, P = "prototype"
, A = Array[P]
, F = Function[P]
, S = String[P]
, N = Number[P]
, slice = F.call.bind(A.slice)
, fns = {}
, hasOwn = fns.hasOwnProperty
, fnRe = /('|")(?:\\?.)*?\1|\/(?:\\?.)+?\/[gim]*|\b(?:false|in|new|null|this|true|typeof|void|function|var|if)\b|\.\w+|\w+:/g
, formatRe = /{(?!\\)((?:("|')(?:\\?.)*?\2|\\}|[^}])*)}/g
, numbersRe = /-?\d+\.?\d*/g
, wordRe = /\b[a-z_$][\w$]*/ig
, unescapeRe = /{\\/g
exports.Fn = Fn
Fn.hold = hold
Fn.wait = wait
// Function extensions
// -------------------
F.extend = function() {
var arg
, fn = this
, i = 0
function wrapper() {
return fn.apply(this, arguments)
}
for (wrapper[P] = Object.create(fn[P]); arg = arguments[i++]; ) {
Object.assign(wrapper[P], arg)
}
wrapper[P].constructor = wrapper
return wrapper
}
// Non-standard
Object.each = function(obj, fn, scope, key) {
if (obj) for (key in obj) {
hasOwn.call(obj, key) && fn.call(scope, obj[key], key, obj)
}
}
// Chrome54, FF47, Edge14, Safari10.1
Object.values = function(obj) {
return Object.keys(obj || {}).map(function(e) {
return obj[e]
})
}
// Non-standard
// IE<9 bug: [1,2].splice(0).join("") == "" but should be "12"
A.remove = arrayRemove
function arrayRemove() {
var arr = this
, len = arr.length
, o = slice(arguments)
, lastId = -1
for (; len--; ) if (~o.indexOf(arr[len])) {
arr.splice(lastId = len, 1)
}
return lastId
}
A.each = A.forEach
// uniq
// first item preserved
A.uniq = function() {
for (var a = this, i = a.length; i--; ) {
if (a.indexOf(a[i]) !== i) a.splice(i, 1)
}
return a
}
A.pushUniq = function(item) {
return this.indexOf(item) < 0 && this.push(item)
}
// THANKS: Oliver Steele - Functional Javascript [http://www.osteele.com/sources/javascript/functional/]
function Fn(expr /*, scope, mask1, ..maskN */) {
var args = []
, arr = expr.match(/[^"']+?->|[\s\S]+$/g)
, scope = slice(arguments, 1)
, key = scope.length + ":" + expr
, fn = fns[key]
if (!fn) {
fn = expr.replace(fnRe, "").match(wordRe) || []
for (; arr.length > 1; ) {
expr = arr.pop()
args = arr.pop().match(/\w+/g) || []
arrayRemove.apply(fn, args)
if (arr.length) {
arr.push("function(" + args + "){return(" + expr + ")}" + (scope[0] ? ".bind(this)" : ""))
}
}
expr = "return(" + expr + ")"
if (scope[0]) {
arr = Object.keys(scope).map(Fn("a->'__'+a"))
arr[0] = "this"
expr = (
fn[0] ?
"var " + fn.uniq().join("='',") + "='';" :
""
) + "with(" + arr.join(")with(") + "){" + expr + "}"
args = arr.slice(1).concat(args)
}
fn = fns[key] = Function(args, expr)
}
return scope.length ? fn.bind.apply(fn, scope) : fn
}
Fn.keys = function(str) {
var i, tmp
, arr = []
, match = str.match(formatRe)
if (match) {
for (i = match.length; i--; ) {
if (tmp = match[i].replace(fnRe, "").match(wordRe)) {
arr.push.apply(arr, tmp)
}
}
}
return arr.uniq()
}
S.format = function() {
var args = A.slice.call(arguments)
args.unshift(0)
return this.replace(formatRe, function(_, arg) {
args[0] = arg.replace(/\\}/g, "}")
return Fn.apply(null, args)()
}).replace(unescapeRe, "{")
}
N.format = function(data) {
return "" + this
}
S.safe = function() {
return this
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/\"/g, """)
}
S.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1)
}
S.lower = S.toLowerCase
S.upper = S.toUpperCase
N.step = function(a, add) {
var x = ("" + a).split(".")
, steps = this / a
, n = ~~(steps + ((steps < 0 ? -1 : 1) * (add == undef ? .5 : add === 1 && steps == (steps|0) ? 0 : +add))) * a
return "" + (1 in x ? n.toFixed(x[1].length) : n)
}
S.step = function(a, add) {
return this.replace(numbersRe, function(num) {
return (+num).step(a, add)
})
}
N.scale = words([1000, 1000, 1000], ["","k","M","G"], {"default": "{n}{u}"})
S.scale = function() {
return this.replace(numbersRe, function(num) {
return (+num).scale()
})
}
S.pick = N.pick = function() {
var val = this + "="
for (var s, a = arguments, i = 0, len = a.length; i < len;) {
s = a[i++]
if (s.indexOf(val) == 0) {
s = s.slice(val.length)
i = len
}
}
return s.replace("#", this)
}
S.plural = N.plural = function() {
// Plural-Forms: nplurals=2; plural=n != 1;
// http://www.gnu.org/software/gettext/manual/html_mono/gettext.html#Plural-forms
return arguments[ +Fn("n->" + (String.plural || "n!=1"))( parseFloat(this) ) ].replace("#", this)
}
A.pluck = function(name) {
for (var arr = this, i = arr.length, out = []; i--; ) {
out[i] = arr[i][name]
}
return out
}
function words(steps, units, strings, overflow) {
return function(input) {
var n = +(arguments.length ? input : this)
, i = 0
, s = strings || {"default": "{n} {u}{s}"}
for (; n>=steps[i]; ) {
n /= steps[i++]
}
if (i == steps.length && overflow) {
return overflow(this)
}
i = units[i]
return (s[n < 2 ? i : i + "s"] || s["default"]).format({n: n, u: i, s: n < 2 ? "" : "s"})
}
}
Fn.words = words
function wait(fn) {
var pending = 1
function resume() {
if (!--pending && fn) fn.call(this)
}
resume.wait = function() {
pending++
return resume
}
return resume
}
function hold(ignore) {
var k
, obj = this
, hooks = []
, hooked = []
, _resume = wait(resume)
ignore = ignore || obj.syncMethods || []
for (k in obj) if (typeof obj[k] == "function" && ignore.indexOf(k) == -1) !function(k) {
hooked.push(k, hasOwn.call(obj, k) && obj[k])
obj[k] = function() {
hooks.push(k, arguments)
return obj
}
}(k)
/**
* `wait` is already in hooked array,
* so override hooked method
* that will be cleared on resume.
*/
obj.wait = _resume.wait
return _resume
function resume() {
for (var v, scope = obj, i = hooked.length; i--; i--) {
if (hooked[i]) obj[hooked[i-1]] = hooked[i]
else delete obj[hooked[i-1]]
}
// i == -1 from previous loop
for (; v = hooks[++i]; ) {
scope = scope[v].apply(scope, hooks[++i]) || scope
}
hooks = hooked = null
}
}
}(this, Object)
!function(exports) {
var empty = []
exports.Emitter = EventEmitter
exports.asEmitter = asEmitter
function EventEmitter() {}
function asEmitter(obj) {
obj.on = on
obj.off = off
obj.one = one
obj.emit = emit
obj.listen = listen
obj.unlisten = unlisten
}
asEmitter(EventEmitter.prototype)
function on(type, fn, scope, _origin) {
var emitter = this === exports ? empty : this
, events = emitter._e || (emitter._e = Object.create(null))
if (type && fn) {
if (typeof fn === "string") fn = emit.bind(null, fn)
emit.call(emitter, "newListener", type, fn, scope, _origin)
;(events[type] || (events[type] = [])).unshift(scope, _origin, fn)
}
return emitter
}
function off(type, fn, scope) {
var i, args
, emitter = this === exports ? empty : this
, events = emitter._e && emitter._e[type]
if (events) {
for (i = events.length - 2; i > 0; i -= 3) {
if ((events[i + 1] === fn || events[i] === fn) && events[i - 1] == scope) {
args = events.splice(i - 1, 3)
emit.call(emitter, "removeListener", type, args[2], args[0], args[1])
if (fn) break
}
}
}
return emitter
}
function one(type, fn, scope) {
var emitter = this === exports ? empty : this
function remove() {
emitter.off(type, fn, scope).off(type, remove, scope)
}
return emitter.on(type, remove, scope).on(type, fn, scope)
}
// emitNext
// emitLate
function emit(type) {
var args, i
, emitter = this === exports ? empty : this
, _e = emitter._e
, arr = _e ? (_e[type] || empty).concat(_e["*"] || empty) : empty
_e = 0
if (i = arr.length) {
for (args = arr.slice.call(arguments, 1); i--; ) {
arr[i--].apply(arr[--i] || emitter, args)
_e++
}
}
return _e
}
function listen(emitter, ev, fn, scope, _origin) {
if (emitter) {
emitter.on(ev, fn, scope)
;(this._l || (this._l = [])).push([emitter, ev, fn, scope, _origin])
}
return this
}
function unlisten(key) {
var a, i
, listening = this._l
if (listening) for (i = listening.length; i--; ) {
a = listening[i]
if (key === "*" || a.indexOf(key) > -1) {
listening.splice(i, 1)
a[0].off(a[1], a[2], a[3])
}
}
return this
}
// `this` refers to the `window` in browser and to the `exports` in Node.js.
}(this.Event || this)
/* litejs.com/MIT-LICENSE.txt */
!function(window, document, history, location) {
var cb, base, lastRoute, iframe, tick, last
, cleanRe = /^[#\/\!]+|[\s\/]+$/g
// The JScript engine used in IE doesn't recognize vertical tabulation character
// http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
// oldIE = "\v" == "v"
//
// The documentMode is an IE only property, supported in IE8+.
//
// Starting in Internet Explorer 9 standards mode, Internet Explorer 10 standards mode,
// and win8_appname_long apps, you cannot identify the browser as Internet Explorer
// by testing for the equivalence of the vertical tab (\v) and the "v".
// In earlier versions, the expression "\v" === "v" returns true.
// In Internet Explorer 9 standards mode, Internet Explorer 10 standards mode,
// and win8_appname_long apps, the expression returns false.
, ie6_7 = !+"\v1" && (document.documentMode | 0) < 8
function getUrl(_loc) {
var url
/*** PUSH ***/
if (base) {
url = location.pathname.slice(base.length)
} else {
/**/
// bug in Firefox where location.hash is decoded
// bug in Safari where location.pathname is decoded
// var hash = location.href.split('#')[1] || '';
// https://bugs.webkit.org/show_bug.cgi?id=30225
// https://github.com/documentcloud/backbone/pull/967
url = (_loc || location).href.split("#")[1] || ""
/*** PUSH ***/
}
/**/
return url.replace(cleanRe, "")
}
function setUrl(url, replace) {
/*** PUSH ***/
if (base) {
history[replace ? "replaceState" : "pushState"](null, null, base + url)
} else {
/**/
location[replace ? "replace" : "assign"]("#" + url)
// Opening and closing the iframe tricks IE7 and earlier
// to push a history entry on hash-tag change.
if (iframe && getUrl() !== getUrl(iframe.location) ) {
iframe.location[replace ? "replace" : iframe.document.open().close(), "assign"]("#" + url)
}
/*** PUSH ***/
}
/**/
checkUrl()
}
function checkUrl() {
if (lastRoute != (lastRoute = getUrl()) && cb) {
cb(lastRoute)
}
}
history.getUrl = getUrl
history.setUrl = setUrl
history.start = function(_cb) {
cb = _cb
/*** PUSH ***/
// Chrome5, Firefox4, IE10, Safari5, Opera11.50
var url
, _base = document.documentElement.getElementsByTagName("base")[0]
if (_base) _base = _base.href.replace(/.*:\/\/[^/]*|[^\/]*$/g, "")
if (_base && !history.pushState) {
url = location.pathname.slice(_base.length)
if (url) {
location.replace(_base + "#" + url)
}
}
if (_base && history.pushState) {
base = _base
url = location.href.split("#")[1]
if (url && !getUrl()) {
setUrl(url, 1)
}
// Chrome and Safari emit a popstate event on page load, Firefox doesn't.
// Firing popstate after onload is as designed.
//
// See the discussion on https://bugs.webkit.org/show_bug.cgi?id=41372,
// https://code.google.com/p/chromium/issues/detail?id=63040
// and the change to the HTML5 spec that was made:
// http://html5.org/tools/web-apps-tracker?from=5345&to=5346.
window.onpopstate = checkUrl
} else
/**/
if ("onhashchange" in window && !ie6_7) {
// There are onhashchange in IE7 but its not get emitted
//
// Basic support:
// Chrome 5.0, Firefox 3.6, IE 8, Opera 10.6, Safari 5.0
window.onhashchange = checkUrl
} else {
if (ie6_7 && !iframe) {
// IE<9 encounters the Mixed Content warning when the URI javascript: is used.
// IE5/6 additionally encounters the Mixed Content warning when the URI about:blank is used.
// src="//:"
iframe = document.body.appendChild(document.createElement('<iframe class="hide" tabindex="-1">')).contentWindow
}
clearInterval(tick)
tick = setInterval(function(){
var cur = getUrl()
if (iframe && last === cur) cur = getUrl(iframe.location)
if (last !== cur) {
last = cur
iframe ? setUrl(cur) : checkUrl()
}
}, 60)
}
checkUrl()
}
}(this, document, history, location)
/* litejs.com/MIT-LICENSE.txt */
!function(exports) {
var fn, lastView, lastParams, lastStr, lastUrl, syncResume
, isArray = Array.isArray
, capture = 1
, fnStr = ""
, reStr = ""
, views = View.views = {}
, paramCb = {}
, hasOwn = views.hasOwnProperty
, escapeRe = /[.*+?^=!:${}()|\[\]\/\\]/g
, parseRe = /\{([\w%.]+?)\}|.[^{\\]*?/g
exports.View = View
function View(route, el, parent) {
var view = views[route]
if (view) {
if (el) {
view.el = el
view.parent = parent && View(parent)
}
return view
}
view = this
if (!(view instanceof View)) return new View(route, el, parent)
views[view.route = route] = view
view.el = el
view.parent = parent && View(parent)
if (route.charAt(0) != "#") {
var params = "m[" + (view.seq = capture++) + "]?("
, _re = route.replace(parseRe, function(_, key) {
return key ?
(params += "o['" + key + "']=m[" + (capture++) + "],") && "([^/]+?)" :
_.replace(escapeRe, "\\$&")
})
fnStr += params + "'" + route + "'):"
reStr += (reStr ? "|(" : "(") + _re + ")"
fn = 0
}
}
View.prototype = {
show: function(_params) {
var parent
, params = lastParams = _params || {}
, view = lastView = this
, tmp = params._v || view
, close = view.isOpen && view
View.active = view.route
for (; tmp; tmp = parent) {
syncResume = params._v = tmp
tmp.emit("ping", params)
syncResume = null
if (lastParams != params) return
if (parent = tmp.parent) {
if (parent.child && parent.child != tmp) {
close = parent.child
}
parent.child = tmp
}
if (!tmp.el) {
if (tmp.file) {
xhr.load(
tmp.file
.replace(/^|,/g, "$&" + (View.base || ""))
.split(","),
view.wait()
)
tmp.file = null
} else {
View("404").show(Object.assign({}, params))
}
return
}
}
for (tmp in params) if (tmp.charAt(0) != "_") {
if (syncResume = hasOwn.call(paramCb, tmp) && paramCb[tmp] || paramCb["*"]) {
syncResume.call(view, params[tmp], tmp, params)
syncResume = null
}
}
bubbleDown(params, close)
},
wait: function() {
var params = lastParams
params._p = 1 + (params._p | 0)
return function() {
if (--params._p || lastParams != params || syncResume) return
if (params._d) {
bubbleDown(params)
} else if (params._v) {
lastView.show(params)
}
}
}
}
function bubbleDown(params, close) {
var tmp
, view = params._v
, parent = view && view.parent
if (!view || params._p && /{/.test(view.route)) {
return closeView(close)
}
if (parent && !view.isOpen || view === close) {
closeView(close, view)
El.scope(
view.isOpen = view.el.cloneNode(true),
El.scope(tmp = parent.isOpen || parent.el)
)
El.append(tmp, view.isOpen)
El.render(view.isOpen)
parent.emit("openChild", view, close)
view.emit("open", params)
View.emit("open", params, view)
if (view.kb) El.addKb(view.kb)
close = null
}
if (params._d = params._v = view.child) {
bubbleDown(params, close)
}
if (lastView == view) {
view.emit("show", params)
View.emit("show", params, view)
blur()
}
}
function closeView(view, open) {
if (view && view.isOpen) {
view.parent.emit("closeChild", view, open)
closeView(view.child)
El.kill(view.isOpen)
view.isOpen = null
if (view.kb) El.rmKb(view.kb)
view.emit("close")
}
}
Event.asEmitter(View)
Event.asEmitter(View.prototype)
View.base = "view/"
View.home = "home"
View.get = get
function get(url, params) {
if (!fn) {
fn = Function(
"var r=/^\\/?(?:" + reStr + ")[\\/\\s]*$/;" +
"return function(i,o,d){var m=r.exec(i);return m!==null?(" + fnStr + "d):d}"
)()
}
return View(fn(url || View.home, params || {}, "404"))
}
View.show = function(url, _params) {
if (url === true) {
url = lastUrl
lastUrl = 0
}
var params = _params || {}
, view = get(url, params)
if (!view.isOpen || lastUrl != url) {
params._u = lastUrl = url
view.show(El.data.route = params)
}
}
View.param = function(name, cb, re) {
;(isArray(name) ? name : name.split(/\s+/)).forEach(function(n) {
paramCb[n] = cb
})
}
View.def = function(str) {
for (var match, re = /(\S+) (\S+)/g; match = re.exec(str);) {
match[1].split(",").map(function(view) {
view = View(defMap(view, lastStr))
view.file = (view.file ? view.file + "," : "") +
match[2].split(",").map(function(file) {
return views[file] ? views[file].file : defMap(file, lastStr)
})
})
}
}
View.blur = blur
function blur() {
// When a View completes, blur focused link
// IE8 can throw an exception for document.activeElement.
try {
var el = document.activeElement
, tag = el && el.tagName
if (tag === "A" || tag === "BUTTON") el.blur()
} catch(e) {}
}
View.url = defMap
function defMap(str, _last) {
var chr = str.charAt(0)
, slice = str.slice(1)
, last = _last || lastUrl
return (
chr === "+" ? last + slice :
chr === "%" ? ((chr = last.lastIndexOf(slice.charAt(0))), (chr > 0 ? last.slice(0, chr) : last)) + slice :
(lastStr = str)
)
}
}(this)
/* litejs.com/MIT-LICENSE.txt */
!function(window, document, Object, Event, protoStr) {
var currentLang, styleNode
, BIND_ATTR = "data-bind"
, isArray = Array.isArray
, seq = 0
, elCache = El.cache = {}
, wrapProto = []
, slice = wrapProto.slice
, hasOwn = elCache.hasOwnProperty
, body = document.body
, root = document.documentElement
, txtAttr = El.T = "textContent" in body ? "textContent" : "innerText"
, templateRe = /^([ \t]*)(@?)((?:("|')(?:\\?.)*?\4|[-\w:.#[\]]=?)*)[ \t]*([>&^|\\\/=]?)(([\])}]?).*?([[({]?))$/gm
, renderRe = /[;\s]*(\w+)(?:\s*(:?):((?:(["'\/])(?:\\?.)*?\3|[^;])*))?/g
, splitRe = /[,\s]+/
, camelRe = /\-([a-z])/g
, camelFn = function(_, a) {
return a.toUpperCase()
}
, bindings = El.bindings = {
attr: setAttr,
cls: El.cls = acceptMany(cls),
css: El.css = acceptMany(function(el, key, val) {
el.style[key.replace(camelRe, camelFn)] = "" + val || ""
}, function(el, key) {
return getComputedStyle(el).getPropertyValue(key)
}),
data: function(el, key, val) {
setAttr(el, "data-" + key, val)
},
html: function(el, html) {
el.innerHTML = html
},
ref: function(el, name) {
this[name] = el
},
txt: El.txt = function(el, txt) {
// In Safari 2.x, innerText results an empty string
// when style.display=="none" or node is not in dom
//
// innerText is implemented in IE4, textContent in IE9
// Opera 9-10 have Node.text
if (el[txtAttr] !== txt) el[txtAttr] = txt
},
val: function(el, txt) {
valFn(el, txt)
},
"with": function(el, map) {
var scope = elScope(el, this)
Object.assign(scope, map)
if (scope !== this) {
render(el)
return true
}
}
}
, bindMatch = []
, scopeData = El.data = {
_: i18n,
_b: bindings,
El: El,
history: history,
View: View
}
/*** ie8 ***/
// JScript engine in IE<9 does not recognize vertical tabulation character
, ie678 = !+"\v1"
, ie67 = ie678 && (document.documentMode | 0) < 8
, matches = El.matches = body.matches ?
function(el, sel) {
return el && el.matches(sel)
} :
function(el, sel) {
return !!selectorFn(sel)(el)
}
, closest = El.closest = body.closest ?
function(el, sel) {
return (el.closest ? el : el.parentNode).closest(sel)
} :
function(el, sel) {
return walk("parentNode", 1, el, sel)
}
, selectorRe = /([.#:[])([-\w]+)(?:\((.+?)\)|([~^$*|]?)=(("|')(?:\\?.)*?\6|[-\w]+))?]?/g
, selectorLastRe = /([~\s>+]*)(?:("|')(?:\\?.)*?\2|\(.+?\)|[^\s+>])+$/
, selectorSplitRe = /\s*,\s*(?=(?:[^'"()]|"(?:\\?.)*?"|'(?:\\?.)*?'|\(.+?\))+$)/
, selectorCache = {}
, selectorMap = {
"first-child": "(a=_.parentNode)&&a.firstChild==_",
"last-child": "(a=_.parentNode)&&a.lastChild==_",
".": "~_.className.split(/\\s+/).indexOf(a)",
"#": "_.id==a",
"^": "!a.indexOf(v)",
"|": "a.split('-')[0]==v",
"$": "a.slice(-v.length)==v",
"~": "~a.split(/\\s+/).indexOf(v)",
"*": "~a.indexOf(v)"
}
function selectorFn(str) {
// jshint evil:true
return selectorCache[str] ||
(selectorCache[str] = Function("m,c", "return function(_,v,a,b){return " +
str.split(selectorSplitRe).map(function(sel) {
var relation, from
, rules = ["_&&_.nodeType==1"]
, parentSel = sel.replace(selectorLastRe, function(_, _rel, a, start) {
from = start + _rel.length
relation = _rel.trim()
return ""
})
, tag = sel.slice(from).replace(selectorRe, function(_, op, key, subSel, fn, val, quotation) {
rules.push(
"((v='" +
(subSel || (quotation ? val.slice(1, -1) : val) || "").replace(/'/g, "\\'") +
"'),(a='" + key + "'),1)"
,
selectorMap[op == ":" ? key : op] ||
"(a=_.getAttribute(a))" +
(fn ? "&&" + selectorMap[fn] : val ? "==v" : "")
)
return ""
})
if (tag && tag != "*") rules[0] += "&&_.tagName=='" + tag.toUpperCase() + "'"
if (parentSel) rules.push("(v='" + parentSel + "')", selectorMap[relation + relation])
return rules.join("&&")
}).join("||") + "}"
)(matches, closest))
}
function walk(next, first, el, sel, nextFn) {
var out = []
if (typeof sel !== "function") sel = selectorFn(sel)
for (; el; el = el[next] || nextFn && nextFn(el)) if (sel(el)) {
if (first) return el
out.push(el)
}
return first ? null : out
}
function find(node, sel, first) {
return walk("firstChild", first, node.firstChild, sel, function(el) {
var next = el.nextSibling
while (!next && ((el = el.parentNode) !== node)) next = el.nextSibling
return next
})
}
// Note: querySelector in IE8 supports only CSS 2.1 selectors
if (!ie678 && body.querySelector) {
El.find = function(el, sel) {
return el.querySelector(sel)
}
El.findAll = function(el, sel) {
return new ElWrap(el.querySelectorAll(sel))
}
} else {
El.find = function(el, sel) {
return find(el, sel, true)
}
El.findAll = function(el, sel) {
return new ElWrap(find(el, sel))
}
}
/*/
El.matches = function(el, sel) {
return el.matches(sel)
}
El.closest = function(el, sel) {
return (el.closest ? el : el.parentNode).closest(sel)
}
El.find = function(el, sel) {
return el.querySelector(sel)
}
El.findAll = function(el, sel) {
return new ElWrap(el.querySelectorAll(sel))
}
/**/
/**
* Turns CSS selector like syntax to DOM Node
* @returns {Node}
*
* @example
* El("input#12.nice[type=checkbox]:checked:disabled[data-lang=en].class")
* <input id="12" class="nice class" type="checkbox" checked="checked" disabled="disabled" data-lang="en">
*/
window.El = El
function El(name) {
if (typeof name != "string") {
return new ElWrap(name)
}
var el, pres
, pre = {}
name = name.replace(selectorRe, function(_, op, key, _sub, fn, val, quotation) {
pres = 1
val = quotation ? val.slice(1, -1) : val || key
pre[op =
op == "." ?
(fn = "~", "class") :
op == "#" ?
"id" :
key
] = fn && pre[op] ?
fn == "^" ? val + pre[op] :
pre[op] + (fn == "~" ? " " : "") + val :
val
return ""
}) || "div"
// NOTE: IE-s cloneNode consolidates the two text nodes together as one
// http://brooknovak.wordpress.com/2009/08/23/ies-clonenode-doesnt-actually-clone/
el = (elCache[name] || (elCache[name] = document.createElement(name))).cloneNode(true)
if (pres) {
setAttr(el, pre)
}
return el
}
function ElWrap(nodes) {
var wrap = this
, i = nodes.length
/**
* 1. Extended array size will not updated
* when array elements set directly in Android 2.2.
*/
if (i) {
wrap.length = i /* 1 */
for (; i--; ) {
wrap[i] = nodes[i]
}
} else if (i == null) {
wrap.length = 1 /* 1 */
wrap[0] = nodes
}
}
ElWrap[protoStr] = wrapProto
wrapProto.append = function(el) {
var elWrap = this
if (elWrap._childId != void 0) {
append(elWrap[elWrap._childId], el)
} else {
elWrap.push(el)
}
return elWrap
}
wrapProto.cloneNode = function(deep) {
var clone = new ElWrap(this.map(function(el) {
return el.cloneNode(deep)
}))
clone._childId = this._childId
return clone
}
El.attr = function(el, key, val) {
return arguments.length < 3 && key.constructor != Object ? getAttr(el, key) : setAttr(el, key, val)
}
function getAttr(el, key) {
return el && el.getAttribute && el.getAttribute(key)
}
function setAttr(el, key, val) {
var current
if (key && key.constructor == Object) {
for (current in key) {
setAttr(el, current, key[current])
}
return
}
/* Accept namespaced arguments
var namespaces = {
xlink: "http://www.w3.org/1999/xlink",
svg: "http://www.w3.org/2000/svg"
}
current = key.split("|")
if (current[1]) {
el.setAttributeNS(namespaces[current[0]], current[1], val)
return
}
*/
current = el.getAttribute(key)
// Note: IE5-7 doesn't set styles and removes events when you try to set them.
//
// in IE6, a label with a for attribute linked to a select list
// will cause a re-selection of the first option instead of just giving focus.
// http://webbugtrack.blogspot.com/2007/09/bug-116-for-attribute-woes-in-ie6.html
// there are bug in IE<9 where changed 'name' param not accepted on form submit
// IE8 and below support document.createElement('<P>')
//
// http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
// http://msdn.microsoft.com/en-us/library/ms536614(VS.85).aspx
/*** ie8 ***/
// istanbul ignore next: IE fix
if (ie67 && (key == "id" || key == "name" || key == "checked")) {
el.mergeAttributes(document.createElement('<INPUT ' + key + '="' + val + '">'), false)
} else
/**/
if (key == "class") {
cls(el, val)
} else if (val || val === 0) {
if (current != val) {
el.setAttribute(key, val)
}
} else if (current) {
el.removeAttribute(key)
}
}
El.val = valFn
function valFn(el, val) {
var input, step, key, value
, i = 0
, type = el.type
, opts = el.options
, checkbox = type === "checkbox" || type === "radio"
if (el.tagName === "FORM") {
opts = {}
// Disabled controls do not receive focus,
// are skipped in tabbing navigation, cannot be successfully posted.
//
// Read-only elements receive focus but cannot be modified by the user,
// are included in tabbing navigation, are successfully posted.
//
// Read-only checkboxes can be changed by the user
for (; input = el.elements[i++]; ) if (!input.disabled && (key = input.name || input.id)) {
value = valFn(input)
if (value !== void 0) {
step = opts
key.replace(/\[(.*?)\]/g, function(_, _key, offset) {
if (step == opts) key = key.slice(0, offset)
step = step[key] || (step[key] = _key && +_key != _key ? {} : [])
key = _key
})
step[key || step.length] = value
}
}
return opts
}
if (arguments.length > 1) {
if (opts) {
value = (isArray(val) ? val : [ val ]).map(String)
for (; input = opts[i++]; ) {
input.selected = value.indexOf(input.value) > -1
}
} else {
checkbox ? (el.checked = !!val) : (el.value = val)
}
return
}
if (opts) {
if (type === "select-multiple") {
for (val = []; input = opts[i++]; ) {
if (input.selected && !input.disabled) {
val.push(input.valObject || input.value)
}
}
return val
}
// IE8 throws error when accessing to options[-1]
value = el.selectedIndex
el = value > -1 && opts[value] || el
}
return checkbox && !el.checked ?
(type === "radio" ? void 0 : null) :
el.valObject || el.value
}
function append(el, child, before) {
if (!el.nodeType) {
return el.append ? el.append(child, before) : el
}
var fragment
, i = 0
, tmp = typeof child
if (child) {
if (tmp == "string" || tmp == "number") child = document.createTextNode(child)
else if ( !("nodeType" in child) && "length" in child ) {
// document.createDocumentFragment is unsupported in IE5.5
// fragment = "createDocumentFragment" in document ? document.createDocumentFragment() : El("div")
for (
tmp = child.length
, fragment = document.createDocumentFragment();
i < tmp; ) append(fragment, child[i++])
child = fragment
}
if (child.nodeType) {
tmp = el.insertBefore ? el : el[el.length - 1]
if (i = getAttr(tmp, "data-child")) {
before = find(tmp, Fn("v->n->n.nodeType===8&&n.nodeValue==v")(i), 1) || tmp
tmp = before.parentNode
// TODO:2016-07-05:lauri:handle numeric befores
}
/*** debug ***//*
if (tmp.namespaceURI && child.namespaceURI && tmp.namespaceURI !== child.namespaceURI && child.tagName !== "svg") {
console.error("NAMESPACE CHANGE!", tmp.namespaceURI, child.namespaceURI, child)
}
/**/
tmp.insertBefore(child,
(before === true ? tmp.firstChild :
typeof before == "number" ? tmp.childNodes[
before < 0 ? tmp.childNodes.length - before - 2 : before
] : before) || null
)
}
}
return el
}
function acceptMany(fn, getter) {
return function f(el, name, val, delay) {
if (el && name) {
if (delay > 0) return setTimeout(f, delay, el, name, val)
if (name.constructor === Object) {
for (i in name) {
if (hasOwn.call(name, i)) f(el, i, name[i])
}
return
}
var names = isArray(name) ? name : name.split(splitRe)
, i = 0
, len = names.length
if (arguments.length < 3) {
if (getter) return getter(el, name)
for (; i < len; ) fn(el, names[i++])
} else {
/*
if (isArray(val)) {
for (; i < len; ) fn(el, names[i], val[i++])
} else {
for (; i < len; ) fn(el, names[i++], val)
}
/*/
for (; i < len; ) {
fn(el, names[i++], isArray(val) ? val[i - 1] : val)
}
//*/
}
}
}
}
// setAttribute("class") is broken in IE7
// className is object in SVGElements
El.hasClass = hasClass
function hasClass(el, name) {
var current = el.className || ""
if (typeof current !== "string") {
current = el.getAttribute("class") || ""
}
return !!current && current.split(splitRe).indexOf(name) > -1
}
function cls(el, name, set) {
var current = el.className || ""
, useAttr = typeof current !== "string"
if (useAttr) {
current = el.getAttribute("class") || ""
}
if (arguments.length < 3 || set) {
if (current) {
name = current.split(splitRe).indexOf(name) > -1 ? current : current + " " + name
}
} else {
name = current ? (" " + current + " ").replace(" " + name + " ", " ").trim() : current
}
if (current != name) {
if (useAttr) {
el.setAttribute("class", name)
} else {
el.className = name
}
}
}
// The addEventListener is supported in Internet Explorer from version 9.
// https://developer.mozilla.org/en-US/docs/Web/Reference/Events/wheel
// - IE8 always prevents the default of the mousewheel event.
var wheelDiff = 120
, addEv = "addEventListener"
, remEv = "removeEventListener"
, prefix = window[addEv] ? "" : (addEv = "attachEvent", remEv = "detachEvent", "on")
, fixEv = Event.fixEv = {
wheel:
"onwheel" in document ? "wheel" : // Modern browsers
"onmousewheel" in document ? "mousewheel" : // Webkit and IE
"DOMMouseScroll" // older Firefox
}
, fixFn = Event.fixFn = {
wheel: function(el, _fn) {
return function(e) {
var delta = (e.wheelDelta || -e.detail || -e.deltaY) / wheelDiff
if (delta) {
if (delta < 1 && delta > -1) {
var diff = (delta < 0 ? -1 : 1)/delta
delta *= diff
wheelDiff /= diff
}
//TODO: fix event
// e.deltaY =
// e.deltaX = - 1/40 * e.wheelDeltaX|0
// e.target = e.target || e.srcElement
_fn.call(el, e, delta)
}
}
}
}
, passiveEvents = false
try {
window[addEv]("t", null, Object.defineProperty({}, "passive", {
get: function() {
passiveEvents = true
}
}))
} catch (e) {}
Event.passive = passiveEvents
var emitter = new Event.Emitter
function addEvent(el, ev, _fn) {
var fn = fixFn[ev] && fixFn[ev](el, _fn, ev) || _fn
, fix = prefix ? function() {
var b, e = {}
for (b in event) e[b] = event[b]
e.target = e.srcElement
b = e.buttons = e.button
e.button = b == 1 ? 0: b == 4 ? 1 : b
e.preventDefault = preventDefault
e.stopPropagation = stopPropagation
e.type = ev
if (e.clientX !== void 0) {
e.pageX = e.clientX + scrollLeft()
e.pageY = e.clientY + scrollTop()
}
fn.call(el, e)
} : fn
if (fixEv[ev] !== "") {
el[addEv](prefix + (fixEv[ev] || ev), fix, false)
}
emitter.on.call(el, ev, fix, el, _fn)
}
function rmEvent(el, ev, fn) {
var evs = el._e && el._e[ev]
, id = evs && evs.indexOf(fn)
if (id > -1) {
if (fn !== evs[id + 1] && evs[id + 1]._rm) {
evs[id + 1]._rm()
}
el[remEv](prefix + (fixEv[ev] || ev), evs[id + 1])
evs.splice(id - 1, 3)
}
}
function preventDefault() {
event.returnValue = false
}
function stopPropagation() {
event.cancelBubble = event.cancel = true
}
Event.stop = function(e) {
if (e && e.preventDefault) {
e.stopPropagation()
e.preventDefault()
}
return false
}
El.on = acceptMany(addEvent)
El.off = acceptMany(rmEvent)
El.one = function(el, ev, fn) {
function remove() {
rmEvent(el, ev, fn)
rmEvent(el, ev, remove)
}
addEvent(el, ev, fn)
addEvent(el, ev, remove)
return el
}
El.emit = function(el, ev) {
emitter.emit.apply(el, slice.call(arguments, 1))
}
function empty(el) {
for (var node; node = el.firstChild; ) {
kill(node)
}
return el
}
function kill(el) {
var id
if (el) {
if (el._e) {
emitter.emit.call(el, "kill")
for (id in el._e) rmEvent(el, id)
}
if (el.parentNode) {
el.parentNode.removeChild(el)
}
if (el.nodeType != 1) {
return el.kill && el.kill()
}
empty(el)
if (id = el._scope) {
delete elScope[id]
}
if (el.valObject) {
el.valObject = null
}
}
}
function elScope(node, parent, fb) {
return elScope[node._scope] || fb || (
parent ?
(((fb = elScope[node._scope = ++seq] = Object.create(parent))._super = parent), fb) :
closestScope(node)
) || scopeData
}
function closestScope(node) {
for (; node = node.parentNode; ) {
if (node._scope) return elScope[node._scope]
}
}
function render(node, _scope) {
var bind, fn
, scope = elScope(node, 0, _scope)
, i = 0
if (node.nodeType != 1) {
node.render ? node.render(scope) : node
return
}
if (bind = getAttr(node, BIND_ATTR)) {
scope._m = bindMatch
scope._t = bind
// i18n(bind, lang).format(scope)
// document.documentElement.lang
// document.getElementsByTagName('html')[0].getAttribute('lang')
fn = "data b s B r->data&&(" + bind.replace(renderRe, function(match, name, op, args) {
scope._m[i] = match
var fn = bindings[name]
return (
(op == ":" || fn && hasOwn.call(fn, "once")) ?
"s(this,B,data._t=data._t.replace(data._m[" + (i++)+ "],''))||" :
""
) + (
fn ?
"b['" + name + "'].call(data,this" + (fn.raw ? ",'" + args + "'" : args ? "," + args : "") :
"s(this,'" + name + "'," + args
) + ")||"
}) + "r)"
try {
if (Fn(fn, node, scope)(scope, bindings, setAttr, BIND_ATTR)) {
return
}
} catch (e) {
/*** debug ***//*
e.message += "\nBINDING: " + bind
console.error(e, node)
/**/
if (window.onerror) {
window.onerror(e.message, e.fileName, e.lineNumber)
}
}
}
for (bind = node.firstChild; bind; bind = fn) {
fn = bind.nextSibling
render(bind, scope)
}
/*** ie8 ***/
if (ie678 && node.tagName == "SELECT") {
node.parentNode.insertBefore(node, node)
}
/**/
}
El.empty = empty
El.kill = kill
El.render = render
Object.each(El, function(fn, key) {
if (!wrapProto[key]) {
wrapProto[key] = function wrap() {
var i = 0
, self = this
, len = self.length
, arr = slice.call(arguments)
arr.unshift(1)
for (; i < len; ) {
arr[0] = self[i++]
fn.apply(null, arr)
}
return self
}
}
})
El.append = append
El.scope = elScope
function parseTemplate(str) {
var parent = El("div")
, stack = [-1]
, parentStack = []
function work(all, indent, plugin, name, q, op, text, mapEnd, mapStart, offset) {
if (offset && all === indent) return
for (q = indent.length; q <= stack[0]; ) {
if (parent.plugin) {
parent.plugin.done()
}
parent = parentStack.pop()
stack.shift()
}
if (parent._r) {
parent.txt += all + "\n"
} else if (plugin || mapStart && (name = "map")) {
if (El.plugins[name]) {
parentStack.push(parent)
stack.unshift(q)
parent = (new El.plugins[name](parent, op + text, mapEnd ? "" : ";")).el
} else {
append(parent, all)
}
} else if (mapEnd) {
appendBind(parent, text, "")
} else {
if (name) {
parentStack.push(parent)
stack.unshift(q)
q = El(name, 0, 1)
append(parent, parent = q)
}
if (text && op != "/") {
if (op == ">") {
(indent + " " + text).replace(templateRe, work)
} else if (op == "|" || op == "\\") {
append(parent, text) // + "\n")
} else {
if (op != "&" && op != "^") {
text = (parent.tagName == "INPUT" ? "val" : "txt") + (
op == "=" ? ":" + text.replace(/'/g, "\\'") :
":_('" + text.replace(/'/g, "\\'") + "').format(data)"
)
}
appendBind(parent, text, ";", op)
}
}
}
}
str.replace(templateRe, work)
work("", "")
}
function appendBind(el, val, sep, q) {
var current = getAttr(el, BIND_ATTR)
setAttr(el, BIND_ATTR, (current ? (
q == "^" ?
val + sep + current :
current + sep + val
) : val))
}
function plugin(parent, name) {
var t = this
t.name = name
t.parent = parent
t.el = El("div")
t.el.plugin = t
}
plugin[protoStr] = {
_done: function() {
var el, childId
, t = this
, childNodes = t.el.childNodes
, i = childNodes.length
for (; i--; ) {
el = childNodes[i]
if (el._childKey) {
childId = i
setAttr(el, "data-child", el._childKey)
break
}
}
if (childNodes[1]) {
el = new ElWrap(childNodes)
el._childId = childId
} else {
el = childNodes[0]
}
t.el.plugin = t.el = t.parent = null
return el
},
done: function() {
var t = this
, parent = t.parent
elCache[t.name] = t._done()
return parent
}
}
function js(parent, params, attr1) {
var t = this
// Raw text mode
t._r = t.parent = parent
t.txt = ""
t.plugin = t.el = t
t.params = params
t.a = attr1
}
js[protoStr].done = Fn("Function(this.txt)()")
El.plugins = {
binding: js.extend({
done: function() {
Object.assign(bindings, Function("return({" + this.txt + "})")())
}
}),
child: plugin.extend({
done: function() {
var key = "@child-" + (++seq)
, root = this.parent
for (; (root.parentNode.parentNode || key).nodeType == 1; ) {
root = root.parentNode
}
root._childKey = key
append(this.parent, document.createComment(key))
}
}),
css: js.extend({
done: Fn("xhr.css(this.txt)