mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 06:05:02 +03:00
2273 lines
68 KiB
JavaScript
2273 lines
68 KiB
JavaScript
(function (
|
|
) {
|
|
var Backbone,
|
|
root = this,
|
|
previousBackbone = root.Backbone,
|
|
array = [],
|
|
slice = array.slice;
|
|
(Backbone =
|
|
"undefined" != typeof exports
|
|
? exports
|
|
: (root.Backbone = {
|
|
})).VERSION =
|
|
"1.1.0";
|
|
var _ = root._;
|
|
_ || "undefined" == typeof require || (_ = require(
|
|
"underscore"
|
|
)),
|
|
(Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$),
|
|
(Backbone.noConflict = function (
|
|
) {
|
|
return (root.Backbone = previousBackbone), this;
|
|
}),
|
|
(Backbone.emulateHTTP = !1),
|
|
(Backbone.emulateJSON = !1);
|
|
var Events = (Backbone.Events = {
|
|
on: function (
|
|
name, callback, context
|
|
) {
|
|
return eventsApi(
|
|
this,
|
|
"on",
|
|
name,
|
|
[callback, context,]
|
|
) && callback
|
|
? (this._events || (this._events = {
|
|
}),
|
|
(this._events[name] || (this._events[name] = [])).push(
|
|
{
|
|
callback: callback,
|
|
context: context,
|
|
ctx: context || this,
|
|
}
|
|
),
|
|
this)
|
|
: this;
|
|
},
|
|
once: function (
|
|
name, callback, context
|
|
) {
|
|
if (!eventsApi(
|
|
this,
|
|
"once",
|
|
name,
|
|
[callback, context,]
|
|
) || !callback)
|
|
return this;
|
|
var self = this,
|
|
once = _.once(
|
|
function (
|
|
) {
|
|
self.off(
|
|
name,
|
|
once
|
|
), callback.apply(
|
|
this,
|
|
arguments
|
|
);
|
|
}
|
|
);
|
|
return (once._callback = callback), this.on(
|
|
name,
|
|
once,
|
|
context
|
|
);
|
|
},
|
|
off: function (
|
|
name, callback, context
|
|
) {
|
|
var retain, ev, events, names, i, l, j, k;
|
|
if (!this._events || !eventsApi(
|
|
this,
|
|
"off",
|
|
name,
|
|
[callback, context,]
|
|
))
|
|
return this;
|
|
if (!name && !callback && !context) return (this._events = {
|
|
}), this;
|
|
for (
|
|
i = 0, l = (names = name
|
|
? [name,]
|
|
: _.keys(
|
|
this._events
|
|
)).length;
|
|
i < l;
|
|
i++
|
|
)
|
|
if (((name = names[i]), (events = this._events[name]))) {
|
|
if (((this._events[name] = retain = []), callback || context))
|
|
for (j = 0, k = events.length; j < k; j++)
|
|
(ev = events[j]),
|
|
((callback &&
|
|
callback !== ev.callback &&
|
|
callback !== ev.callback._callback) ||
|
|
(context && context !== ev.context)) &&
|
|
retain.push(
|
|
ev
|
|
);
|
|
retain.length || delete this._events[name];
|
|
}
|
|
return this;
|
|
},
|
|
trigger: function (
|
|
name
|
|
) {
|
|
if (!this._events) return this;
|
|
var args = slice.call(
|
|
arguments,
|
|
1
|
|
);
|
|
if (!eventsApi(
|
|
this,
|
|
"trigger",
|
|
name,
|
|
args
|
|
)) return this;
|
|
var events = this._events[name],
|
|
allEvents = this._events.all;
|
|
return (
|
|
events && triggerEvents(
|
|
events,
|
|
args
|
|
),
|
|
allEvents && triggerEvents(
|
|
allEvents,
|
|
arguments
|
|
),
|
|
this
|
|
);
|
|
},
|
|
stopListening: function (
|
|
obj, name, callback
|
|
) {
|
|
var listeningTo = this._listeningTo;
|
|
if (!listeningTo) return this;
|
|
var remove = !name && !callback;
|
|
for (var id in (callback ||
|
|
"object" != typeof name ||
|
|
(callback = this),
|
|
obj && ((listeningTo = {
|
|
})[obj._listenId] = obj),
|
|
listeningTo))
|
|
(obj = listeningTo[id]).off(
|
|
name,
|
|
callback,
|
|
this
|
|
),
|
|
(remove || _.isEmpty(
|
|
obj._events
|
|
)) && delete this._listeningTo[id];
|
|
return this;
|
|
},
|
|
}),
|
|
eventSplitter = /\s+/,
|
|
eventsApi = function (
|
|
obj, action, name, rest
|
|
) {
|
|
if (!name) return !0;
|
|
if ("object" == typeof name) {
|
|
for (var key in name)
|
|
obj[action].apply(
|
|
obj,
|
|
[key, name[key],].concat(
|
|
rest
|
|
)
|
|
);
|
|
return !1;
|
|
}
|
|
if (eventSplitter.test(
|
|
name
|
|
)) {
|
|
for (
|
|
var names = name.split(
|
|
eventSplitter
|
|
), i = 0, l = names.length;
|
|
i < l;
|
|
i++
|
|
)
|
|
obj[action].apply(
|
|
obj,
|
|
[names[i],].concat(
|
|
rest
|
|
)
|
|
);
|
|
return !1;
|
|
}
|
|
return !0;
|
|
},
|
|
triggerEvents = function (
|
|
events, args
|
|
) {
|
|
var ev,
|
|
i = -1,
|
|
l = events.length,
|
|
a1 = args[0],
|
|
a2 = args[1],
|
|
a3 = args[2];
|
|
switch (args.length) {
|
|
case 0:
|
|
for (; ++i < l; ) (ev = events[i]).callback.call(
|
|
ev.ctx
|
|
);
|
|
return;
|
|
case 1:
|
|
for (; ++i < l; ) (ev = events[i]).callback.call(
|
|
ev.ctx,
|
|
a1
|
|
);
|
|
return;
|
|
case 2:
|
|
for (; ++i < l; ) (ev = events[i]).callback.call(
|
|
ev.ctx,
|
|
a1,
|
|
a2
|
|
);
|
|
return;
|
|
case 3:
|
|
for (; ++i < l; ) (ev = events[i]).callback.call(
|
|
ev.ctx,
|
|
a1,
|
|
a2,
|
|
a3
|
|
);
|
|
return;
|
|
default:
|
|
for (; ++i < l; ) (ev = events[i]).callback.apply(
|
|
ev.ctx,
|
|
args
|
|
);
|
|
}
|
|
};
|
|
_.each(
|
|
{
|
|
listenTo: "on",
|
|
listenToOnce: "once",
|
|
},
|
|
function (
|
|
implementation, method
|
|
) {
|
|
Events[method] = function (
|
|
obj, name, callback
|
|
) {
|
|
return (
|
|
((this._listeningTo || (this._listeningTo = {
|
|
}))[
|
|
obj._listenId || (obj._listenId = _.uniqueId(
|
|
"l"
|
|
))
|
|
] = obj),
|
|
callback || "object" != typeof name || (callback = this),
|
|
obj[implementation](
|
|
name,
|
|
callback,
|
|
this
|
|
),
|
|
this
|
|
);
|
|
};
|
|
},
|
|
),
|
|
(Events.bind = Events.on),
|
|
(Events.unbind = Events.off),
|
|
_.extend(
|
|
Backbone,
|
|
Events
|
|
);
|
|
var Model = (Backbone.Model = function (
|
|
attributes, options
|
|
) {
|
|
var attrs = attributes || {
|
|
};
|
|
options || (options = {
|
|
}),
|
|
(this.cid = _.uniqueId(
|
|
"c"
|
|
)),
|
|
(this.attributes = {
|
|
}),
|
|
options.collection && (this.collection = options.collection),
|
|
options.parse && (attrs = this.parse(
|
|
attrs,
|
|
options
|
|
) || {
|
|
}),
|
|
(attrs = _.defaults(
|
|
{
|
|
},
|
|
attrs,
|
|
_.result(
|
|
this,
|
|
"defaults"
|
|
)
|
|
)),
|
|
this.set(
|
|
attrs,
|
|
options
|
|
),
|
|
(this.changed = {
|
|
}),
|
|
this.initialize.apply(
|
|
this,
|
|
arguments
|
|
);
|
|
});
|
|
_.extend(
|
|
Model.prototype,
|
|
Events,
|
|
{
|
|
changed: null,
|
|
validationError: null,
|
|
idAttribute: "id",
|
|
initialize: function (
|
|
) {},
|
|
toJSON: function (
|
|
options
|
|
) {
|
|
return _.clone(
|
|
this.attributes
|
|
);
|
|
},
|
|
sync: function (
|
|
) {
|
|
return Backbone.sync.apply(
|
|
this,
|
|
arguments
|
|
);
|
|
},
|
|
get: function (
|
|
attr
|
|
) {
|
|
return this.attributes[attr];
|
|
},
|
|
escape: function (
|
|
attr
|
|
) {
|
|
return _.escape(
|
|
this.get(
|
|
attr
|
|
)
|
|
);
|
|
},
|
|
has: function (
|
|
attr
|
|
) {
|
|
return null != this.get(
|
|
attr
|
|
);
|
|
},
|
|
set: function (
|
|
key, val, options
|
|
) {
|
|
var attr, attrs, unset, changes, silent, changing, prev, current;
|
|
if (null == key) return this;
|
|
if (
|
|
("object" == typeof key
|
|
? ((attrs = key), (options = val))
|
|
: ((attrs = {
|
|
})[key] = val),
|
|
options || (options = {
|
|
}),
|
|
!this._validate(
|
|
attrs,
|
|
options
|
|
))
|
|
)
|
|
return !1;
|
|
for (attr in ((unset = options.unset),
|
|
(silent = options.silent),
|
|
(changes = []),
|
|
(changing = this._changing),
|
|
(this._changing = !0),
|
|
changing ||
|
|
((this._previousAttributes = _.clone(
|
|
this.attributes
|
|
)),
|
|
(this.changed = {
|
|
})),
|
|
(current = this.attributes),
|
|
(prev = this._previousAttributes),
|
|
this.idAttribute in attrs && (this.id = attrs[this.idAttribute]),
|
|
attrs))
|
|
(val = attrs[attr]),
|
|
_.isEqual(
|
|
current[attr],
|
|
val
|
|
) || changes.push(
|
|
attr
|
|
),
|
|
_.isEqual(
|
|
prev[attr],
|
|
val
|
|
)
|
|
? delete this.changed[attr]
|
|
: (this.changed[attr] = val),
|
|
unset ? delete current[attr] : (current[attr] = val);
|
|
if (!silent) {
|
|
changes.length && (this._pending = !0);
|
|
for (var i = 0, l = changes.length; i < l; i++)
|
|
this.trigger(
|
|
"change:" + changes[i],
|
|
this,
|
|
current[changes[i]],
|
|
options,
|
|
);
|
|
}
|
|
if (changing) return this;
|
|
if (!silent)
|
|
for (; this._pending; )
|
|
(this._pending = !1), this.trigger(
|
|
"change",
|
|
this,
|
|
options
|
|
);
|
|
return (this._pending = !1), (this._changing = !1), this;
|
|
},
|
|
unset: function (
|
|
attr, options
|
|
) {
|
|
return this.set(
|
|
attr,
|
|
void 0,
|
|
_.extend(
|
|
{
|
|
},
|
|
options,
|
|
{
|
|
unset: !0,
|
|
}
|
|
)
|
|
);
|
|
},
|
|
clear: function (
|
|
options
|
|
) {
|
|
var attrs = {
|
|
};
|
|
for (var key in this.attributes) attrs[key] = void 0;
|
|
return this.set(
|
|
attrs,
|
|
_.extend(
|
|
{
|
|
},
|
|
options,
|
|
{
|
|
unset: !0,
|
|
}
|
|
)
|
|
);
|
|
},
|
|
hasChanged: function (
|
|
attr
|
|
) {
|
|
return null == attr
|
|
? !_.isEmpty(
|
|
this.changed
|
|
)
|
|
: _.has(
|
|
this.changed,
|
|
attr
|
|
);
|
|
},
|
|
changedAttributes: function (
|
|
diff
|
|
) {
|
|
if (!diff) return !!this.hasChanged(
|
|
) && _.clone(
|
|
this.changed
|
|
);
|
|
var val,
|
|
changed = !1,
|
|
old = this._changing ? this._previousAttributes : this.attributes;
|
|
for (var attr in diff)
|
|
_.isEqual(
|
|
old[attr], (
|
|
val = diff[attr])
|
|
) ||
|
|
((changed || (changed = {
|
|
}))[attr] = val);
|
|
return changed;
|
|
},
|
|
previous: function (
|
|
attr
|
|
) {
|
|
return null != attr && this._previousAttributes
|
|
? this._previousAttributes[attr]
|
|
: null;
|
|
},
|
|
previousAttributes: function (
|
|
) {
|
|
return _.clone(
|
|
this._previousAttributes
|
|
);
|
|
},
|
|
fetch: function (
|
|
options
|
|
) {
|
|
void 0 === (options = options
|
|
? _.clone(
|
|
options
|
|
)
|
|
: {
|
|
}).parse &&
|
|
(options.parse = !0);
|
|
var model = this,
|
|
success = options.success;
|
|
return (
|
|
(options.success = function (
|
|
resp
|
|
) {
|
|
if (!model.set(
|
|
model.parse(
|
|
resp,
|
|
options
|
|
),
|
|
options
|
|
)) return !1;
|
|
success && success(
|
|
model,
|
|
resp,
|
|
options
|
|
),
|
|
model.trigger(
|
|
"sync",
|
|
model,
|
|
resp,
|
|
options
|
|
);
|
|
}),
|
|
wrapError(
|
|
this,
|
|
options
|
|
),
|
|
this.sync(
|
|
"read",
|
|
this,
|
|
options
|
|
)
|
|
);
|
|
},
|
|
save: function (
|
|
key, val, options
|
|
) {
|
|
var attrs,
|
|
method,
|
|
xhr,
|
|
attributes = this.attributes;
|
|
if (
|
|
(null == key || "object" == typeof key
|
|
? ((attrs = key), (options = val))
|
|
: ((attrs = {
|
|
})[key] = val),
|
|
(options = _.extend(
|
|
{
|
|
validate: !0,
|
|
},
|
|
options
|
|
)),
|
|
attrs && !options.wait)
|
|
) {
|
|
if (!this.set(
|
|
attrs,
|
|
options
|
|
)) return !1;
|
|
} else if (!this._validate(
|
|
attrs,
|
|
options
|
|
)) return !1;
|
|
attrs &&
|
|
options.wait &&
|
|
(this.attributes = _.extend(
|
|
{
|
|
},
|
|
attributes,
|
|
attrs
|
|
)),
|
|
void 0 === options.parse && (options.parse = !0);
|
|
var model = this,
|
|
success = options.success;
|
|
return (
|
|
(options.success = function (
|
|
resp
|
|
) {
|
|
model.attributes = attributes;
|
|
var serverAttrs = model.parse(
|
|
resp,
|
|
options
|
|
);
|
|
if (
|
|
(options.wait && (serverAttrs = _.extend(
|
|
attrs || {
|
|
},
|
|
serverAttrs
|
|
)),
|
|
_.isObject(
|
|
serverAttrs
|
|
) && !model.set(
|
|
serverAttrs,
|
|
options
|
|
))
|
|
)
|
|
return !1;
|
|
success && success(
|
|
model,
|
|
resp,
|
|
options
|
|
),
|
|
model.trigger(
|
|
"sync",
|
|
model,
|
|
resp,
|
|
options
|
|
);
|
|
}),
|
|
wrapError(
|
|
this,
|
|
options
|
|
),
|
|
"patch" ===
|
|
(method = this.isNew(
|
|
)
|
|
? "create"
|
|
: options.patch
|
|
? "patch"
|
|
: "update") && (options.attrs = attrs),
|
|
(xhr = this.sync(
|
|
method,
|
|
this,
|
|
options
|
|
)),
|
|
attrs && options.wait && (this.attributes = attributes),
|
|
xhr
|
|
);
|
|
},
|
|
destroy: function (
|
|
options
|
|
) {
|
|
options = options
|
|
? _.clone(
|
|
options
|
|
)
|
|
: {
|
|
};
|
|
var model = this,
|
|
success = options.success,
|
|
destroy = function (
|
|
) {
|
|
model.trigger(
|
|
"destroy",
|
|
model,
|
|
model.collection,
|
|
options
|
|
);
|
|
};
|
|
if (
|
|
((options.success = function (
|
|
resp
|
|
) {
|
|
(options.wait || model.isNew(
|
|
)) && destroy(
|
|
),
|
|
success && success(
|
|
model,
|
|
resp,
|
|
options
|
|
),
|
|
model.isNew(
|
|
) || model.trigger(
|
|
"sync",
|
|
model,
|
|
resp,
|
|
options
|
|
);
|
|
}),
|
|
this.isNew(
|
|
))
|
|
)
|
|
return options.success(
|
|
), !1;
|
|
wrapError(
|
|
this,
|
|
options
|
|
);
|
|
var xhr = this.sync(
|
|
"delete",
|
|
this,
|
|
options
|
|
);
|
|
return options.wait || destroy(
|
|
), xhr;
|
|
},
|
|
url: function (
|
|
) {
|
|
var base =
|
|
_.result(
|
|
this,
|
|
"urlRoot"
|
|
) ||
|
|
_.result(
|
|
this.collection,
|
|
"url"
|
|
) ||
|
|
urlError(
|
|
);
|
|
return this.isNew(
|
|
)
|
|
? base
|
|
: base +
|
|
("/" === base.charAt(
|
|
base.length - 1
|
|
)
|
|
? ""
|
|
: "/") +
|
|
encodeURIComponent(
|
|
this.id
|
|
);
|
|
},
|
|
parse: function (
|
|
resp, options
|
|
) {
|
|
return resp;
|
|
},
|
|
clone: function (
|
|
) {
|
|
return new this.constructor(
|
|
this.attributes
|
|
);
|
|
},
|
|
isNew: function (
|
|
) {
|
|
return null == this.id;
|
|
},
|
|
isValid: function (
|
|
options
|
|
) {
|
|
return this._validate(
|
|
{
|
|
},
|
|
_.extend(
|
|
options || {
|
|
},
|
|
{
|
|
validate: !0,
|
|
}
|
|
)
|
|
);
|
|
},
|
|
_validate: function (
|
|
attrs, options
|
|
) {
|
|
if (!options.validate || !this.validate) return !0;
|
|
attrs = _.extend(
|
|
{
|
|
},
|
|
this.attributes,
|
|
attrs
|
|
);
|
|
var error = (this.validationError =
|
|
this.validate(
|
|
attrs,
|
|
options
|
|
) || null);
|
|
return (
|
|
!error ||
|
|
(this.trigger(
|
|
"invalid",
|
|
this,
|
|
error,
|
|
_.extend(
|
|
options,
|
|
{
|
|
validationError: error,
|
|
}
|
|
),
|
|
),
|
|
!1)
|
|
);
|
|
},
|
|
}
|
|
);
|
|
_.each(
|
|
["keys", "values", "pairs", "invert", "pick", "omit",],
|
|
function (
|
|
method
|
|
) {
|
|
Model.prototype[method] = function (
|
|
) {
|
|
var args = slice.call(
|
|
arguments
|
|
);
|
|
return args.unshift(
|
|
this.attributes
|
|
), _[method].apply(
|
|
_,
|
|
args
|
|
);
|
|
};
|
|
},
|
|
);
|
|
var Collection = (Backbone.Collection = function (
|
|
models, options
|
|
) {
|
|
options || (options = {
|
|
}),
|
|
options.model && (this.model = options.model),
|
|
void 0 !== options.comparator && (this.comparator = options.comparator),
|
|
this._reset(
|
|
),
|
|
this.initialize.apply(
|
|
this,
|
|
arguments
|
|
),
|
|
models && this.reset(
|
|
models,
|
|
_.extend(
|
|
{
|
|
silent: !0,
|
|
},
|
|
options
|
|
)
|
|
);
|
|
}),
|
|
setOptions = {
|
|
add: !0,
|
|
remove: !0,
|
|
merge: !0,
|
|
},
|
|
addOptions = {
|
|
add: !0,
|
|
remove: !1,
|
|
};
|
|
_.extend(
|
|
Collection.prototype,
|
|
Events,
|
|
{
|
|
model: Model,
|
|
initialize: function (
|
|
) {},
|
|
toJSON: function (
|
|
options
|
|
) {
|
|
return this.map(
|
|
function (
|
|
model
|
|
) {
|
|
return model.toJSON(
|
|
options
|
|
);
|
|
}
|
|
);
|
|
},
|
|
sync: function (
|
|
) {
|
|
return Backbone.sync.apply(
|
|
this,
|
|
arguments
|
|
);
|
|
},
|
|
add: function (
|
|
models, options
|
|
) {
|
|
return this.set(
|
|
models,
|
|
_.extend(
|
|
{
|
|
merge: !1,
|
|
},
|
|
options,
|
|
addOptions
|
|
)
|
|
);
|
|
},
|
|
remove: function (
|
|
models, options
|
|
) {
|
|
var i,
|
|
l,
|
|
index,
|
|
model,
|
|
singular = !_.isArray(
|
|
models
|
|
);
|
|
for (
|
|
options || (options = {
|
|
}),
|
|
i = 0,
|
|
l = (models = singular
|
|
? [models,]
|
|
: _.clone(
|
|
models
|
|
)).length;
|
|
i < l;
|
|
i++
|
|
)
|
|
(model = models[i] = this.get(
|
|
models[i]
|
|
)) &&
|
|
(delete this._byId[model.id],
|
|
delete this._byId[model.cid],
|
|
(index = this.indexOf(
|
|
model
|
|
)),
|
|
this.models.splice(
|
|
index,
|
|
1
|
|
),
|
|
this.length--,
|
|
options.silent ||
|
|
((options.index = index),
|
|
model.trigger(
|
|
"remove",
|
|
model,
|
|
this,
|
|
options
|
|
)),
|
|
this._removeReference(
|
|
model
|
|
));
|
|
return singular ? models[0] : models;
|
|
},
|
|
set: function (
|
|
models, options
|
|
) {
|
|
(options = _.defaults(
|
|
{
|
|
},
|
|
options,
|
|
setOptions
|
|
)).parse &&
|
|
(models = this.parse(
|
|
models,
|
|
options
|
|
));
|
|
var i,
|
|
l,
|
|
id,
|
|
model,
|
|
attrs,
|
|
existing,
|
|
sort,
|
|
singular = !_.isArray(
|
|
models
|
|
);
|
|
models = singular
|
|
? (models ? [models,] : [])
|
|
: _.clone(
|
|
models
|
|
);
|
|
var at = options.at,
|
|
targetModel = this.model,
|
|
sortable = this.comparator && null == at && !1 !== options.sort,
|
|
sortAttr = _.isString(
|
|
this.comparator
|
|
)
|
|
? this.comparator
|
|
: null,
|
|
toAdd = [],
|
|
toRemove = [],
|
|
modelMap = {
|
|
},
|
|
add = options.add,
|
|
merge = options.merge,
|
|
remove = options.remove,
|
|
order = !(sortable || !add || !remove) && [];
|
|
for (i = 0, l = models.length; i < l; i++) {
|
|
if (
|
|
((id =
|
|
(attrs = models[i]) instanceof Model
|
|
? (model = attrs)
|
|
: attrs[targetModel.prototype.idAttribute]),
|
|
(existing = this.get(
|
|
id
|
|
)))
|
|
)
|
|
remove && (modelMap[existing.cid] = !0),
|
|
merge &&
|
|
((attrs = attrs === model ? model.attributes : attrs),
|
|
options.parse && (attrs = existing.parse(
|
|
attrs,
|
|
options
|
|
)),
|
|
existing.set(
|
|
attrs,
|
|
options
|
|
),
|
|
sortable &&
|
|
!sort &&
|
|
existing.hasChanged(
|
|
sortAttr
|
|
) &&
|
|
(sort = !0)),
|
|
(models[i] = existing);
|
|
else if (add) {
|
|
if (!(model = models[i] = this._prepareModel(
|
|
attrs,
|
|
options
|
|
)))
|
|
continue;
|
|
toAdd.push(
|
|
model
|
|
),
|
|
model.on(
|
|
"all",
|
|
this._onModelEvent,
|
|
this
|
|
),
|
|
(this._byId[model.cid] = model),
|
|
null != model.id && (this._byId[model.id] = model);
|
|
}
|
|
order && order.push(
|
|
existing || model
|
|
);
|
|
}
|
|
if (remove) {
|
|
for (i = 0, l = this.length; i < l; ++i)
|
|
modelMap[(model = this.models[i]).cid] || toRemove.push(
|
|
model
|
|
);
|
|
toRemove.length && this.remove(
|
|
toRemove,
|
|
options
|
|
);
|
|
}
|
|
if (toAdd.length || (order && order.length))
|
|
if (
|
|
(sortable && (sort = !0), (this.length += toAdd.length), null != at)
|
|
)
|
|
for (i = 0, l = toAdd.length; i < l; i++)
|
|
this.models.splice(
|
|
at + i,
|
|
0,
|
|
toAdd[i]
|
|
);
|
|
else {
|
|
order && (this.models.length = 0);
|
|
var orderedModels = order || toAdd;
|
|
for (i = 0, l = orderedModels.length; i < l; i++)
|
|
this.models.push(
|
|
orderedModels[i]
|
|
);
|
|
}
|
|
if ((sort && this.sort(
|
|
{
|
|
silent: !0,
|
|
}
|
|
), !options.silent)) {
|
|
for (i = 0, l = toAdd.length; i < l; i++)
|
|
(model = toAdd[i]).trigger(
|
|
"add",
|
|
model,
|
|
this,
|
|
options
|
|
);
|
|
(sort || (order && order.length)) &&
|
|
this.trigger(
|
|
"sort",
|
|
this,
|
|
options
|
|
);
|
|
}
|
|
return singular ? models[0] : models;
|
|
},
|
|
reset: function (
|
|
models, options
|
|
) {
|
|
options || (options = {
|
|
});
|
|
for (var i = 0, l = this.models.length; i < l; i++)
|
|
this._removeReference(
|
|
this.models[i]
|
|
);
|
|
return (
|
|
(options.previousModels = this.models),
|
|
this._reset(
|
|
),
|
|
(models = this.add(
|
|
models,
|
|
_.extend(
|
|
{
|
|
silent: !0,
|
|
},
|
|
options
|
|
)
|
|
)),
|
|
options.silent || this.trigger(
|
|
"reset",
|
|
this,
|
|
options
|
|
),
|
|
models
|
|
);
|
|
},
|
|
push: function (
|
|
model, options
|
|
) {
|
|
return this.add(
|
|
model,
|
|
_.extend(
|
|
{
|
|
at: this.length,
|
|
},
|
|
options
|
|
)
|
|
);
|
|
},
|
|
pop: function (
|
|
options
|
|
) {
|
|
var model = this.at(
|
|
this.length - 1
|
|
);
|
|
return this.remove(
|
|
model,
|
|
options
|
|
), model;
|
|
},
|
|
unshift: function (
|
|
model, options
|
|
) {
|
|
return this.add(
|
|
model,
|
|
_.extend(
|
|
{
|
|
at: 0,
|
|
},
|
|
options
|
|
)
|
|
);
|
|
},
|
|
shift: function (
|
|
options
|
|
) {
|
|
var model = this.at(
|
|
0
|
|
);
|
|
return this.remove(
|
|
model,
|
|
options
|
|
), model;
|
|
},
|
|
slice: function (
|
|
) {
|
|
return slice.apply(
|
|
this.models,
|
|
arguments
|
|
);
|
|
},
|
|
get: function (
|
|
obj
|
|
) {
|
|
if (null != obj)
|
|
return this._byId[obj.id] || this._byId[obj.cid] || this._byId[obj];
|
|
},
|
|
at: function (
|
|
index
|
|
) {
|
|
return this.models[index];
|
|
},
|
|
where: function (
|
|
attrs, first
|
|
) {
|
|
return _.isEmpty(
|
|
attrs
|
|
)
|
|
? first
|
|
? void 0
|
|
: []
|
|
: this[first ? "find" : "filter"](
|
|
function (
|
|
model
|
|
) {
|
|
for (var key in attrs) if (attrs[key] !== model.get(
|
|
key
|
|
)) return !1;
|
|
return !0;
|
|
}
|
|
);
|
|
},
|
|
findWhere: function (
|
|
attrs
|
|
) {
|
|
return this.where(
|
|
attrs,
|
|
!0
|
|
);
|
|
},
|
|
sort: function (
|
|
options
|
|
) {
|
|
if (!this.comparator)
|
|
throw new Error(
|
|
"Cannot sort a set without a comparator"
|
|
);
|
|
return (
|
|
options || (options = {
|
|
}),
|
|
_.isString(
|
|
this.comparator
|
|
) || 1 === this.comparator.length
|
|
? (this.models = this.sortBy(
|
|
this.comparator,
|
|
this
|
|
))
|
|
: this.models.sort(
|
|
_.bind(
|
|
this.comparator,
|
|
this
|
|
)
|
|
),
|
|
options.silent || this.trigger(
|
|
"sort",
|
|
this,
|
|
options
|
|
),
|
|
this
|
|
);
|
|
},
|
|
pluck: function (
|
|
attr
|
|
) {
|
|
return _.invoke(
|
|
this.models,
|
|
"get",
|
|
attr
|
|
);
|
|
},
|
|
fetch: function (
|
|
options
|
|
) {
|
|
void 0 === (options = options
|
|
? _.clone(
|
|
options
|
|
)
|
|
: {
|
|
}).parse &&
|
|
(options.parse = !0);
|
|
var success = options.success,
|
|
collection = this;
|
|
return (
|
|
(options.success = function (
|
|
resp
|
|
) {
|
|
var method = options.reset ? "reset" : "set";
|
|
collection[method](
|
|
resp,
|
|
options
|
|
),
|
|
success && success(
|
|
collection,
|
|
resp,
|
|
options
|
|
),
|
|
collection.trigger(
|
|
"sync",
|
|
collection,
|
|
resp,
|
|
options
|
|
);
|
|
}),
|
|
wrapError(
|
|
this,
|
|
options
|
|
),
|
|
this.sync(
|
|
"read",
|
|
this,
|
|
options
|
|
)
|
|
);
|
|
},
|
|
create: function (
|
|
model, options
|
|
) {
|
|
if (
|
|
((options = options
|
|
? _.clone(
|
|
options
|
|
)
|
|
: {
|
|
}),
|
|
!(model = this._prepareModel(
|
|
model,
|
|
options
|
|
)))
|
|
)
|
|
return !1;
|
|
options.wait || this.add(
|
|
model,
|
|
options
|
|
);
|
|
var collection = this,
|
|
success = options.success;
|
|
return (
|
|
(options.success = function (
|
|
model, resp, options
|
|
) {
|
|
options.wait && collection.add(
|
|
model,
|
|
options
|
|
),
|
|
success && success(
|
|
model,
|
|
resp,
|
|
options
|
|
);
|
|
}),
|
|
model.save(
|
|
null,
|
|
options
|
|
),
|
|
model
|
|
);
|
|
},
|
|
parse: function (
|
|
resp, options
|
|
) {
|
|
return resp;
|
|
},
|
|
clone: function (
|
|
) {
|
|
return new this.constructor(
|
|
this.models
|
|
);
|
|
},
|
|
_reset: function (
|
|
) {
|
|
(this.length = 0), (this.models = []), (this._byId = {
|
|
});
|
|
},
|
|
_prepareModel: function (
|
|
attrs, options
|
|
) {
|
|
if (attrs instanceof Model)
|
|
return attrs.collection || (attrs.collection = this), attrs;
|
|
(options = options
|
|
? _.clone(
|
|
options
|
|
)
|
|
: {
|
|
}).collection = this;
|
|
var model = new this.model(
|
|
attrs,
|
|
options
|
|
);
|
|
return model.validationError
|
|
? (this.trigger(
|
|
"invalid",
|
|
this,
|
|
model.validationError,
|
|
options
|
|
), !1)
|
|
: model;
|
|
},
|
|
_removeReference: function (
|
|
model
|
|
) {
|
|
this === model.collection && delete model.collection,
|
|
model.off(
|
|
"all",
|
|
this._onModelEvent,
|
|
this
|
|
);
|
|
},
|
|
_onModelEvent: function (
|
|
event, model, collection, options
|
|
) {
|
|
(("add" !== event && "remove" !== event) || collection === this) &&
|
|
("destroy" === event && this.remove(
|
|
model,
|
|
options
|
|
),
|
|
model &&
|
|
event === "change:" + model.idAttribute &&
|
|
(delete this._byId[model.previous(
|
|
model.idAttribute
|
|
)],
|
|
null != model.id && (this._byId[model.id] = model)),
|
|
this.trigger.apply(
|
|
this,
|
|
arguments
|
|
));
|
|
},
|
|
}
|
|
);
|
|
_.each(
|
|
[
|
|
"forEach",
|
|
"each",
|
|
"map",
|
|
"collect",
|
|
"reduce",
|
|
"foldl",
|
|
"inject",
|
|
"reduceRight",
|
|
"foldr",
|
|
"find",
|
|
"detect",
|
|
"filter",
|
|
"select",
|
|
"reject",
|
|
"every",
|
|
"all",
|
|
"some",
|
|
"any",
|
|
"include",
|
|
"contains",
|
|
"invoke",
|
|
"max",
|
|
"min",
|
|
"toArray",
|
|
"size",
|
|
"first",
|
|
"head",
|
|
"take",
|
|
"initial",
|
|
"rest",
|
|
"tail",
|
|
"drop",
|
|
"last",
|
|
"without",
|
|
"difference",
|
|
"indexOf",
|
|
"shuffle",
|
|
"lastIndexOf",
|
|
"isEmpty",
|
|
"chain",
|
|
],
|
|
function (
|
|
method
|
|
) {
|
|
Collection.prototype[method] = function (
|
|
) {
|
|
var args = slice.call(
|
|
arguments
|
|
);
|
|
return args.unshift(
|
|
this.models
|
|
), _[method].apply(
|
|
_,
|
|
args
|
|
);
|
|
};
|
|
},
|
|
);
|
|
_.each(
|
|
["groupBy", "countBy", "sortBy",],
|
|
function (
|
|
method
|
|
) {
|
|
Collection.prototype[method] = function (
|
|
value, context
|
|
) {
|
|
var iterator = _.isFunction(
|
|
value
|
|
)
|
|
? value
|
|
: function (
|
|
model
|
|
) {
|
|
return model.get(
|
|
value
|
|
);
|
|
};
|
|
return _[method](
|
|
this.models,
|
|
iterator,
|
|
context
|
|
);
|
|
};
|
|
}
|
|
);
|
|
var View = (Backbone.View = function (
|
|
options
|
|
) {
|
|
(this.cid = _.uniqueId(
|
|
"view"
|
|
)),
|
|
options || (options = {
|
|
}),
|
|
_.extend(
|
|
this,
|
|
_.pick(
|
|
options,
|
|
viewOptions
|
|
)
|
|
),
|
|
this._ensureElement(
|
|
),
|
|
this.initialize.apply(
|
|
this,
|
|
arguments
|
|
),
|
|
this.delegateEvents(
|
|
);
|
|
}),
|
|
delegateEventSplitter = /^(\S+)\s*(.*)$/,
|
|
viewOptions = [
|
|
"model",
|
|
"collection",
|
|
"el",
|
|
"id",
|
|
"attributes",
|
|
"className",
|
|
"tagName",
|
|
"events",
|
|
];
|
|
_.extend(
|
|
View.prototype,
|
|
Events,
|
|
{
|
|
tagName: "div",
|
|
$: function (
|
|
selector
|
|
) {
|
|
return this.$el.find(
|
|
selector
|
|
);
|
|
},
|
|
initialize: function (
|
|
) {},
|
|
render: function (
|
|
) {
|
|
return this;
|
|
},
|
|
remove: function (
|
|
) {
|
|
return this.$el.remove(
|
|
), this.stopListening(
|
|
), this;
|
|
},
|
|
setElement: function (
|
|
element, delegate
|
|
) {
|
|
return (
|
|
this.$el && this.undelegateEvents(
|
|
),
|
|
(this.$el =
|
|
element instanceof Backbone.$
|
|
? element
|
|
: Backbone.$(
|
|
element
|
|
)),
|
|
(this.el = this.$el[0]),
|
|
!1 !== delegate && this.delegateEvents(
|
|
),
|
|
this
|
|
);
|
|
},
|
|
delegateEvents: function (
|
|
events
|
|
) {
|
|
if (!events && !(events = _.result(
|
|
this,
|
|
"events"
|
|
))) return this;
|
|
for (var key in (this.undelegateEvents(
|
|
), events)) {
|
|
var method = events[key];
|
|
if ((_.isFunction(
|
|
method
|
|
) || (method = this[events[key]]), method)) {
|
|
var match = key.match(
|
|
delegateEventSplitter
|
|
),
|
|
eventName = match[1],
|
|
selector = match[2];
|
|
(method = _.bind(
|
|
method,
|
|
this
|
|
)),
|
|
(eventName += ".delegateEvents" + this.cid),
|
|
"" === selector
|
|
? this.$el.on(
|
|
eventName,
|
|
method
|
|
)
|
|
: this.$el.on(
|
|
eventName,
|
|
selector,
|
|
method
|
|
);
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
undelegateEvents: function (
|
|
) {
|
|
return this.$el.off(
|
|
".delegateEvents" + this.cid
|
|
), this;
|
|
},
|
|
_ensureElement: function (
|
|
) {
|
|
if (this.el) this.setElement(
|
|
_.result(
|
|
this,
|
|
"el"
|
|
),
|
|
!1
|
|
);
|
|
else {
|
|
var attrs = _.extend(
|
|
{
|
|
},
|
|
_.result(
|
|
this,
|
|
"attributes"
|
|
)
|
|
);
|
|
this.id && (attrs.id = _.result(
|
|
this,
|
|
"id"
|
|
)),
|
|
this.className && (attrs.class = _.result(
|
|
this,
|
|
"className"
|
|
));
|
|
var $el = Backbone.$(
|
|
"<" + _.result(
|
|
this,
|
|
"tagName"
|
|
) + ">"
|
|
).attr(
|
|
attrs
|
|
);
|
|
this.setElement(
|
|
$el,
|
|
!1
|
|
);
|
|
}
|
|
},
|
|
}
|
|
),
|
|
(Backbone.sync = function (
|
|
method, model, options
|
|
) {
|
|
var type = methodMap[method];
|
|
_.defaults(
|
|
options || (options = {
|
|
}),
|
|
{
|
|
emulateHTTP: Backbone.emulateHTTP,
|
|
emulateJSON: Backbone.emulateJSON,
|
|
}
|
|
);
|
|
var params = {
|
|
type: type,
|
|
dataType: "json",
|
|
};
|
|
if (
|
|
(options.url || (params.url = _.result(
|
|
model,
|
|
"url"
|
|
) || urlError(
|
|
)),
|
|
null != options.data ||
|
|
!model ||
|
|
("create" !== method && "update" !== method && "patch" !== method) ||
|
|
((params.contentType = "application/json"),
|
|
(params.data = JSON.stringify(
|
|
options.attrs || model.toJSON(
|
|
options
|
|
),
|
|
))),
|
|
options.emulateJSON &&
|
|
((params.contentType = "application/x-www-form-urlencoded"),
|
|
(params.data = params.data
|
|
? {
|
|
model: params.data,
|
|
}
|
|
: {
|
|
})),
|
|
options.emulateHTTP &&
|
|
("PUT" === type || "DELETE" === type || "PATCH" === type))
|
|
) {
|
|
(params.type = "POST"),
|
|
options.emulateJSON && (params.data._method = type);
|
|
var beforeSend = options.beforeSend;
|
|
options.beforeSend = function (
|
|
xhr
|
|
) {
|
|
if (
|
|
(xhr.setRequestHeader(
|
|
"X-HTTP-Method-Override",
|
|
type
|
|
), beforeSend)
|
|
)
|
|
return beforeSend.apply(
|
|
this,
|
|
arguments
|
|
);
|
|
};
|
|
}
|
|
"GET" === params.type || options.emulateJSON || (params.processData = !1),
|
|
"PATCH" === params.type &&
|
|
noXhrPatch &&
|
|
(params.xhr = function (
|
|
) {
|
|
return new ActiveXObject(
|
|
"Microsoft.XMLHTTP"
|
|
);
|
|
});
|
|
var xhr = (options.xhr = Backbone.ajax(
|
|
_.extend(
|
|
params,
|
|
options
|
|
)
|
|
));
|
|
return model.trigger(
|
|
"request",
|
|
model,
|
|
xhr,
|
|
options
|
|
), xhr;
|
|
});
|
|
var noXhrPatch = !(
|
|
"undefined" == typeof window ||
|
|
!window.ActiveXObject ||
|
|
(window.XMLHttpRequest && new XMLHttpRequest(
|
|
).dispatchEvent)
|
|
),
|
|
methodMap = {
|
|
create: "POST",
|
|
update: "PUT",
|
|
patch: "PATCH",
|
|
delete: "DELETE",
|
|
read: "GET",
|
|
};
|
|
Backbone.ajax = function (
|
|
) {
|
|
return Backbone.$.ajax.apply(
|
|
Backbone.$,
|
|
arguments
|
|
);
|
|
};
|
|
var Router = (Backbone.Router = function (
|
|
options
|
|
) {
|
|
options || (options = {
|
|
}),
|
|
options.routes && (this.routes = options.routes),
|
|
this._bindRoutes(
|
|
),
|
|
this.initialize.apply(
|
|
this,
|
|
arguments
|
|
);
|
|
}),
|
|
optionalParam = /\((.*?)\)/g,
|
|
namedParam = /(\(\?)?:\w+/g,
|
|
splatParam = /\*\w+/g,
|
|
escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
|
|
_.extend(
|
|
Router.prototype,
|
|
Events,
|
|
{
|
|
initialize: function (
|
|
) {},
|
|
route: function (
|
|
route, name, callback
|
|
) {
|
|
_.isRegExp(
|
|
route
|
|
) || (route = this._routeToRegExp(
|
|
route
|
|
)),
|
|
_.isFunction(
|
|
name
|
|
) && ((callback = name), (name = "")),
|
|
callback || (callback = this[name]);
|
|
var router = this;
|
|
return (
|
|
Backbone.history.route(
|
|
route,
|
|
function (
|
|
fragment
|
|
) {
|
|
var args = router._extractParameters(
|
|
route,
|
|
fragment
|
|
);
|
|
callback && callback.apply(
|
|
router,
|
|
args
|
|
),
|
|
router.trigger.apply(
|
|
router,
|
|
["route:" + name,].concat(
|
|
args
|
|
)
|
|
),
|
|
router.trigger(
|
|
"route",
|
|
name,
|
|
args
|
|
),
|
|
Backbone.history.trigger(
|
|
"route",
|
|
router,
|
|
name,
|
|
args
|
|
);
|
|
}
|
|
),
|
|
this
|
|
);
|
|
},
|
|
navigate: function (
|
|
fragment, options
|
|
) {
|
|
return Backbone.history.navigate(
|
|
fragment,
|
|
options
|
|
), this;
|
|
},
|
|
_bindRoutes: function (
|
|
) {
|
|
if (this.routes) {
|
|
this.routes = _.result(
|
|
this,
|
|
"routes"
|
|
);
|
|
for (
|
|
var route, routes = _.keys(
|
|
this.routes
|
|
);
|
|
null != (route = routes.pop(
|
|
));
|
|
|
|
)
|
|
this.route(
|
|
route,
|
|
this.routes[route]
|
|
);
|
|
}
|
|
},
|
|
_routeToRegExp: function (
|
|
route
|
|
) {
|
|
return (
|
|
(route = route
|
|
.replace(
|
|
escapeRegExp,
|
|
"\\$&"
|
|
)
|
|
.replace(
|
|
optionalParam,
|
|
"(?:$1)?"
|
|
)
|
|
.replace(
|
|
namedParam,
|
|
function (
|
|
match, optional
|
|
) {
|
|
return optional ? match : "([^/]+)";
|
|
}
|
|
)
|
|
.replace(
|
|
splatParam,
|
|
"(.*?)"
|
|
)),
|
|
new RegExp(
|
|
"^" + route + "$"
|
|
)
|
|
);
|
|
},
|
|
_extractParameters: function (
|
|
route, fragment
|
|
) {
|
|
var params = route.exec(
|
|
fragment
|
|
).slice(
|
|
1
|
|
);
|
|
return _.map(
|
|
params,
|
|
function (
|
|
param
|
|
) {
|
|
return param
|
|
? decodeURIComponent(
|
|
param
|
|
)
|
|
: null;
|
|
}
|
|
);
|
|
},
|
|
}
|
|
);
|
|
var History = (Backbone.History = function (
|
|
) {
|
|
(this.handlers = []),
|
|
_.bindAll(
|
|
this,
|
|
"checkUrl"
|
|
),
|
|
"undefined" != typeof window &&
|
|
((this.location = window.location), (this.history = window.history));
|
|
}),
|
|
routeStripper = /^[#\/]|\s+$/g,
|
|
rootStripper = /^\/+|\/+$/g,
|
|
isExplorer = /msie [\w.]+/,
|
|
trailingSlash = /\/$/,
|
|
pathStripper = /[?#].*$/;
|
|
(History.started = !1),
|
|
_.extend(
|
|
History.prototype,
|
|
Events,
|
|
{
|
|
interval: 50,
|
|
getHash: function (
|
|
window
|
|
) {
|
|
var match = (window || this).location.href.match(
|
|
/#(.*)$/
|
|
);
|
|
return match ? match[1] : "";
|
|
},
|
|
getFragment: function (
|
|
fragment, forcePushState
|
|
) {
|
|
if (null == fragment)
|
|
if (this._hasPushState || !this._wantsHashChange || forcePushState) {
|
|
fragment = this.location.pathname;
|
|
var root = this.root.replace(
|
|
trailingSlash,
|
|
""
|
|
);
|
|
fragment.indexOf(
|
|
root
|
|
) || (fragment = fragment.slice(
|
|
root.length
|
|
));
|
|
} else fragment = this.getHash(
|
|
);
|
|
return fragment.replace(
|
|
routeStripper,
|
|
""
|
|
);
|
|
},
|
|
start: function (
|
|
options
|
|
) {
|
|
if (History.started)
|
|
throw new Error(
|
|
"Backbone.history has already been started"
|
|
);
|
|
(History.started = !0),
|
|
(this.options = _.extend(
|
|
{
|
|
root: "/",
|
|
},
|
|
this.options,
|
|
options
|
|
)),
|
|
(this.root = this.options.root),
|
|
(this._wantsHashChange = !1 !== this.options.hashChange),
|
|
(this._wantsPushState = !!this.options.pushState),
|
|
(this._hasPushState = !!(
|
|
this.options.pushState &&
|
|
this.history &&
|
|
this.history.pushState
|
|
));
|
|
var fragment = this.getFragment(
|
|
),
|
|
docMode = document.documentMode,
|
|
oldIE =
|
|
isExplorer.exec(
|
|
navigator.userAgent.toLowerCase(
|
|
)
|
|
) &&
|
|
(!docMode || docMode <= 7);
|
|
(this.root = ("/" + this.root + "/").replace(
|
|
rootStripper,
|
|
"/"
|
|
)),
|
|
oldIE &&
|
|
this._wantsHashChange &&
|
|
((this.iframe = Backbone.$(
|
|
'<iframe src="javascript:0" tabindex="-1" />',
|
|
)
|
|
.hide(
|
|
)
|
|
.appendTo(
|
|
"body"
|
|
)[0].contentWindow),
|
|
this.navigate(
|
|
fragment
|
|
)),
|
|
this._hasPushState
|
|
? Backbone.$(
|
|
window
|
|
).on(
|
|
"popstate",
|
|
this.checkUrl
|
|
)
|
|
: this._wantsHashChange && "onhashchange" in window && !oldIE
|
|
? Backbone.$(
|
|
window
|
|
).on(
|
|
"hashchange",
|
|
this.checkUrl
|
|
)
|
|
: this._wantsHashChange &&
|
|
(this._checkUrlInterval = setInterval(
|
|
this.checkUrl,
|
|
this.interval,
|
|
)),
|
|
(this.fragment = fragment);
|
|
var loc = this.location,
|
|
atRoot = loc.pathname.replace(
|
|
/[^\/]$/,
|
|
"$&/"
|
|
) === this.root;
|
|
if (this._wantsHashChange && this._wantsPushState) {
|
|
if (!this._hasPushState && !atRoot)
|
|
return (
|
|
(this.fragment = this.getFragment(
|
|
null,
|
|
!0
|
|
)),
|
|
this.location.replace(
|
|
this.root + this.location.search + "#" + this.fragment,
|
|
),
|
|
!0
|
|
);
|
|
this._hasPushState &&
|
|
atRoot &&
|
|
loc.hash &&
|
|
((this.fragment = this.getHash(
|
|
).replace(
|
|
routeStripper,
|
|
""
|
|
)),
|
|
this.history.replaceState(
|
|
{
|
|
},
|
|
document.title,
|
|
this.root + this.fragment + loc.search,
|
|
));
|
|
}
|
|
if (!this.options.silent) return this.loadUrl(
|
|
);
|
|
},
|
|
stop: function (
|
|
) {
|
|
Backbone.$(
|
|
window
|
|
)
|
|
.off(
|
|
"popstate",
|
|
this.checkUrl
|
|
)
|
|
.off(
|
|
"hashchange",
|
|
this.checkUrl
|
|
),
|
|
clearInterval(
|
|
this._checkUrlInterval
|
|
),
|
|
(History.started = !1);
|
|
},
|
|
route: function (
|
|
route, callback
|
|
) {
|
|
this.handlers.unshift(
|
|
{
|
|
route: route,
|
|
callback: callback,
|
|
}
|
|
);
|
|
},
|
|
checkUrl: function (
|
|
e
|
|
) {
|
|
var current = this.getFragment(
|
|
);
|
|
if (
|
|
(current === this.fragment &&
|
|
this.iframe &&
|
|
(current = this.getFragment(
|
|
this.getHash(
|
|
this.iframe
|
|
)
|
|
)),
|
|
current === this.fragment)
|
|
)
|
|
return !1;
|
|
this.iframe && this.navigate(
|
|
current
|
|
), this.loadUrl(
|
|
);
|
|
},
|
|
loadUrl: function (
|
|
fragment
|
|
) {
|
|
return (
|
|
(fragment = this.fragment = this.getFragment(
|
|
fragment
|
|
)),
|
|
_.any(
|
|
this.handlers,
|
|
function (
|
|
handler
|
|
) {
|
|
if (handler.route.test(
|
|
fragment
|
|
))
|
|
return handler.callback(
|
|
fragment
|
|
), !0;
|
|
}
|
|
)
|
|
);
|
|
},
|
|
navigate: function (
|
|
fragment, options
|
|
) {
|
|
if (!History.started) return !1;
|
|
(options && !0 !== options) || (options = {
|
|
trigger: !!options,
|
|
});
|
|
var url = this.root + (fragment = this.getFragment(
|
|
fragment || ""
|
|
));
|
|
if (
|
|
((fragment = fragment.replace(
|
|
pathStripper,
|
|
""
|
|
)),
|
|
this.fragment !== fragment)
|
|
) {
|
|
if (
|
|
((this.fragment = fragment),
|
|
"" === fragment && "/" !== url && (url = url.slice(
|
|
0,
|
|
-1
|
|
)),
|
|
this._hasPushState)
|
|
)
|
|
this.history[options.replace ? "replaceState" : "pushState"](
|
|
{
|
|
},
|
|
document.title,
|
|
url,
|
|
);
|
|
else {
|
|
if (!this._wantsHashChange) return this.location.assign(
|
|
url
|
|
);
|
|
this._updateHash(
|
|
this.location,
|
|
fragment,
|
|
options.replace
|
|
),
|
|
this.iframe &&
|
|
fragment !== this.getFragment(
|
|
this.getHash(
|
|
this.iframe
|
|
)
|
|
) &&
|
|
(options.replace || this.iframe.document.open(
|
|
).close(
|
|
),
|
|
this._updateHash(
|
|
this.iframe.location,
|
|
fragment,
|
|
options.replace,
|
|
));
|
|
}
|
|
return options.trigger
|
|
? this.loadUrl(
|
|
fragment
|
|
)
|
|
: void 0;
|
|
}
|
|
},
|
|
_updateHash: function (
|
|
location, fragment, replace
|
|
) {
|
|
if (replace) {
|
|
var href = location.href.replace(
|
|
/(javascript:|#).*$/,
|
|
""
|
|
);
|
|
location.replace(
|
|
href + "#" + fragment
|
|
);
|
|
} else location.hash = "#" + fragment;
|
|
},
|
|
}
|
|
),
|
|
(Backbone.history = new History(
|
|
));
|
|
Model.extend = Collection.extend = Router.extend = View.extend = History.extend = function (
|
|
protoProps,
|
|
staticProps,
|
|
) {
|
|
var child,
|
|
parent = this;
|
|
(child =
|
|
protoProps && _.has(
|
|
protoProps,
|
|
"constructor"
|
|
)
|
|
? protoProps.constructor
|
|
: function (
|
|
) {
|
|
return parent.apply(
|
|
this,
|
|
arguments
|
|
);
|
|
}),
|
|
_.extend(
|
|
child,
|
|
parent,
|
|
staticProps
|
|
);
|
|
var Surrogate = function (
|
|
) {
|
|
this.constructor = child;
|
|
};
|
|
return (
|
|
(Surrogate.prototype = parent.prototype),
|
|
(child.prototype = new Surrogate(
|
|
)),
|
|
protoProps && _.extend(
|
|
child.prototype,
|
|
protoProps
|
|
),
|
|
(child.__super__ = parent.prototype),
|
|
child
|
|
);
|
|
};
|
|
var urlError = function (
|
|
) {
|
|
throw new Error(
|
|
'A "url" property or function must be specified'
|
|
);
|
|
},
|
|
wrapError = function (
|
|
model, options
|
|
) {
|
|
var error = options.error;
|
|
options.error = function (
|
|
resp
|
|
) {
|
|
error && error(
|
|
model,
|
|
resp,
|
|
options
|
|
),
|
|
model.trigger(
|
|
"error",
|
|
model,
|
|
resp,
|
|
options
|
|
);
|
|
};
|
|
};
|
|
}.call(
|
|
this
|
|
));
|