You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1324 lines
36 KiB
JavaScript
1324 lines
36 KiB
JavaScript
;(function (t) {
|
|
var e =
|
|
(typeof self == 'object' && self.self === self && self) ||
|
|
(typeof global == 'object' && global.global === global && global)
|
|
if (typeof define === 'function' && define.amd) {
|
|
define(['underscore', 'jquery', 'exports'], function (i, n, r) {
|
|
e.Backbone = t(e, r, i, n)
|
|
})
|
|
} else if (typeof exports !== 'undefined') {
|
|
var i = require('underscore'),
|
|
n
|
|
try {
|
|
n = require('jquery')
|
|
} catch (r) {}
|
|
t(e, exports, i, n)
|
|
} else {
|
|
e.Backbone = t(e, {}, e._, e.jQuery || e.Zepto || e.ender || e.$)
|
|
}
|
|
})(function (t, e, i, n) {
|
|
var r = t.Backbone
|
|
var s = Array.prototype.slice
|
|
e.VERSION = '1.4.0'
|
|
e.$ = n
|
|
e.noConflict = function () {
|
|
t.Backbone = r
|
|
return this
|
|
}
|
|
e.emulateHTTP = false
|
|
e.emulateJSON = false
|
|
var a = (e.Events = {})
|
|
var o = /\s+/
|
|
var h
|
|
var u = function (t, e, n, r, s) {
|
|
var a = 0,
|
|
h
|
|
if (n && typeof n === 'object') {
|
|
if (r !== void 0 && 'context' in s && s.context === void 0) s.context = r
|
|
for (h = i.keys(n); a < h.length; a++) {
|
|
e = u(t, e, h[a], n[h[a]], s)
|
|
}
|
|
} else if (n && o.test(n)) {
|
|
for (h = n.split(o); a < h.length; a++) {
|
|
e = t(e, h[a], r, s)
|
|
}
|
|
} else {
|
|
e = t(e, n, r, s)
|
|
}
|
|
return e
|
|
}
|
|
a.on = function (t, e, i) {
|
|
this._events = u(l, this._events || {}, t, e, { context: i, ctx: this, listening: h })
|
|
if (h) {
|
|
var n = this._listeners || (this._listeners = {})
|
|
n[h.id] = h
|
|
h.interop = false
|
|
}
|
|
return this
|
|
}
|
|
a.listenTo = function (t, e, n) {
|
|
if (!t) return this
|
|
var r = t._listenId || (t._listenId = i.uniqueId('l'))
|
|
var s = this._listeningTo || (this._listeningTo = {})
|
|
var a = (h = s[r])
|
|
if (!a) {
|
|
this._listenId || (this._listenId = i.uniqueId('l'))
|
|
a = h = s[r] = new g(this, t)
|
|
}
|
|
var o = c(t, e, n, this)
|
|
h = void 0
|
|
if (o) throw o
|
|
if (a.interop) a.on(e, n)
|
|
return this
|
|
}
|
|
var l = function (t, e, i, n) {
|
|
if (i) {
|
|
var r = t[e] || (t[e] = [])
|
|
var s = n.context,
|
|
a = n.ctx,
|
|
o = n.listening
|
|
if (o) o.count++
|
|
r.push({ callback: i, context: s, ctx: s || a, listening: o })
|
|
}
|
|
return t
|
|
}
|
|
var c = function (t, e, i, n) {
|
|
try {
|
|
t.on(e, i, n)
|
|
} catch (r) {
|
|
return r
|
|
}
|
|
}
|
|
a.off = function (t, e, i) {
|
|
if (!this._events) return this
|
|
this._events = u(f, this._events, t, e, { context: i, listeners: this._listeners })
|
|
return this
|
|
}
|
|
a.stopListening = function (t, e, n) {
|
|
var r = this._listeningTo
|
|
if (!r) return this
|
|
var s = t ? [t._listenId] : i.keys(r)
|
|
for (var a = 0; a < s.length; a++) {
|
|
var o = r[s[a]]
|
|
if (!o) break
|
|
o.obj.off(e, n, this)
|
|
if (o.interop) o.off(e, n)
|
|
}
|
|
if (i.isEmpty(r)) this._listeningTo = void 0
|
|
return this
|
|
}
|
|
var f = function (t, e, n, r) {
|
|
if (!t) return
|
|
var s = r.context,
|
|
a = r.listeners
|
|
var o = 0,
|
|
h
|
|
if (!e && !s && !n) {
|
|
for (h = i.keys(a); o < h.length; o++) {
|
|
a[h[o]].cleanup()
|
|
}
|
|
return
|
|
}
|
|
h = e ? [e] : i.keys(t)
|
|
for (; o < h.length; o++) {
|
|
e = h[o]
|
|
var u = t[e]
|
|
if (!u) break
|
|
var l = []
|
|
for (var c = 0; c < u.length; c++) {
|
|
var f = u[c]
|
|
if ((n && n !== f.callback && n !== f.callback._callback) || (s && s !== f.context)) {
|
|
l.push(f)
|
|
} else {
|
|
var d = f.listening
|
|
if (d) d.off(e, n)
|
|
}
|
|
}
|
|
if (l.length) {
|
|
t[e] = l
|
|
} else {
|
|
delete t[e]
|
|
}
|
|
}
|
|
return t
|
|
}
|
|
a.once = function (t, e, i) {
|
|
var n = u(d, {}, t, e, this.off.bind(this))
|
|
if (typeof t === 'string' && i == null) e = void 0
|
|
return this.on(n, e, i)
|
|
}
|
|
a.listenToOnce = function (t, e, i) {
|
|
var n = u(d, {}, e, i, this.stopListening.bind(this, t))
|
|
return this.listenTo(t, n)
|
|
}
|
|
var d = function (t, e, n, r) {
|
|
if (n) {
|
|
var s = (t[e] = i.once(function () {
|
|
r(e, s)
|
|
n.apply(this, arguments)
|
|
}))
|
|
s._callback = n
|
|
}
|
|
return t
|
|
}
|
|
a.trigger = function (t) {
|
|
if (!this._events) return this
|
|
var e = Math.max(0, arguments.length - 1)
|
|
var i = Array(e)
|
|
for (var n = 0; n < e; n++) i[n] = arguments[n + 1]
|
|
u(v, this._events, t, void 0, i)
|
|
return this
|
|
}
|
|
var v = function (t, e, i, n) {
|
|
if (t) {
|
|
var r = t[e]
|
|
var s = t.all
|
|
if (r && s) s = s.slice()
|
|
if (r) p(r, n)
|
|
if (s) p(s, [e].concat(n))
|
|
}
|
|
return t
|
|
}
|
|
var p = function (t, e) {
|
|
var i,
|
|
n = -1,
|
|
r = t.length,
|
|
s = e[0],
|
|
a = e[1],
|
|
o = e[2]
|
|
switch (e.length) {
|
|
case 0:
|
|
while (++n < r) (i = t[n]).callback.call(i.ctx)
|
|
return
|
|
case 1:
|
|
while (++n < r) (i = t[n]).callback.call(i.ctx, s)
|
|
return
|
|
case 2:
|
|
while (++n < r) (i = t[n]).callback.call(i.ctx, s, a)
|
|
return
|
|
case 3:
|
|
while (++n < r) (i = t[n]).callback.call(i.ctx, s, a, o)
|
|
return
|
|
default:
|
|
while (++n < r) (i = t[n]).callback.apply(i.ctx, e)
|
|
return
|
|
}
|
|
}
|
|
var g = function (t, e) {
|
|
this.id = t._listenId
|
|
this.listener = t
|
|
this.obj = e
|
|
this.interop = true
|
|
this.count = 0
|
|
this._events = void 0
|
|
}
|
|
g.prototype.on = a.on
|
|
g.prototype.off = function (t, e) {
|
|
var i
|
|
if (this.interop) {
|
|
this._events = u(f, this._events, t, e, { context: void 0, listeners: void 0 })
|
|
i = !this._events
|
|
} else {
|
|
this.count--
|
|
i = this.count === 0
|
|
}
|
|
if (i) this.cleanup()
|
|
}
|
|
g.prototype.cleanup = function () {
|
|
delete this.listener._listeningTo[this.obj._listenId]
|
|
if (!this.interop) delete this.obj._listeners[this.id]
|
|
}
|
|
a.bind = a.on
|
|
a.unbind = a.off
|
|
i.extend(e, a)
|
|
var m = (e.Model = function (t, e) {
|
|
var n = t || {}
|
|
e || (e = {})
|
|
this.preinitialize.apply(this, arguments)
|
|
this.cid = i.uniqueId(this.cidPrefix)
|
|
this.attributes = {}
|
|
if (e.collection) this.collection = e.collection
|
|
if (e.parse) n = this.parse(n, e) || {}
|
|
var r = i.result(this, 'defaults')
|
|
n = i.defaults(i.extend({}, r, n), r)
|
|
this.set(n, e)
|
|
this.changed = {}
|
|
this.initialize.apply(this, arguments)
|
|
})
|
|
i.extend(m.prototype, a, {
|
|
changed: null,
|
|
validationError: null,
|
|
idAttribute: 'id',
|
|
cidPrefix: 'c',
|
|
preinitialize: function () {},
|
|
initialize: function () {},
|
|
toJSON: function (t) {
|
|
return i.clone(this.attributes)
|
|
},
|
|
sync: function () {
|
|
return e.sync.apply(this, arguments)
|
|
},
|
|
get: function (t) {
|
|
return this.attributes[t]
|
|
},
|
|
escape: function (t) {
|
|
return i.escape(this.get(t))
|
|
},
|
|
has: function (t) {
|
|
return this.get(t) != null
|
|
},
|
|
matches: function (t) {
|
|
return !!i.iteratee(t, this)(this.attributes)
|
|
},
|
|
set: function (t, e, n) {
|
|
if (t == null) return this
|
|
var r
|
|
if (typeof t === 'object') {
|
|
r = t
|
|
n = e
|
|
} else {
|
|
;(r = {})[t] = e
|
|
}
|
|
n || (n = {})
|
|
if (!this._validate(r, n)) return false
|
|
var s = n.unset
|
|
var a = n.silent
|
|
var o = []
|
|
var h = this._changing
|
|
this._changing = true
|
|
if (!h) {
|
|
this._previousAttributes = i.clone(this.attributes)
|
|
this.changed = {}
|
|
}
|
|
var u = this.attributes
|
|
var l = this.changed
|
|
var c = this._previousAttributes
|
|
for (var f in r) {
|
|
e = r[f]
|
|
if (!i.isEqual(u[f], e)) o.push(f)
|
|
if (!i.isEqual(c[f], e)) {
|
|
l[f] = e
|
|
} else {
|
|
delete l[f]
|
|
}
|
|
s ? delete u[f] : (u[f] = e)
|
|
}
|
|
if (this.idAttribute in r) this.id = this.get(this.idAttribute)
|
|
if (!a) {
|
|
if (o.length) this._pending = n
|
|
for (var d = 0; d < o.length; d++) {
|
|
this.trigger('change:' + o[d], this, u[o[d]], n)
|
|
}
|
|
}
|
|
if (h) return this
|
|
if (!a) {
|
|
while (this._pending) {
|
|
n = this._pending
|
|
this._pending = false
|
|
this.trigger('change', this, n)
|
|
}
|
|
}
|
|
this._pending = false
|
|
this._changing = false
|
|
return this
|
|
},
|
|
unset: function (t, e) {
|
|
return this.set(t, void 0, i.extend({}, e, { unset: true }))
|
|
},
|
|
clear: function (t) {
|
|
var e = {}
|
|
for (var n in this.attributes) e[n] = void 0
|
|
return this.set(e, i.extend({}, t, { unset: true }))
|
|
},
|
|
hasChanged: function (t) {
|
|
if (t == null) return !i.isEmpty(this.changed)
|
|
return i.has(this.changed, t)
|
|
},
|
|
changedAttributes: function (t) {
|
|
if (!t) return this.hasChanged() ? i.clone(this.changed) : false
|
|
var e = this._changing ? this._previousAttributes : this.attributes
|
|
var n = {}
|
|
var r
|
|
for (var s in t) {
|
|
var a = t[s]
|
|
if (i.isEqual(e[s], a)) continue
|
|
n[s] = a
|
|
r = true
|
|
}
|
|
return r ? n : false
|
|
},
|
|
previous: function (t) {
|
|
if (t == null || !this._previousAttributes) return null
|
|
return this._previousAttributes[t]
|
|
},
|
|
previousAttributes: function () {
|
|
return i.clone(this._previousAttributes)
|
|
},
|
|
fetch: function (t) {
|
|
t = i.extend({ parse: true }, t)
|
|
var e = this
|
|
var n = t.success
|
|
t.success = function (i) {
|
|
var r = t.parse ? e.parse(i, t) : i
|
|
if (!e.set(r, t)) return false
|
|
if (n) n.call(t.context, e, i, t)
|
|
e.trigger('sync', e, i, t)
|
|
}
|
|
G(this, t)
|
|
return this.sync('read', this, t)
|
|
},
|
|
save: function (t, e, n) {
|
|
var r
|
|
if (t == null || typeof t === 'object') {
|
|
r = t
|
|
n = e
|
|
} else {
|
|
;(r = {})[t] = e
|
|
}
|
|
n = i.extend({ validate: true, parse: true }, n)
|
|
var s = n.wait
|
|
if (r && !s) {
|
|
if (!this.set(r, n)) return false
|
|
} else if (!this._validate(r, n)) {
|
|
return false
|
|
}
|
|
var a = this
|
|
var o = n.success
|
|
var h = this.attributes
|
|
n.success = function (t) {
|
|
a.attributes = h
|
|
var e = n.parse ? a.parse(t, n) : t
|
|
if (s) e = i.extend({}, r, e)
|
|
if (e && !a.set(e, n)) return false
|
|
if (o) o.call(n.context, a, t, n)
|
|
a.trigger('sync', a, t, n)
|
|
}
|
|
G(this, n)
|
|
if (r && s) this.attributes = i.extend({}, h, r)
|
|
var u = this.isNew() ? 'create' : n.patch ? 'patch' : 'update'
|
|
if (u === 'patch' && !n.attrs) n.attrs = r
|
|
var l = this.sync(u, this, n)
|
|
this.attributes = h
|
|
return l
|
|
},
|
|
destroy: function (t) {
|
|
t = t ? i.clone(t) : {}
|
|
var e = this
|
|
var n = t.success
|
|
var r = t.wait
|
|
var s = function () {
|
|
e.stopListening()
|
|
e.trigger('destroy', e, e.collection, t)
|
|
}
|
|
t.success = function (i) {
|
|
if (r) s()
|
|
if (n) n.call(t.context, e, i, t)
|
|
if (!e.isNew()) e.trigger('sync', e, i, t)
|
|
}
|
|
var a = false
|
|
if (this.isNew()) {
|
|
i.defer(t.success)
|
|
} else {
|
|
G(this, t)
|
|
a = this.sync('delete', this, t)
|
|
}
|
|
if (!r) s()
|
|
return a
|
|
},
|
|
url: function () {
|
|
var t = i.result(this, 'urlRoot') || i.result(this.collection, 'url') || V()
|
|
if (this.isNew()) return t
|
|
var e = this.get(this.idAttribute)
|
|
return t.replace(/[^\/]$/, '$&/') + encodeURIComponent(e)
|
|
},
|
|
parse: function (t, e) {
|
|
return t
|
|
},
|
|
clone: function () {
|
|
return new this.constructor(this.attributes)
|
|
},
|
|
isNew: function () {
|
|
return !this.has(this.idAttribute)
|
|
},
|
|
isValid: function (t) {
|
|
return this._validate({}, i.extend({}, t, { validate: true }))
|
|
},
|
|
_validate: function (t, e) {
|
|
if (!e.validate || !this.validate) return true
|
|
t = i.extend({}, this.attributes, t)
|
|
var n = (this.validationError = this.validate(t, e) || null)
|
|
if (!n) return true
|
|
this.trigger('invalid', this, n, i.extend(e, { validationError: n }))
|
|
return false
|
|
},
|
|
})
|
|
var _ = (e.Collection = function (t, e) {
|
|
e || (e = {})
|
|
this.preinitialize.apply(this, arguments)
|
|
if (e.model) this.model = e.model
|
|
if (e.comparator !== void 0) this.comparator = e.comparator
|
|
this._reset()
|
|
this.initialize.apply(this, arguments)
|
|
if (t) this.reset(t, i.extend({ silent: true }, e))
|
|
})
|
|
var y = { add: true, remove: true, merge: true }
|
|
var b = { add: true, remove: false }
|
|
var x = function (t, e, i) {
|
|
i = Math.min(Math.max(i, 0), t.length)
|
|
var n = Array(t.length - i)
|
|
var r = e.length
|
|
var s
|
|
for (s = 0; s < n.length; s++) n[s] = t[s + i]
|
|
for (s = 0; s < r; s++) t[s + i] = e[s]
|
|
for (s = 0; s < n.length; s++) t[s + r + i] = n[s]
|
|
}
|
|
i.extend(_.prototype, a, {
|
|
model: m,
|
|
preinitialize: function () {},
|
|
initialize: function () {},
|
|
toJSON: function (t) {
|
|
return this.map(function (e) {
|
|
return e.toJSON(t)
|
|
})
|
|
},
|
|
sync: function () {
|
|
return e.sync.apply(this, arguments)
|
|
},
|
|
add: function (t, e) {
|
|
return this.set(t, i.extend({ merge: false }, e, b))
|
|
},
|
|
remove: function (t, e) {
|
|
e = i.extend({}, e)
|
|
var n = !i.isArray(t)
|
|
t = n ? [t] : t.slice()
|
|
var r = this._removeModels(t, e)
|
|
if (!e.silent && r.length) {
|
|
e.changes = { added: [], merged: [], removed: r }
|
|
this.trigger('update', this, e)
|
|
}
|
|
return n ? r[0] : r
|
|
},
|
|
set: function (t, e) {
|
|
if (t == null) return
|
|
e = i.extend({}, y, e)
|
|
if (e.parse && !this._isModel(t)) {
|
|
t = this.parse(t, e) || []
|
|
}
|
|
var n = !i.isArray(t)
|
|
t = n ? [t] : t.slice()
|
|
var r = e.at
|
|
if (r != null) r = +r
|
|
if (r > this.length) r = this.length
|
|
if (r < 0) r += this.length + 1
|
|
var s = []
|
|
var a = []
|
|
var o = []
|
|
var h = []
|
|
var u = {}
|
|
var l = e.add
|
|
var c = e.merge
|
|
var f = e.remove
|
|
var d = false
|
|
var v = this.comparator && r == null && e.sort !== false
|
|
var p = i.isString(this.comparator) ? this.comparator : null
|
|
var g, m
|
|
for (m = 0; m < t.length; m++) {
|
|
g = t[m]
|
|
var _ = this.get(g)
|
|
if (_) {
|
|
if (c && g !== _) {
|
|
var b = this._isModel(g) ? g.attributes : g
|
|
if (e.parse) b = _.parse(b, e)
|
|
_.set(b, e)
|
|
o.push(_)
|
|
if (v && !d) d = _.hasChanged(p)
|
|
}
|
|
if (!u[_.cid]) {
|
|
u[_.cid] = true
|
|
s.push(_)
|
|
}
|
|
t[m] = _
|
|
} else if (l) {
|
|
g = t[m] = this._prepareModel(g, e)
|
|
if (g) {
|
|
a.push(g)
|
|
this._addReference(g, e)
|
|
u[g.cid] = true
|
|
s.push(g)
|
|
}
|
|
}
|
|
}
|
|
if (f) {
|
|
for (m = 0; m < this.length; m++) {
|
|
g = this.models[m]
|
|
if (!u[g.cid]) h.push(g)
|
|
}
|
|
if (h.length) this._removeModels(h, e)
|
|
}
|
|
var w = false
|
|
var E = !v && l && f
|
|
if (s.length && E) {
|
|
w =
|
|
this.length !== s.length ||
|
|
i.some(this.models, function (t, e) {
|
|
return t !== s[e]
|
|
})
|
|
this.models.length = 0
|
|
x(this.models, s, 0)
|
|
this.length = this.models.length
|
|
} else if (a.length) {
|
|
if (v) d = true
|
|
x(this.models, a, r == null ? this.length : r)
|
|
this.length = this.models.length
|
|
}
|
|
if (d) this.sort({ silent: true })
|
|
if (!e.silent) {
|
|
for (m = 0; m < a.length; m++) {
|
|
if (r != null) e.index = r + m
|
|
g = a[m]
|
|
g.trigger('add', g, this, e)
|
|
}
|
|
if (d || w) this.trigger('sort', this, e)
|
|
if (a.length || h.length || o.length) {
|
|
e.changes = { added: a, removed: h, merged: o }
|
|
this.trigger('update', this, e)
|
|
}
|
|
}
|
|
return n ? t[0] : t
|
|
},
|
|
reset: function (t, e) {
|
|
e = e ? i.clone(e) : {}
|
|
for (var n = 0; n < this.models.length; n++) {
|
|
this._removeReference(this.models[n], e)
|
|
}
|
|
e.previousModels = this.models
|
|
this._reset()
|
|
t = this.add(t, i.extend({ silent: true }, e))
|
|
if (!e.silent) this.trigger('reset', this, e)
|
|
return t
|
|
},
|
|
push: function (t, e) {
|
|
return this.add(t, i.extend({ at: this.length }, e))
|
|
},
|
|
pop: function (t) {
|
|
var e = this.at(this.length - 1)
|
|
return this.remove(e, t)
|
|
},
|
|
unshift: function (t, e) {
|
|
return this.add(t, i.extend({ at: 0 }, e))
|
|
},
|
|
shift: function (t) {
|
|
var e = this.at(0)
|
|
return this.remove(e, t)
|
|
},
|
|
slice: function () {
|
|
return s.apply(this.models, arguments)
|
|
},
|
|
get: function (t) {
|
|
if (t == null) return void 0
|
|
return (
|
|
this._byId[t] ||
|
|
this._byId[this.modelId(this._isModel(t) ? t.attributes : t)] ||
|
|
(t.cid && this._byId[t.cid])
|
|
)
|
|
},
|
|
has: function (t) {
|
|
return this.get(t) != null
|
|
},
|
|
at: function (t) {
|
|
if (t < 0) t += this.length
|
|
return this.models[t]
|
|
},
|
|
where: function (t, e) {
|
|
return this[e ? 'find' : 'filter'](t)
|
|
},
|
|
findWhere: function (t) {
|
|
return this.where(t, true)
|
|
},
|
|
sort: function (t) {
|
|
var e = this.comparator
|
|
if (!e) throw new Error('Cannot sort a set without a comparator')
|
|
t || (t = {})
|
|
var n = e.length
|
|
if (i.isFunction(e)) e = e.bind(this)
|
|
if (n === 1 || i.isString(e)) {
|
|
this.models = this.sortBy(e)
|
|
} else {
|
|
this.models.sort(e)
|
|
}
|
|
if (!t.silent) this.trigger('sort', this, t)
|
|
return this
|
|
},
|
|
pluck: function (t) {
|
|
return this.map(t + '')
|
|
},
|
|
fetch: function (t) {
|
|
t = i.extend({ parse: true }, t)
|
|
var e = t.success
|
|
var n = this
|
|
t.success = function (i) {
|
|
var r = t.reset ? 'reset' : 'set'
|
|
n[r](i, t)
|
|
if (e) e.call(t.context, n, i, t)
|
|
n.trigger('sync', n, i, t)
|
|
}
|
|
G(this, t)
|
|
return this.sync('read', this, t)
|
|
},
|
|
create: function (t, e) {
|
|
e = e ? i.clone(e) : {}
|
|
var n = e.wait
|
|
t = this._prepareModel(t, e)
|
|
if (!t) return false
|
|
if (!n) this.add(t, e)
|
|
var r = this
|
|
var s = e.success
|
|
e.success = function (t, e, i) {
|
|
if (n) r.add(t, i)
|
|
if (s) s.call(i.context, t, e, i)
|
|
}
|
|
t.save(null, e)
|
|
return t
|
|
},
|
|
parse: function (t, e) {
|
|
return t
|
|
},
|
|
clone: function () {
|
|
return new this.constructor(this.models, { model: this.model, comparator: this.comparator })
|
|
},
|
|
modelId: function (t) {
|
|
return t[this.model.prototype.idAttribute || 'id']
|
|
},
|
|
values: function () {
|
|
return new E(this, k)
|
|
},
|
|
keys: function () {
|
|
return new E(this, I)
|
|
},
|
|
entries: function () {
|
|
return new E(this, S)
|
|
},
|
|
_reset: function () {
|
|
this.length = 0
|
|
this.models = []
|
|
this._byId = {}
|
|
},
|
|
_prepareModel: function (t, e) {
|
|
if (this._isModel(t)) {
|
|
if (!t.collection) t.collection = this
|
|
return t
|
|
}
|
|
e = e ? i.clone(e) : {}
|
|
e.collection = this
|
|
var n = new this.model(t, e)
|
|
if (!n.validationError) return n
|
|
this.trigger('invalid', this, n.validationError, e)
|
|
return false
|
|
},
|
|
_removeModels: function (t, e) {
|
|
var i = []
|
|
for (var n = 0; n < t.length; n++) {
|
|
var r = this.get(t[n])
|
|
if (!r) continue
|
|
var s = this.indexOf(r)
|
|
this.models.splice(s, 1)
|
|
this.length--
|
|
delete this._byId[r.cid]
|
|
var a = this.modelId(r.attributes)
|
|
if (a != null) delete this._byId[a]
|
|
if (!e.silent) {
|
|
e.index = s
|
|
r.trigger('remove', r, this, e)
|
|
}
|
|
i.push(r)
|
|
this._removeReference(r, e)
|
|
}
|
|
return i
|
|
},
|
|
_isModel: function (t) {
|
|
return t instanceof m
|
|
},
|
|
_addReference: function (t, e) {
|
|
this._byId[t.cid] = t
|
|
var i = this.modelId(t.attributes)
|
|
if (i != null) this._byId[i] = t
|
|
t.on('all', this._onModelEvent, this)
|
|
},
|
|
_removeReference: function (t, e) {
|
|
delete this._byId[t.cid]
|
|
var i = this.modelId(t.attributes)
|
|
if (i != null) delete this._byId[i]
|
|
if (this === t.collection) delete t.collection
|
|
t.off('all', this._onModelEvent, this)
|
|
},
|
|
_onModelEvent: function (t, e, i, n) {
|
|
if (e) {
|
|
if ((t === 'add' || t === 'remove') && i !== this) return
|
|
if (t === 'destroy') this.remove(e, n)
|
|
if (t === 'change') {
|
|
var r = this.modelId(e.previousAttributes())
|
|
var s = this.modelId(e.attributes)
|
|
if (r !== s) {
|
|
if (r != null) delete this._byId[r]
|
|
if (s != null) this._byId[s] = e
|
|
}
|
|
}
|
|
}
|
|
this.trigger.apply(this, arguments)
|
|
},
|
|
})
|
|
var w = typeof Symbol === 'function' && Symbol.iterator
|
|
if (w) {
|
|
_.prototype[w] = _.prototype.values
|
|
}
|
|
var E = function (t, e) {
|
|
this._collection = t
|
|
this._kind = e
|
|
this._index = 0
|
|
}
|
|
var k = 1
|
|
var I = 2
|
|
var S = 3
|
|
if (w) {
|
|
E.prototype[w] = function () {
|
|
return this
|
|
}
|
|
}
|
|
E.prototype.next = function () {
|
|
if (this._collection) {
|
|
if (this._index < this._collection.length) {
|
|
var t = this._collection.at(this._index)
|
|
this._index++
|
|
var e
|
|
if (this._kind === k) {
|
|
e = t
|
|
} else {
|
|
var i = this._collection.modelId(t.attributes)
|
|
if (this._kind === I) {
|
|
e = i
|
|
} else {
|
|
e = [i, t]
|
|
}
|
|
}
|
|
return { value: e, done: false }
|
|
}
|
|
this._collection = void 0
|
|
}
|
|
return { value: void 0, done: true }
|
|
}
|
|
var T = (e.View = function (t) {
|
|
this.cid = i.uniqueId('view')
|
|
this.preinitialize.apply(this, arguments)
|
|
i.extend(this, i.pick(t, H))
|
|
this._ensureElement()
|
|
this.initialize.apply(this, arguments)
|
|
})
|
|
var P = /^(\S+)\s*(.*)$/
|
|
var H = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']
|
|
i.extend(T.prototype, a, {
|
|
tagName: 'div',
|
|
$: function (t) {
|
|
return this.$el.find(t)
|
|
},
|
|
preinitialize: function () {},
|
|
initialize: function () {},
|
|
render: function () {
|
|
return this
|
|
},
|
|
remove: function () {
|
|
this._removeElement()
|
|
this.stopListening()
|
|
return this
|
|
},
|
|
_removeElement: function () {
|
|
this.$el.remove()
|
|
},
|
|
setElement: function (t) {
|
|
this.undelegateEvents()
|
|
this._setElement(t)
|
|
this.delegateEvents()
|
|
return this
|
|
},
|
|
_setElement: function (t) {
|
|
this.$el = t instanceof e.$ ? t : e.$(t)
|
|
this.el = this.$el[0]
|
|
},
|
|
delegateEvents: function (t) {
|
|
t || (t = i.result(this, 'events'))
|
|
if (!t) return this
|
|
this.undelegateEvents()
|
|
for (var e in t) {
|
|
var n = t[e]
|
|
if (!i.isFunction(n)) n = this[n]
|
|
if (!n) continue
|
|
var r = e.match(P)
|
|
this.delegate(r[1], r[2], n.bind(this))
|
|
}
|
|
return this
|
|
},
|
|
delegate: function (t, e, i) {
|
|
this.$el.on(t + '.delegateEvents' + this.cid, e, i)
|
|
return this
|
|
},
|
|
undelegateEvents: function () {
|
|
if (this.$el) this.$el.off('.delegateEvents' + this.cid)
|
|
return this
|
|
},
|
|
undelegate: function (t, e, i) {
|
|
this.$el.off(t + '.delegateEvents' + this.cid, e, i)
|
|
return this
|
|
},
|
|
_createElement: function (t) {
|
|
return document.createElement(t)
|
|
},
|
|
_ensureElement: function () {
|
|
if (!this.el) {
|
|
var t = i.extend({}, i.result(this, 'attributes'))
|
|
if (this.id) t.id = i.result(this, 'id')
|
|
if (this.className) t['class'] = i.result(this, 'className')
|
|
this.setElement(this._createElement(i.result(this, 'tagName')))
|
|
this._setAttributes(t)
|
|
} else {
|
|
this.setElement(i.result(this, 'el'))
|
|
}
|
|
},
|
|
_setAttributes: function (t) {
|
|
this.$el.attr(t)
|
|
},
|
|
})
|
|
var $ = function (t, e, i, n) {
|
|
switch (e) {
|
|
case 1:
|
|
return function () {
|
|
return t[i](this[n])
|
|
}
|
|
case 2:
|
|
return function (e) {
|
|
return t[i](this[n], e)
|
|
}
|
|
case 3:
|
|
return function (e, r) {
|
|
return t[i](this[n], C(e, this), r)
|
|
}
|
|
case 4:
|
|
return function (e, r, s) {
|
|
return t[i](this[n], C(e, this), r, s)
|
|
}
|
|
default:
|
|
return function () {
|
|
var e = s.call(arguments)
|
|
e.unshift(this[n])
|
|
return t[i].apply(t, e)
|
|
}
|
|
}
|
|
}
|
|
var A = function (t, e, n, r) {
|
|
i.each(n, function (i, n) {
|
|
if (e[n]) t.prototype[n] = $(e, i, n, r)
|
|
})
|
|
}
|
|
var C = function (t, e) {
|
|
if (i.isFunction(t)) return t
|
|
if (i.isObject(t) && !e._isModel(t)) return R(t)
|
|
if (i.isString(t))
|
|
return function (e) {
|
|
return e.get(t)
|
|
}
|
|
return t
|
|
}
|
|
var R = function (t) {
|
|
var e = i.matches(t)
|
|
return function (t) {
|
|
return e(t.attributes)
|
|
}
|
|
}
|
|
var M = {
|
|
forEach: 3,
|
|
each: 3,
|
|
map: 3,
|
|
collect: 3,
|
|
reduce: 0,
|
|
foldl: 0,
|
|
inject: 0,
|
|
reduceRight: 0,
|
|
foldr: 0,
|
|
find: 3,
|
|
detect: 3,
|
|
filter: 3,
|
|
select: 3,
|
|
reject: 3,
|
|
every: 3,
|
|
all: 3,
|
|
some: 3,
|
|
any: 3,
|
|
include: 3,
|
|
includes: 3,
|
|
contains: 3,
|
|
invoke: 0,
|
|
max: 3,
|
|
min: 3,
|
|
toArray: 1,
|
|
size: 1,
|
|
first: 3,
|
|
head: 3,
|
|
take: 3,
|
|
initial: 3,
|
|
rest: 3,
|
|
tail: 3,
|
|
drop: 3,
|
|
last: 3,
|
|
without: 0,
|
|
difference: 0,
|
|
indexOf: 3,
|
|
shuffle: 1,
|
|
lastIndexOf: 3,
|
|
isEmpty: 1,
|
|
chain: 1,
|
|
sample: 3,
|
|
partition: 3,
|
|
groupBy: 3,
|
|
countBy: 3,
|
|
sortBy: 3,
|
|
indexBy: 3,
|
|
findIndex: 3,
|
|
findLastIndex: 3,
|
|
}
|
|
var N = { keys: 1, values: 1, pairs: 1, invert: 1, pick: 0, omit: 0, chain: 1, isEmpty: 1 }
|
|
i.each(
|
|
[
|
|
[_, M, 'models'],
|
|
[m, N, 'attributes'],
|
|
],
|
|
function (t) {
|
|
var e = t[0],
|
|
n = t[1],
|
|
r = t[2]
|
|
e.mixin = function (t) {
|
|
var n = i.reduce(
|
|
i.functions(t),
|
|
function (t, e) {
|
|
t[e] = 0
|
|
return t
|
|
},
|
|
{},
|
|
)
|
|
A(e, t, n, r)
|
|
}
|
|
A(e, i, n, r)
|
|
},
|
|
)
|
|
e.sync = function (t, n, r) {
|
|
var s = j[t]
|
|
i.defaults(r || (r = {}), { emulateHTTP: e.emulateHTTP, emulateJSON: e.emulateJSON })
|
|
var a = { type: s, dataType: 'json' }
|
|
if (!r.url) {
|
|
a.url = i.result(n, 'url') || V()
|
|
}
|
|
if (r.data == null && n && (t === 'create' || t === 'update' || t === 'patch')) {
|
|
a.contentType = 'application/json'
|
|
a.data = JSON.stringify(r.attrs || n.toJSON(r))
|
|
}
|
|
if (r.emulateJSON) {
|
|
a.contentType = 'application/x-www-form-urlencoded'
|
|
a.data = a.data ? { model: a.data } : {}
|
|
}
|
|
if (r.emulateHTTP && (s === 'PUT' || s === 'DELETE' || s === 'PATCH')) {
|
|
a.type = 'POST'
|
|
if (r.emulateJSON) a.data._method = s
|
|
var o = r.beforeSend
|
|
r.beforeSend = function (t) {
|
|
t.setRequestHeader('X-HTTP-Method-Override', s)
|
|
if (o) return o.apply(this, arguments)
|
|
}
|
|
}
|
|
if (a.type !== 'GET' && !r.emulateJSON) {
|
|
a.processData = false
|
|
}
|
|
var h = r.error
|
|
r.error = function (t, e, i) {
|
|
r.textStatus = e
|
|
r.errorThrown = i
|
|
if (h) h.call(r.context, t, e, i)
|
|
}
|
|
var u = (r.xhr = e.ajax(i.extend(a, r)))
|
|
n.trigger('request', n, u, r)
|
|
return u
|
|
}
|
|
var j = { create: 'POST', update: 'PUT', patch: 'PATCH', delete: 'DELETE', read: 'GET' }
|
|
e.ajax = function () {
|
|
return e.$.ajax.apply(e.$, arguments)
|
|
}
|
|
var O = (e.Router = function (t) {
|
|
t || (t = {})
|
|
this.preinitialize.apply(this, arguments)
|
|
if (t.routes) this.routes = t.routes
|
|
this._bindRoutes()
|
|
this.initialize.apply(this, arguments)
|
|
})
|
|
var U = /\((.*?)\)/g
|
|
var z = /(\(\?)?:\w+/g
|
|
var q = /\*\w+/g
|
|
var F = /[\-{}\[\]+?.,\\\^$|#\s]/g
|
|
i.extend(O.prototype, a, {
|
|
preinitialize: function () {},
|
|
initialize: function () {},
|
|
route: function (t, n, r) {
|
|
if (!i.isRegExp(t)) t = this._routeToRegExp(t)
|
|
if (i.isFunction(n)) {
|
|
r = n
|
|
n = ''
|
|
}
|
|
if (!r) r = this[n]
|
|
var s = this
|
|
e.history.route(t, function (i) {
|
|
var a = s._extractParameters(t, i)
|
|
if (s.execute(r, a, n) !== false) {
|
|
s.trigger.apply(s, ['route:' + n].concat(a))
|
|
s.trigger('route', n, a)
|
|
e.history.trigger('route', s, n, a)
|
|
}
|
|
})
|
|
return this
|
|
},
|
|
execute: function (t, e, i) {
|
|
if (t) t.apply(this, e)
|
|
},
|
|
navigate: function (t, i) {
|
|
e.history.navigate(t, i)
|
|
return this
|
|
},
|
|
_bindRoutes: function () {
|
|
if (!this.routes) return
|
|
this.routes = i.result(this, 'routes')
|
|
var t,
|
|
e = i.keys(this.routes)
|
|
while ((t = e.pop()) != null) {
|
|
this.route(t, this.routes[t])
|
|
}
|
|
},
|
|
_routeToRegExp: function (t) {
|
|
t = t
|
|
.replace(F, '\\$&')
|
|
.replace(U, '(?:$1)?')
|
|
.replace(z, function (t, e) {
|
|
return e ? t : '([^/?]+)'
|
|
})
|
|
.replace(q, '([^?]*?)')
|
|
return new RegExp('^' + t + '(?:\\?([\\s\\S]*))?$')
|
|
},
|
|
_extractParameters: function (t, e) {
|
|
var n = t.exec(e).slice(1)
|
|
return i.map(n, function (t, e) {
|
|
if (e === n.length - 1) return t || null
|
|
return t ? decodeURIComponent(t) : null
|
|
})
|
|
},
|
|
})
|
|
var B = (e.History = function () {
|
|
this.handlers = []
|
|
this.checkUrl = this.checkUrl.bind(this)
|
|
if (typeof window !== 'undefined') {
|
|
this.location = window.location
|
|
this.history = window.history
|
|
}
|
|
})
|
|
var J = /^[#\/]|\s+$/g
|
|
var L = /^\/+|\/+$/g
|
|
var W = /#.*$/
|
|
B.started = false
|
|
i.extend(B.prototype, a, {
|
|
interval: 50,
|
|
atRoot: function () {
|
|
var t = this.location.pathname.replace(/[^\/]$/, '$&/')
|
|
return t === this.root && !this.getSearch()
|
|
},
|
|
matchRoot: function () {
|
|
var t = this.decodeFragment(this.location.pathname)
|
|
var e = t.slice(0, this.root.length - 1) + '/'
|
|
return e === this.root
|
|
},
|
|
decodeFragment: function (t) {
|
|
return decodeURI(t.replace(/%25/g, '%2525'))
|
|
},
|
|
getSearch: function () {
|
|
var t = this.location.href.replace(/#.*/, '').match(/\?.+/)
|
|
return t ? t[0] : ''
|
|
},
|
|
getHash: function (t) {
|
|
var e = (t || this).location.href.match(/#(.*)$/)
|
|
return e ? e[1] : ''
|
|
},
|
|
getPath: function () {
|
|
var t = this.decodeFragment(this.location.pathname + this.getSearch()).slice(
|
|
this.root.length - 1,
|
|
)
|
|
return t.charAt(0) === '/' ? t.slice(1) : t
|
|
},
|
|
getFragment: function (t) {
|
|
if (t == null) {
|
|
if (this._usePushState || !this._wantsHashChange) {
|
|
t = this.getPath()
|
|
} else {
|
|
t = this.getHash()
|
|
}
|
|
}
|
|
return t.replace(J, '')
|
|
},
|
|
start: function (t) {
|
|
if (B.started) throw new Error('Backbone.history has already been started')
|
|
B.started = true
|
|
this.options = i.extend({ root: '/' }, this.options, t)
|
|
this.root = this.options.root
|
|
this._wantsHashChange = this.options.hashChange !== false
|
|
this._hasHashChange =
|
|
'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7)
|
|
this._useHashChange = this._wantsHashChange && this._hasHashChange
|
|
this._wantsPushState = !!this.options.pushState
|
|
this._hasPushState = !!(this.history && this.history.pushState)
|
|
this._usePushState = this._wantsPushState && this._hasPushState
|
|
this.fragment = this.getFragment()
|
|
this.root = ('/' + this.root + '/').replace(L, '/')
|
|
if (this._wantsHashChange && this._wantsPushState) {
|
|
if (!this._hasPushState && !this.atRoot()) {
|
|
var e = this.root.slice(0, -1) || '/'
|
|
this.location.replace(e + '#' + this.getPath())
|
|
return true
|
|
} else if (this._hasPushState && this.atRoot()) {
|
|
this.navigate(this.getHash(), { replace: true })
|
|
}
|
|
}
|
|
if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) {
|
|
this.iframe = document.createElement('iframe')
|
|
this.iframe.src = 'javascript:0'
|
|
this.iframe.style.display = 'none'
|
|
this.iframe.tabIndex = -1
|
|
var n = document.body
|
|
var r = n.insertBefore(this.iframe, n.firstChild).contentWindow
|
|
r.document.open()
|
|
r.document.close()
|
|
r.location.hash = '#' + this.fragment
|
|
}
|
|
var s =
|
|
window.addEventListener ||
|
|
function (t, e) {
|
|
return attachEvent('on' + t, e)
|
|
}
|
|
if (this._usePushState) {
|
|
s('popstate', this.checkUrl, false)
|
|
} else if (this._useHashChange && !this.iframe) {
|
|
s('hashchange', this.checkUrl, false)
|
|
} else if (this._wantsHashChange) {
|
|
this._checkUrlInterval = setInterval(this.checkUrl, this.interval)
|
|
}
|
|
if (!this.options.silent) return this.loadUrl()
|
|
},
|
|
stop: function () {
|
|
var t =
|
|
window.removeEventListener ||
|
|
function (t, e) {
|
|
return detachEvent('on' + t, e)
|
|
}
|
|
if (this._usePushState) {
|
|
t('popstate', this.checkUrl, false)
|
|
} else if (this._useHashChange && !this.iframe) {
|
|
t('hashchange', this.checkUrl, false)
|
|
}
|
|
if (this.iframe) {
|
|
document.body.removeChild(this.iframe)
|
|
this.iframe = null
|
|
}
|
|
if (this._checkUrlInterval) clearInterval(this._checkUrlInterval)
|
|
B.started = false
|
|
},
|
|
route: function (t, e) {
|
|
this.handlers.unshift({ route: t, callback: e })
|
|
},
|
|
checkUrl: function (t) {
|
|
var e = this.getFragment()
|
|
if (e === this.fragment && this.iframe) {
|
|
e = this.getHash(this.iframe.contentWindow)
|
|
}
|
|
if (e === this.fragment) return false
|
|
if (this.iframe) this.navigate(e)
|
|
this.loadUrl()
|
|
},
|
|
loadUrl: function (t) {
|
|
if (!this.matchRoot()) return false
|
|
t = this.fragment = this.getFragment(t)
|
|
return i.some(this.handlers, function (e) {
|
|
if (e.route.test(t)) {
|
|
e.callback(t)
|
|
return true
|
|
}
|
|
})
|
|
},
|
|
navigate: function (t, e) {
|
|
if (!B.started) return false
|
|
if (!e || e === true) e = { trigger: !!e }
|
|
t = this.getFragment(t || '')
|
|
var i = this.root
|
|
if (t === '' || t.charAt(0) === '?') {
|
|
i = i.slice(0, -1) || '/'
|
|
}
|
|
var n = i + t
|
|
t = t.replace(W, '')
|
|
var r = this.decodeFragment(t)
|
|
if (this.fragment === r) return
|
|
this.fragment = r
|
|
if (this._usePushState) {
|
|
this.history[e.replace ? 'replaceState' : 'pushState']({}, document.title, n)
|
|
} else if (this._wantsHashChange) {
|
|
this._updateHash(this.location, t, e.replace)
|
|
if (this.iframe && t !== this.getHash(this.iframe.contentWindow)) {
|
|
var s = this.iframe.contentWindow
|
|
if (!e.replace) {
|
|
s.document.open()
|
|
s.document.close()
|
|
}
|
|
this._updateHash(s.location, t, e.replace)
|
|
}
|
|
} else {
|
|
return this.location.assign(n)
|
|
}
|
|
if (e.trigger) return this.loadUrl(t)
|
|
},
|
|
_updateHash: function (t, e, i) {
|
|
if (i) {
|
|
var n = t.href.replace(/(javascript:|#).*$/, '')
|
|
t.replace(n + '#' + e)
|
|
} else {
|
|
t.hash = '#' + e
|
|
}
|
|
},
|
|
})
|
|
e.history = new B()
|
|
var D = function (t, e) {
|
|
var n = this
|
|
var r
|
|
if (t && i.has(t, 'constructor')) {
|
|
r = t.constructor
|
|
} else {
|
|
r = function () {
|
|
return n.apply(this, arguments)
|
|
}
|
|
}
|
|
i.extend(r, n, e)
|
|
r.prototype = i.create(n.prototype, t)
|
|
r.prototype.constructor = r
|
|
r.__super__ = n.prototype
|
|
return r
|
|
}
|
|
m.extend = _.extend = O.extend = T.extend = B.extend = D
|
|
var V = function () {
|
|
throw new Error('A "url" property or function must be specified')
|
|
}
|
|
var G = function (t, e) {
|
|
var i = e.error
|
|
e.error = function (n) {
|
|
if (i) i.call(e.context, t, n, e)
|
|
t.trigger('error', t, n, e)
|
|
}
|
|
}
|
|
return e
|
|
})
|