Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
todomvc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Eugene Shen
todomvc
Commits
440ef2b1
Commit
440ef2b1
authored
Jul 13, 2015
by
Arthur Verschaeve
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Typescript-backbone: update dependencies
parent
96d7717a
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
4677 additions
and
2875 deletions
+4677
-2875
examples/typescript-backbone/node_modules/backbone/backbone.js
...les/typescript-backbone/node_modules/backbone/backbone.js
+643
-378
examples/typescript-backbone/node_modules/jquery/dist/jquery.js
...es/typescript-backbone/node_modules/jquery/dist/jquery.js
+9
-4
examples/typescript-backbone/node_modules/lodash/index.js
examples/typescript-backbone/node_modules/lodash/index.js
+4018
-2491
examples/typescript-backbone/node_modules/todomvc-common/base.js
...s/typescript-backbone/node_modules/todomvc-common/base.js
+7
-2
No files found.
examples/typescript-backbone/node_modules/backbone/backbone.js
View file @
440ef2b1
// Backbone.js 1.
1.2
// Backbone.js 1.
2.1
// (c) 2010-201
4
Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// (c) 2010-201
5
Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Backbone may be freely distributed under the MIT license.
// For all details and documentation:
// http://backbonejs.org
(
function
(
root
,
factory
)
{
(
function
(
factory
)
{
// Establish the root object, `window` (`self`) in the browser, or `global` on the server.
// We use `self` instead of `window` for `WebWorker` support.
var
root
=
(
typeof
self
==
'
object
'
&&
self
.
self
==
self
&&
self
)
||
(
typeof
global
==
'
object
'
&&
global
.
global
==
global
&&
global
);
// Set up Backbone appropriately for the environment. Start with AMD.
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
...
...
@@ -17,15 +22,16 @@
// Next for Node.js or CommonJS. jQuery may not be needed as a module.
}
else
if
(
typeof
exports
!==
'
undefined
'
)
{
var
_
=
require
(
'
underscore
'
);
factory
(
root
,
exports
,
_
);
var
_
=
require
(
'
underscore
'
),
$
;
try
{
$
=
require
(
'
jquery
'
);
}
catch
(
e
)
{}
factory
(
root
,
exports
,
_
,
$
);
// Finally, as a browser global.
}
else
{
root
.
Backbone
=
factory
(
root
,
{},
root
.
_
,
(
root
.
jQuery
||
root
.
Zepto
||
root
.
ender
||
root
.
$
));
}
}(
this
,
function
(
root
,
Backbone
,
_
,
$
)
{
}(
function
(
root
,
Backbone
,
_
,
$
)
{
// Initial Setup
// -------------
...
...
@@ -34,14 +40,11 @@
// restored later on, if `noConflict` is used.
var
previousBackbone
=
root
.
Backbone
;
// Create local references to array methods we'll want to use later.
var
array
=
[];
var
push
=
array
.
push
;
var
slice
=
array
.
slice
;
var
splice
=
array
.
splice
;
// Create a local reference to a common array method we'll want to use later.
var
slice
=
[].
slice
;
// Current version of the library. Keep in sync with `package.json`.
Backbone
.
VERSION
=
'
1.
1.2
'
;
Backbone
.
VERSION
=
'
1.
2.1
'
;
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
// the `$` variable.
...
...
@@ -60,11 +63,40 @@
Backbone
.
emulateHTTP
=
false
;
// Turn on `emulateJSON` to support legacy servers that can't deal with direct
// `application/json` requests ... will encode the body as
// `application/json` requests ...
this
will encode the body as
// `application/x-www-form-urlencoded` instead and will send the model in a
// form param named `model`.
Backbone
.
emulateJSON
=
false
;
// Proxy Underscore methods to a Backbone class' prototype using a
// particular attribute as the data argument
var
addMethod
=
function
(
length
,
method
,
attribute
)
{
switch
(
length
)
{
case
1
:
return
function
()
{
return
_
[
method
](
this
[
attribute
]);
};
case
2
:
return
function
(
value
)
{
return
_
[
method
](
this
[
attribute
],
value
);
};
case
3
:
return
function
(
iteratee
,
context
)
{
return
_
[
method
](
this
[
attribute
],
iteratee
,
context
);
};
case
4
:
return
function
(
iteratee
,
defaultVal
,
context
)
{
return
_
[
method
](
this
[
attribute
],
iteratee
,
defaultVal
,
context
);
};
default
:
return
function
()
{
var
args
=
slice
.
call
(
arguments
);
args
.
unshift
(
this
[
attribute
]);
return
_
[
method
].
apply
(
_
,
args
);
};
}
};
var
addUnderscoreMethods
=
function
(
Class
,
methods
,
attribute
)
{
_
.
each
(
methods
,
function
(
length
,
method
)
{
if
(
_
[
method
])
Class
.
prototype
[
method
]
=
addMethod
(
length
,
method
,
attribute
);
});
};
// Backbone.Events
// ---------------
...
...
@@ -78,123 +110,236 @@
// object.on('expand', function(){ alert('expanded'); });
// object.trigger('expand');
//
var
Events
=
Backbone
.
Events
=
{
// Bind an event to a `callback` function. Passing `"all"` will bind
// the callback to all events fired.
on
:
function
(
name
,
callback
,
context
)
{
if
(
!
eventsApi
(
this
,
'
on
'
,
name
,
[
callback
,
context
])
||
!
callback
)
return
this
;
this
.
_events
||
(
this
.
_events
=
{});
var
events
=
this
.
_events
[
name
]
||
(
this
.
_events
[
name
]
=
[]);
events
.
push
({
callback
:
callback
,
context
:
context
,
ctx
:
context
||
this
});
return
this
;
},
var
Events
=
Backbone
.
Events
=
{};
// Bind an event to only be triggered a single time. After the first time
// the callback is invoked, it will be removed.
once
:
function
(
name
,
callback
,
context
)
{
if
(
!
eventsApi
(
this
,
'
once
'
,
name
,
[
callback
,
context
])
||
!
callback
)
return
this
;
var
self
=
this
;
var
once
=
_
.
once
(
function
()
{
self
.
off
(
name
,
once
);
callback
.
apply
(
this
,
arguments
);
});
once
.
_callback
=
callback
;
return
this
.
on
(
name
,
once
,
context
);
},
// Remove one or many callbacks. If `context` is null, removes all
// callbacks with that function. If `callback` is null, removes all
// callbacks for the event. If `name` is null, removes all bound
// callbacks for all events.
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
)
{
this
.
_events
=
void
0
;
return
this
;
// Regular expression used to split event strings.
var
eventSplitter
=
/
\s
+/
;
// Iterates over the standard `event, callback` (as well as the fancy multiple
// space-separated events `"change blur", callback` and jQuery-style event
// maps `{event: callback}`), reducing them by manipulating `memo`.
// Passes a normalized single event name and callback, as well as any
// optional `opts`.
var
eventsApi
=
function
(
iteratee
,
memo
,
name
,
callback
,
opts
)
{
var
i
=
0
,
names
;
if
(
name
&&
typeof
name
===
'
object
'
)
{
// Handle event maps.
if
(
callback
!==
void
0
&&
'
context
'
in
opts
&&
opts
.
context
===
void
0
)
opts
.
context
=
callback
;
for
(
names
=
_
.
keys
(
name
);
i
<
names
.
length
;
i
++
)
{
memo
=
iteratee
(
memo
,
names
[
i
],
name
[
names
[
i
]],
opts
);
}
names
=
name
?
[
name
]
:
_
.
keys
(
this
.
_events
);
for
(
i
=
0
,
l
=
names
.
length
;
i
<
l
;
i
++
)
{
name
=
names
[
i
];
if
(
events
=
this
.
_events
[
name
])
{
this
.
_events
[
name
]
=
retain
=
[];
if
(
callback
||
context
)
{
for
(
j
=
0
,
k
=
events
.
length
;
j
<
k
;
j
++
)
{
ev
=
events
[
j
];
if
((
callback
&&
callback
!==
ev
.
callback
&&
callback
!==
ev
.
callback
.
_callback
)
||
(
context
&&
context
!==
ev
.
context
))
{
retain
.
push
(
ev
);
}
}
}
if
(
!
retain
.
length
)
delete
this
.
_events
[
name
];
}
}
else
if
(
name
&&
eventSplitter
.
test
(
name
))
{
// Handle space separated event names.
for
(
names
=
name
.
split
(
eventSplitter
);
i
<
names
.
length
;
i
++
)
{
memo
=
iteratee
(
memo
,
names
[
i
],
callback
,
opts
);
}
}
else
{
memo
=
iteratee
(
memo
,
name
,
callback
,
opts
);
}
return
memo
;
};
return
this
;
},
// Bind an event to a `callback` function. Passing `"all"` will bind
// the callback to all events fired.
Events
.
on
=
function
(
name
,
callback
,
context
)
{
return
internalOn
(
this
,
name
,
callback
,
context
);
};
// Trigger one or many events, firing all bound callbacks. Callbacks are
// passed the same arguments as `trigger` is, apart from the event name
// (unless you're listening on `"all"`, which will cause your callback to
// receive the true name of the event as the first argument).
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
];
var
allEvents
=
this
.
_events
.
all
;
if
(
events
)
triggerEvents
(
events
,
args
);
if
(
allEvents
)
triggerEvents
(
allEvents
,
arguments
);
return
this
;
},
// An internal use `on` function, used to guard the `listening` argument from
// the public API.
var
internalOn
=
function
(
obj
,
name
,
callback
,
context
,
listening
)
{
obj
.
_events
=
eventsApi
(
onApi
,
obj
.
_events
||
{},
name
,
callback
,
{
context
:
context
,
ctx
:
obj
,
listening
:
listening
});
// Tell this object to stop listening to either specific events ... or
// to every object it's currently listening to.
stopListening
:
function
(
obj
,
name
,
callback
)
{
var
listeningTo
=
this
.
_listeningTo
;
if
(
!
listeningTo
)
return
this
;
var
remove
=
!
name
&&
!
callback
;
if
(
!
callback
&&
typeof
name
===
'
object
'
)
callback
=
this
;
if
(
obj
)
(
listeningTo
=
{})[
obj
.
_listenId
]
=
obj
;
for
(
var
id
in
listeningTo
)
{
obj
=
listeningTo
[
id
];
obj
.
off
(
name
,
callback
,
this
);
if
(
remove
||
_
.
isEmpty
(
obj
.
_events
))
delete
this
.
_listeningTo
[
id
];
}
return
this
;
if
(
listening
)
{
var
listeners
=
obj
.
_listeners
||
(
obj
.
_listeners
=
{});
listeners
[
listening
.
id
]
=
listening
;
}
return
obj
;
};
// Regular expression used to split event strings.
var
eventSplitter
=
/
\s
+/
;
// Inversion-of-control versions of `on`. Tell *this* object to listen to
// an event in another object... keeping track of what it's listening to.
Events
.
listenTo
=
function
(
obj
,
name
,
callback
)
{
if
(
!
obj
)
return
this
;
var
id
=
obj
.
_listenId
||
(
obj
.
_listenId
=
_
.
uniqueId
(
'
l
'
));
var
listeningTo
=
this
.
_listeningTo
||
(
this
.
_listeningTo
=
{});
var
listening
=
listeningTo
[
id
];
// This object is not listening to any other events on `obj` yet.
// Setup the necessary references to track the listening callbacks.
if
(
!
listening
)
{
var
thisId
=
this
.
_listenId
||
(
this
.
_listenId
=
_
.
uniqueId
(
'
l
'
));
listening
=
listeningTo
[
id
]
=
{
obj
:
obj
,
objId
:
id
,
id
:
thisId
,
listeningTo
:
listeningTo
,
count
:
0
};
}
// Bind callbacks on obj, and keep track of them on listening.
internalOn
(
obj
,
name
,
callback
,
this
,
listening
);
return
this
;
};
// The reducing API that adds a callback to the `events` object.
var
onApi
=
function
(
events
,
name
,
callback
,
options
)
{
if
(
callback
)
{
var
handlers
=
events
[
name
]
||
(
events
[
name
]
=
[]);
var
context
=
options
.
context
,
ctx
=
options
.
ctx
,
listening
=
options
.
listening
;
if
(
listening
)
listening
.
count
++
;
handlers
.
push
({
callback
:
callback
,
context
:
context
,
ctx
:
context
||
ctx
,
listening
:
listening
});
}
return
events
;
};
// Remove one or many callbacks. If `context` is null, removes all
// callbacks with that function. If `callback` is null, removes all
// callbacks for the event. If `name` is null, removes all bound
// callbacks for all events.
Events
.
off
=
function
(
name
,
callback
,
context
)
{
if
(
!
this
.
_events
)
return
this
;
this
.
_events
=
eventsApi
(
offApi
,
this
.
_events
,
name
,
callback
,
{
context
:
context
,
listeners
:
this
.
_listeners
});
return
this
;
};
// Tell this object to stop listening to either specific events ... or
// to every object it's currently listening to.
Events
.
stopListening
=
function
(
obj
,
name
,
callback
)
{
var
listeningTo
=
this
.
_listeningTo
;
if
(
!
listeningTo
)
return
this
;
var
ids
=
obj
?
[
obj
.
_listenId
]
:
_
.
keys
(
listeningTo
);
// Implement fancy features of the Events API such as multiple event
// names `"change blur"` and jQuery-style event maps `{change: action}`
// in terms of the existing API.
var
eventsApi
=
function
(
obj
,
action
,
name
,
rest
)
{
if
(
!
name
)
return
true
;
for
(
var
i
=
0
;
i
<
ids
.
length
;
i
++
)
{
var
listening
=
listeningTo
[
ids
[
i
]];
// Handle event maps.
if
(
typeof
name
===
'
object
'
)
{
for
(
var
key
in
name
)
{
obj
[
action
].
apply
(
obj
,
[
key
,
name
[
key
]].
concat
(
rest
));
// If listening doesn't exist, this object is not currently
// listening to obj. Break out early.
if
(
!
listening
)
break
;
listening
.
obj
.
off
(
name
,
callback
,
this
);
}
if
(
_
.
isEmpty
(
listeningTo
))
this
.
_listeningTo
=
void
0
;
return
this
;
};
// The reducing API that removes a callback from the `events` object.
var
offApi
=
function
(
events
,
name
,
callback
,
options
)
{
// No events to consider.
if
(
!
events
)
return
;
var
i
=
0
,
listening
;
var
context
=
options
.
context
,
listeners
=
options
.
listeners
;
// Delete all events listeners and "drop" events.
if
(
!
name
&&
!
callback
&&
!
context
)
{
var
ids
=
_
.
keys
(
listeners
);
for
(;
i
<
ids
.
length
;
i
++
)
{
listening
=
listeners
[
ids
[
i
]];
delete
listeners
[
listening
.
id
];
delete
listening
.
listeningTo
[
listening
.
objId
];
}
return
false
;
return
;
}
// Handle space separated event names.
if
(
eventSplitter
.
test
(
name
))
{
var
names
=
name
.
split
(
eventSplitter
);
for
(
var
i
=
0
,
l
=
names
.
length
;
i
<
l
;
i
++
)
{
obj
[
action
].
apply
(
obj
,
[
names
[
i
]].
concat
(
rest
));
var
names
=
name
?
[
name
]
:
_
.
keys
(
events
);
for
(;
i
<
names
.
length
;
i
++
)
{
name
=
names
[
i
];
var
handlers
=
events
[
name
];
// Bail out if there are no events stored.
if
(
!
handlers
)
break
;
// Replace events if there are any remaining. Otherwise, clean up.
var
remaining
=
[];
for
(
var
j
=
0
;
j
<
handlers
.
length
;
j
++
)
{
var
handler
=
handlers
[
j
];
if
(
callback
&&
callback
!==
handler
.
callback
&&
callback
!==
handler
.
callback
.
_callback
||
context
&&
context
!==
handler
.
context
)
{
remaining
.
push
(
handler
);
}
else
{
listening
=
handler
.
listening
;
if
(
listening
&&
--
listening
.
count
===
0
)
{
delete
listeners
[
listening
.
id
];
delete
listening
.
listeningTo
[
listening
.
objId
];
}
}
}
return
false
;
// Update tail event if the list has any events. Otherwise, clean up.
if
(
remaining
.
length
)
{
events
[
name
]
=
remaining
;
}
else
{
delete
events
[
name
];
}
}
if
(
_
.
size
(
events
))
return
events
;
};
// Bind an event to only be triggered a single time. After the first time
// the callback is invoked, it will be removed. When multiple events are
// passed in using the space-separated syntax, the event will fire once for every
// event you passed in, not once for a combination of all events
Events
.
once
=
function
(
name
,
callback
,
context
)
{
// Map the event into a `{event: once}` object.
var
events
=
eventsApi
(
onceMap
,
{},
name
,
callback
,
_
.
bind
(
this
.
off
,
this
));
return
this
.
on
(
events
,
void
0
,
context
);
};
// Inversion-of-control versions of `once`.
Events
.
listenToOnce
=
function
(
obj
,
name
,
callback
)
{
// Map the event into a `{event: once}` object.
var
events
=
eventsApi
(
onceMap
,
{},
name
,
callback
,
_
.
bind
(
this
.
stopListening
,
this
,
obj
));
return
this
.
listenTo
(
obj
,
events
);
};
// Reduces the event callbacks into a map of `{event: onceWrapper}`.
// `offer` unbinds the `onceWrapper` after it has been called.
var
onceMap
=
function
(
map
,
name
,
callback
,
offer
)
{
if
(
callback
)
{
var
once
=
map
[
name
]
=
_
.
once
(
function
()
{
offer
(
name
,
once
);
callback
.
apply
(
this
,
arguments
);
});
once
.
_callback
=
callback
;
}
return
map
;
};
// Trigger one or many events, firing all bound callbacks. Callbacks are
// passed the same arguments as `trigger` is, apart from the event name
// (unless you're listening on `"all"`, which will cause your callback to
// receive the true name of the event as the first argument).
Events
.
trigger
=
function
(
name
)
{
if
(
!
this
.
_events
)
return
this
;
var
length
=
Math
.
max
(
0
,
arguments
.
length
-
1
);
var
args
=
Array
(
length
);
for
(
var
i
=
0
;
i
<
length
;
i
++
)
args
[
i
]
=
arguments
[
i
+
1
];
eventsApi
(
triggerApi
,
this
.
_events
,
name
,
void
0
,
args
);
return
this
;
};
return
true
;
// Handles triggering the appropriate event callbacks.
var
triggerApi
=
function
(
objEvents
,
name
,
cb
,
args
)
{
if
(
objEvents
)
{
var
events
=
objEvents
[
name
];
var
allEvents
=
objEvents
.
all
;
if
(
events
&&
allEvents
)
allEvents
=
allEvents
.
slice
();
if
(
events
)
triggerEvents
(
events
,
args
);
if
(
allEvents
)
triggerEvents
(
allEvents
,
[
name
].
concat
(
args
));
}
return
objEvents
;
};
// A difficult-to-believe, but optimized internal dispatch function for
...
...
@@ -211,22 +356,6 @@
}
};
var
listenMethods
=
{
listenTo
:
'
on
'
,
listenToOnce
:
'
once
'
};
// Inversion-of-control versions of `on` and `once`. Tell *this* object to
// listen to an event in another object ... keeping track of what it's
// listening to.
_
.
each
(
listenMethods
,
function
(
implementation
,
method
)
{
Events
[
method
]
=
function
(
obj
,
name
,
callback
)
{
var
listeningTo
=
this
.
_listeningTo
||
(
this
.
_listeningTo
=
{});
var
id
=
obj
.
_listenId
||
(
obj
.
_listenId
=
_
.
uniqueId
(
'
l
'
));
listeningTo
[
id
]
=
obj
;
if
(
!
callback
&&
typeof
name
===
'
object
'
)
callback
=
this
;
obj
[
implementation
](
name
,
callback
,
this
);
return
this
;
};
});
// Aliases for backwards compatibility.
Events
.
bind
=
Events
.
on
;
Events
.
unbind
=
Events
.
off
;
...
...
@@ -248,7 +377,7 @@
var
Model
=
Backbone
.
Model
=
function
(
attributes
,
options
)
{
var
attrs
=
attributes
||
{};
options
||
(
options
=
{});
this
.
cid
=
_
.
uniqueId
(
'
c
'
);
this
.
cid
=
_
.
uniqueId
(
this
.
cidPrefix
);
this
.
attributes
=
{};
if
(
options
.
collection
)
this
.
collection
=
options
.
collection
;
if
(
options
.
parse
)
attrs
=
this
.
parse
(
attrs
,
options
)
||
{};
...
...
@@ -271,6 +400,10 @@
// CouchDB users may want to set this to `"_id"`.
idAttribute
:
'
id
'
,
// The prefix is used to create the client id which is used to identify models locally.
// You may want to override this if you're experiencing name clashes with model ids.
cidPrefix
:
'
c
'
,
// Initialize is an empty function by default. Override it with your own
// initialization logic.
initialize
:
function
(){},
...
...
@@ -302,14 +435,19 @@
return
this
.
get
(
attr
)
!=
null
;
},
// Special-cased proxy to underscore's `_.matches` method.
matches
:
function
(
attrs
)
{
return
!!
_
.
iteratee
(
attrs
,
this
)(
this
.
attributes
);
},
// Set a hash of model attributes on the object, firing `"change"`. This is
// the core primitive operation of a model, updating the data and notifying
// anyone who needs to know about the change in state. The heart of the beast.
set
:
function
(
key
,
val
,
options
)
{
var
attr
,
attrs
,
unset
,
changes
,
silent
,
changing
,
prev
,
current
;
if
(
key
==
null
)
return
this
;
// Handle both `"key", value` and `{key: value}` -style arguments.
var
attrs
;
if
(
typeof
key
===
'
object
'
)
{
attrs
=
key
;
options
=
val
;
...
...
@@ -323,29 +461,32 @@
if
(
!
this
.
_validate
(
attrs
,
options
))
return
false
;
// Extract attributes and options.
unset
=
options
.
unset
;
silent
=
options
.
silent
;
changes
=
[];
changing
=
this
.
_changing
;
this
.
_changing
=
true
;
var
unset
=
options
.
unset
;
var
silent
=
options
.
silent
;
var
changes
=
[];
var
changing
=
this
.
_changing
;
this
.
_changing
=
true
;
if
(
!
changing
)
{
this
.
_previousAttributes
=
_
.
clone
(
this
.
attributes
);
this
.
changed
=
{};
}
current
=
this
.
attributes
,
prev
=
this
.
_previousAttributes
;
var
current
=
this
.
attributes
;
var
changed
=
this
.
changed
;
var
prev
=
this
.
_previousAttributes
;
// Check for changes of `id`.
if
(
this
.
idAttribute
in
attrs
)
this
.
id
=
attrs
[
this
.
idAttribute
];
// For each `set` attribute, update or delete the current value.
for
(
attr
in
attrs
)
{
for
(
var
attr
in
attrs
)
{
val
=
attrs
[
attr
];
if
(
!
_
.
isEqual
(
current
[
attr
],
val
))
changes
.
push
(
attr
);
if
(
!
_
.
isEqual
(
prev
[
attr
],
val
))
{
this
.
changed
[
attr
]
=
val
;
changed
[
attr
]
=
val
;
}
else
{
delete
this
.
changed
[
attr
];
delete
changed
[
attr
];
}
unset
?
delete
current
[
attr
]
:
current
[
attr
]
=
val
;
}
...
...
@@ -353,7 +494,7 @@
// Trigger all relevant attribute changes.
if
(
!
silent
)
{
if
(
changes
.
length
)
this
.
_pending
=
options
;
for
(
var
i
=
0
,
l
=
changes
.
length
;
i
<
l
;
i
++
)
{
for
(
var
i
=
0
;
i
<
changes
.
length
;
i
++
)
{
this
.
trigger
(
'
change:
'
+
changes
[
i
],
this
,
current
[
changes
[
i
]],
options
);
}
}
...
...
@@ -401,13 +542,14 @@
// determining if there *would be* a change.
changedAttributes
:
function
(
diff
)
{
if
(
!
diff
)
return
this
.
hasChanged
()
?
_
.
clone
(
this
.
changed
)
:
false
;
var
val
,
changed
=
false
;
var
old
=
this
.
_changing
?
this
.
_previousAttributes
:
this
.
attributes
;
var
changed
=
{};
for
(
var
attr
in
diff
)
{
if
(
_
.
isEqual
(
old
[
attr
],
(
val
=
diff
[
attr
])))
continue
;
(
changed
||
(
changed
=
{}))[
attr
]
=
val
;
var
val
=
diff
[
attr
];
if
(
_
.
isEqual
(
old
[
attr
],
val
))
continue
;
changed
[
attr
]
=
val
;
}
return
changed
;
return
_
.
size
(
changed
)
?
changed
:
false
;
},
// Get the previous value of an attribute, recorded at the time the last
...
...
@@ -423,17 +565,16 @@
return
_
.
clone
(
this
.
_previousAttributes
);
},
// Fetch the model from the server. If the server's representation of the
// model differs from its current attributes, they will be overridden,
// triggering a `"change"` event.
// Fetch the model from the server, merging the response with the model's
// local attributes. Any changed attributes will trigger a "change" event.
fetch
:
function
(
options
)
{
options
=
options
?
_
.
clone
(
options
)
:
{};
if
(
options
.
parse
===
void
0
)
options
.
parse
=
true
;
options
=
_
.
extend
({
parse
:
true
},
options
);
var
model
=
this
;
var
success
=
options
.
success
;
options
.
success
=
function
(
resp
)
{
if
(
!
model
.
set
(
model
.
parse
(
resp
,
options
),
options
))
return
false
;
if
(
success
)
success
(
model
,
resp
,
options
);
var
serverAttrs
=
options
.
parse
?
model
.
parse
(
resp
,
options
)
:
resp
;
if
(
!
model
.
set
(
serverAttrs
,
options
))
return
false
;
if
(
success
)
success
.
call
(
options
.
context
,
model
,
resp
,
options
);
model
.
trigger
(
'
sync
'
,
model
,
resp
,
options
);
};
wrapError
(
this
,
options
);
...
...
@@ -444,9 +585,8 @@
// If the server returns an attributes hash that differs, the model's
// state will be `set` again.
save
:
function
(
key
,
val
,
options
)
{
var
attrs
,
method
,
xhr
,
attributes
=
this
.
attributes
;
// Handle both `"key", value` and `{key: value}` -style arguments.
var
attrs
;
if
(
key
==
null
||
typeof
key
===
'
object
'
)
{
attrs
=
key
;
options
=
val
;
...
...
@@ -454,46 +594,43 @@
(
attrs
=
{})[
key
]
=
val
;
}
options
=
_
.
extend
({
validate
:
true
},
options
);
options
=
_
.
extend
({
validate
:
true
,
parse
:
true
},
options
);
var
wait
=
options
.
wait
;
// If we're not waiting and attributes exist, save acts as
// `set(attr).save(null, opts)` with validation. Otherwise, check if
// the model will be valid when the attributes, if any, are set.
if
(
attrs
&&
!
options
.
wait
)
{
if
(
attrs
&&
!
wait
)
{
if
(
!
this
.
set
(
attrs
,
options
))
return
false
;
}
else
{
if
(
!
this
.
_validate
(
attrs
,
options
))
return
false
;
}
// Set temporary attributes if `{wait: true}`.
if
(
attrs
&&
options
.
wait
)
{
this
.
attributes
=
_
.
extend
({},
attributes
,
attrs
);
}
// After a successful server-side save, the client is (optionally)
// updated with the server-side state.
if
(
options
.
parse
===
void
0
)
options
.
parse
=
true
;
var
model
=
this
;
var
success
=
options
.
success
;
var
attributes
=
this
.
attributes
;
options
.
success
=
function
(
resp
)
{
// Ensure attributes are restored during synchronous saves.
model
.
attributes
=
attributes
;
var
serverAttrs
=
model
.
parse
(
resp
,
options
);
if
(
options
.
wait
)
serverAttrs
=
_
.
extend
(
attrs
||
{},
serverAttrs
);
if
(
_
.
isObject
(
serverAttrs
)
&&
!
model
.
set
(
serverAttrs
,
options
))
{
return
false
;
}
if
(
success
)
success
(
model
,
resp
,
options
);
var
serverAttrs
=
options
.
parse
?
model
.
parse
(
resp
,
options
)
:
resp
;
if
(
wait
)
serverAttrs
=
_
.
extend
({},
attrs
,
serverAttrs
);
if
(
serverAttrs
&&
!
model
.
set
(
serverAttrs
,
options
))
return
false
;
if
(
success
)
success
.
call
(
options
.
context
,
model
,
resp
,
options
);
model
.
trigger
(
'
sync
'
,
model
,
resp
,
options
);
};
wrapError
(
this
,
options
);
method
=
this
.
isNew
()
?
'
create
'
:
(
options
.
patch
?
'
patch
'
:
'
update
'
);
if
(
method
===
'
patch
'
)
options
.
attrs
=
attrs
;
xhr
=
this
.
sync
(
method
,
this
,
options
);
// Set temporary attributes if `{wait: true}` to properly find new ids.
if
(
attrs
&&
wait
)
this
.
attributes
=
_
.
extend
({},
attributes
,
attrs
);
var
method
=
this
.
isNew
()
?
'
create
'
:
(
options
.
patch
?
'
patch
'
:
'
update
'
);
if
(
method
===
'
patch
'
&&
!
options
.
attrs
)
options
.
attrs
=
attrs
;
var
xhr
=
this
.
sync
(
method
,
this
,
options
);
// Restore attributes.
if
(
attrs
&&
options
.
wait
)
this
.
attributes
=
attributes
;
this
.
attributes
=
attributes
;
return
xhr
;
},
...
...
@@ -505,25 +642,27 @@
options
=
options
?
_
.
clone
(
options
)
:
{};
var
model
=
this
;
var
success
=
options
.
success
;
var
wait
=
options
.
wait
;
var
destroy
=
function
()
{
model
.
stopListening
();
model
.
trigger
(
'
destroy
'
,
model
,
model
.
collection
,
options
);
};
options
.
success
=
function
(
resp
)
{
if
(
options
.
wait
||
model
.
isNew
()
)
destroy
();
if
(
success
)
success
(
model
,
resp
,
options
);
if
(
wait
)
destroy
();
if
(
success
)
success
.
call
(
options
.
context
,
model
,
resp
,
options
);
if
(
!
model
.
isNew
())
model
.
trigger
(
'
sync
'
,
model
,
resp
,
options
);
};
var
xhr
=
false
;
if
(
this
.
isNew
())
{
options
.
success
();
return
false
;
_
.
defer
(
options
.
success
);
}
else
{
wrapError
(
this
,
options
);
xhr
=
this
.
sync
(
'
delete
'
,
this
,
options
);
}
wrapError
(
this
,
options
);
var
xhr
=
this
.
sync
(
'
delete
'
,
this
,
options
);
if
(
!
options
.
wait
)
destroy
();
if
(
!
wait
)
destroy
();
return
xhr
;
},
...
...
@@ -536,7 +675,8 @@
_
.
result
(
this
.
collection
,
'
url
'
)
||
urlError
();
if
(
this
.
isNew
())
return
base
;
return
base
.
replace
(
/
([^\/])
$/
,
'
$1/
'
)
+
encodeURIComponent
(
this
.
id
);
var
id
=
this
.
get
(
this
.
idAttribute
);
return
base
.
replace
(
/
[^\/]
$/
,
'
$&/
'
)
+
encodeURIComponent
(
id
);
},
// **parse** converts a response into the hash of attributes to be `set` on
...
...
@@ -557,7 +697,7 @@
// Check if the model is currently in a valid state.
isValid
:
function
(
options
)
{
return
this
.
_validate
({},
_
.
extend
(
options
||
{},
{
validate
:
true
}
));
return
this
.
_validate
({},
_
.
defaults
({
validate
:
true
},
options
));
},
// Run validation against the next complete set of model attributes,
...
...
@@ -574,22 +714,17 @@
});
// Underscore methods that we want to implement on the Model.
var
modelMethods
=
[
'
keys
'
,
'
values
'
,
'
pairs
'
,
'
invert
'
,
'
pick
'
,
'
omit
'
];
var
modelMethods
=
{
keys
:
1
,
values
:
1
,
pairs
:
1
,
invert
:
1
,
pick
:
0
,
omit
:
0
,
chain
:
1
,
isEmpty
:
1
};
// Mix in each Underscore method as a proxy to `Model#attributes`.
_
.
each
(
modelMethods
,
function
(
method
)
{
Model
.
prototype
[
method
]
=
function
()
{
var
args
=
slice
.
call
(
arguments
);
args
.
unshift
(
this
.
attributes
);
return
_
[
method
].
apply
(
_
,
args
);
};
});
addUnderscoreMethods
(
Model
,
modelMethods
,
'
attributes
'
);
// Backbone.Collection
// -------------------
// If models tend to represent a single row of data, a Backbone Collection is
// more anal
a
gous to a table full of data ... or a small slice or page of that
// more anal
o
gous to a table full of data ... or a small slice or page of that
// table, or a collection of rows that belong together for a particular reason
// -- all of the messages in this particular folder, all of the documents
// belonging to this particular author, and so on. Collections maintain
...
...
@@ -625,7 +760,7 @@
// The JSON representation of a Collection is an array of the
// models' attributes.
toJSON
:
function
(
options
)
{
return
this
.
map
(
function
(
model
){
return
model
.
toJSON
(
options
);
});
return
this
.
map
(
function
(
model
)
{
return
model
.
toJSON
(
options
);
});
},
// Proxy `Backbone.sync` by default.
...
...
@@ -640,25 +775,12 @@
// Remove a model, or a list of models from the set.
remove
:
function
(
models
,
options
)
{
options
=
_
.
extend
({},
options
);
var
singular
=
!
_
.
isArray
(
models
);
models
=
singular
?
[
models
]
:
_
.
clone
(
models
);
options
||
(
options
=
{});
var
i
,
l
,
index
,
model
;
for
(
i
=
0
,
l
=
models
.
length
;
i
<
l
;
i
++
)
{
model
=
models
[
i
]
=
this
.
get
(
models
[
i
]);
if
(
!
model
)
continue
;
delete
this
.
_byId
[
model
.
id
];
delete
this
.
_byId
[
model
.
cid
];
index
=
this
.
indexOf
(
model
);
this
.
models
.
splice
(
index
,
1
);
this
.
length
--
;
if
(
!
options
.
silent
)
{
options
.
index
=
index
;
model
.
trigger
(
'
remove
'
,
model
,
this
,
options
);
}
this
.
_removeReference
(
model
,
options
);
}
return
singular
?
models
[
0
]
:
models
;
var
removed
=
this
.
_removeModels
(
models
,
options
);
if
(
!
options
.
silent
&&
removed
)
this
.
trigger
(
'
update
'
,
this
,
options
);
return
singular
?
removed
[
0
]
:
removed
;
},
// Update a collection by `set`-ing a new list of models, adding new ones,
...
...
@@ -667,34 +789,31 @@
// the core operation for updating the data contained by the collection.
set
:
function
(
models
,
options
)
{
options
=
_
.
defaults
({},
options
,
setOptions
);
if
(
options
.
parse
)
models
=
this
.
parse
(
models
,
options
);
if
(
options
.
parse
&&
!
this
.
_isModel
(
models
)
)
models
=
this
.
parse
(
models
,
options
);
var
singular
=
!
_
.
isArray
(
models
);
models
=
singular
?
(
models
?
[
models
]
:
[])
:
_
.
clone
(
models
);
var
i
,
l
,
i
d
,
model
,
attrs
,
existing
,
sort
;
models
=
singular
?
(
models
?
[
models
]
:
[])
:
models
.
slice
(
);
var
id
,
model
,
attrs
,
existing
,
sort
;
var
at
=
options
.
at
;
var
targetModel
=
this
.
model
;
if
(
at
!=
null
)
at
=
+
at
;
if
(
at
<
0
)
at
+=
this
.
length
+
1
;
var
sortable
=
this
.
comparator
&&
(
at
==
null
)
&&
options
.
sort
!==
false
;
var
sortAttr
=
_
.
isString
(
this
.
comparator
)
?
this
.
comparator
:
null
;
var
toAdd
=
[],
toRemove
=
[],
modelMap
=
{};
var
add
=
options
.
add
,
merge
=
options
.
merge
,
remove
=
options
.
remove
;
var
order
=
!
sortable
&&
add
&&
remove
?
[]
:
false
;
var
orderChanged
=
false
;
// Turn bare objects into model references, and prevent invalid models
// from being added.
for
(
i
=
0
,
l
=
models
.
length
;
i
<
l
;
i
++
)
{
attrs
=
models
[
i
]
||
{};
if
(
attrs
instanceof
Model
)
{
id
=
model
=
attrs
;
}
else
{
id
=
attrs
[
targetModel
.
prototype
.
idAttribute
||
'
id
'
];
}
for
(
var
i
=
0
;
i
<
models
.
length
;
i
++
)
{
attrs
=
models
[
i
];
// If a duplicate is found, prevent it from being added and
// optionally merge it into the existing model.
if
(
existing
=
this
.
get
(
id
))
{
if
(
existing
=
this
.
get
(
attrs
))
{
if
(
remove
)
modelMap
[
existing
.
cid
]
=
true
;
if
(
merge
)
{
attrs
=
attrs
===
model
?
model
.
attributes
:
attrs
;
if
(
merge
&&
attrs
!==
existing
)
{
attrs
=
this
.
_isModel
(
attrs
)
?
attrs
.
attributes
:
attrs
;
if
(
options
.
parse
)
attrs
=
existing
.
parse
(
attrs
,
options
);
existing
.
set
(
attrs
,
options
);
if
(
sortable
&&
!
sort
&&
existing
.
hasChanged
(
sortAttr
))
sort
=
true
;
...
...
@@ -711,30 +830,38 @@
// Do not add multiple models with the same `id`.
model
=
existing
||
model
;
if
(
order
&&
(
model
.
isNew
()
||
!
modelMap
[
model
.
id
]))
order
.
push
(
model
);
modelMap
[
model
.
id
]
=
true
;
if
(
!
model
)
continue
;
id
=
this
.
modelId
(
model
.
attributes
);
if
(
order
&&
(
model
.
isNew
()
||
!
modelMap
[
id
]))
{
order
.
push
(
model
);
// Check to see if this is actually a new model at this index.
orderChanged
=
orderChanged
||
!
this
.
models
[
i
]
||
model
.
cid
!==
this
.
models
[
i
].
cid
;
}
modelMap
[
id
]
=
true
;
}
// Remove nonexistent models if appropriate.
if
(
remove
)
{
for
(
i
=
0
,
l
=
this
.
length
;
i
<
l
;
++
i
)
{
for
(
var
i
=
0
;
i
<
this
.
length
;
i
++
)
{
if
(
!
modelMap
[(
model
=
this
.
models
[
i
]).
cid
])
toRemove
.
push
(
model
);
}
if
(
toRemove
.
length
)
this
.
remove
(
toRemove
,
options
);
if
(
toRemove
.
length
)
this
.
_removeModels
(
toRemove
,
options
);
}
// See if sorting is needed, update `length` and splice in new models.
if
(
toAdd
.
length
||
(
order
&&
order
.
length
)
)
{
if
(
toAdd
.
length
||
orderChanged
)
{
if
(
sortable
)
sort
=
true
;
this
.
length
+=
toAdd
.
length
;
if
(
at
!=
null
)
{
for
(
i
=
0
,
l
=
toAdd
.
length
;
i
<
l
;
i
++
)
{
for
(
var
i
=
0
;
i
<
toAdd
.
length
;
i
++
)
{
this
.
models
.
splice
(
at
+
i
,
0
,
toAdd
[
i
]);
}
}
else
{
if
(
order
)
this
.
models
.
length
=
0
;
var
orderedModels
=
order
||
toAdd
;
for
(
i
=
0
,
l
=
orderedModels
.
length
;
i
<
l
;
i
++
)
{
for
(
var
i
=
0
;
i
<
orderedModels
.
length
;
i
++
)
{
this
.
models
.
push
(
orderedModels
[
i
]);
}
}
...
...
@@ -745,10 +872,13 @@
// Unless silenced, it's time to fire all appropriate add/sort events.
if
(
!
options
.
silent
)
{
for
(
i
=
0
,
l
=
toAdd
.
length
;
i
<
l
;
i
++
)
{
(
model
=
toAdd
[
i
]).
trigger
(
'
add
'
,
model
,
this
,
options
);
var
addOpts
=
at
!=
null
?
_
.
clone
(
options
)
:
options
;
for
(
var
i
=
0
;
i
<
toAdd
.
length
;
i
++
)
{
if
(
at
!=
null
)
addOpts
.
index
=
at
+
i
;
(
model
=
toAdd
[
i
]).
trigger
(
'
add
'
,
model
,
this
,
addOpts
);
}
if
(
sort
||
(
order
&&
order
.
length
))
this
.
trigger
(
'
sort
'
,
this
,
options
);
if
(
sort
||
orderChanged
)
this
.
trigger
(
'
sort
'
,
this
,
options
);
if
(
toAdd
.
length
||
toRemove
.
length
)
this
.
trigger
(
'
update
'
,
this
,
options
);
}
// Return the added (or merged) model (or models).
...
...
@@ -760,8 +890,8 @@
// any granular `add` or `remove` events. Fires `reset` when finished.
// Useful for bulk operations and optimizations.
reset
:
function
(
models
,
options
)
{
options
||
(
options
=
{})
;
for
(
var
i
=
0
,
l
=
this
.
models
.
length
;
i
<
l
;
i
++
)
{
options
=
options
?
_
.
clone
(
options
)
:
{}
;
for
(
var
i
=
0
;
i
<
this
.
models
.
length
;
i
++
)
{
this
.
_removeReference
(
this
.
models
[
i
],
options
);
}
options
.
previousModels
=
this
.
models
;
...
...
@@ -779,8 +909,7 @@
// Remove a model from the end of the collection.
pop
:
function
(
options
)
{
var
model
=
this
.
at
(
this
.
length
-
1
);
this
.
remove
(
model
,
options
);
return
model
;
return
this
.
remove
(
model
,
options
);
},
// Add a model to the beginning of the collection.
...
...
@@ -791,8 +920,7 @@
// Remove a model from the beginning of the collection.
shift
:
function
(
options
)
{
var
model
=
this
.
at
(
0
);
this
.
remove
(
model
,
options
);
return
model
;
return
this
.
remove
(
model
,
options
);
},
// Slice out a sub-array of models from the collection.
...
...
@@ -803,23 +931,22 @@
// Get a model from the set by id.
get
:
function
(
obj
)
{
if
(
obj
==
null
)
return
void
0
;
return
this
.
_byId
[
obj
]
||
this
.
_byId
[
obj
.
id
]
||
this
.
_byId
[
obj
.
cid
];
var
id
=
this
.
modelId
(
this
.
_isModel
(
obj
)
?
obj
.
attributes
:
obj
);
return
this
.
_byId
[
obj
]
||
this
.
_byId
[
id
]
||
this
.
_byId
[
obj
.
cid
];
},
// Get the model at the given index.
at
:
function
(
index
)
{
if
(
index
<
0
)
index
+=
this
.
length
;
return
this
.
models
[
index
];
},
// Return models with matching attributes. Useful for simple cases of
// `filter`.
where
:
function
(
attrs
,
first
)
{
if
(
_
.
isEmpty
(
attrs
))
return
first
?
void
0
:
[]
;
var
matches
=
_
.
matches
(
attrs
)
;
return
this
[
first
?
'
find
'
:
'
filter
'
](
function
(
model
)
{
for
(
var
key
in
attrs
)
{
if
(
attrs
[
key
]
!==
model
.
get
(
key
))
return
false
;
}
return
true
;
return
matches
(
model
.
attributes
);
});
},
...
...
@@ -856,14 +983,13 @@
// collection when they arrive. If `reset: true` is passed, the response
// data will be passed through the `reset` method instead of `set`.
fetch
:
function
(
options
)
{
options
=
options
?
_
.
clone
(
options
)
:
{};
if
(
options
.
parse
===
void
0
)
options
.
parse
=
true
;
options
=
_
.
extend
({
parse
:
true
},
options
);
var
success
=
options
.
success
;
var
collection
=
this
;
options
.
success
=
function
(
resp
)
{
var
method
=
options
.
reset
?
'
reset
'
:
'
set
'
;
collection
[
method
](
resp
,
options
);
if
(
success
)
success
(
collection
,
resp
,
options
);
if
(
success
)
success
.
call
(
options
.
context
,
collection
,
resp
,
options
);
collection
.
trigger
(
'
sync
'
,
collection
,
resp
,
options
);
};
wrapError
(
this
,
options
);
...
...
@@ -875,13 +1001,15 @@
// wait for the server to agree.
create
:
function
(
model
,
options
)
{
options
=
options
?
_
.
clone
(
options
)
:
{};
if
(
!
(
model
=
this
.
_prepareModel
(
model
,
options
)))
return
false
;
if
(
!
options
.
wait
)
this
.
add
(
model
,
options
);
var
wait
=
options
.
wait
;
model
=
this
.
_prepareModel
(
model
,
options
);
if
(
!
model
)
return
false
;
if
(
!
wait
)
this
.
add
(
model
,
options
);
var
collection
=
this
;
var
success
=
options
.
success
;
options
.
success
=
function
(
model
,
resp
)
{
if
(
options
.
wait
)
collection
.
add
(
model
,
option
s
);
if
(
success
)
success
(
model
,
resp
,
option
s
);
options
.
success
=
function
(
model
,
resp
,
callbackOpts
)
{
if
(
wait
)
collection
.
add
(
model
,
callbackOpt
s
);
if
(
success
)
success
.
call
(
callbackOpts
.
context
,
model
,
resp
,
callbackOpt
s
);
};
model
.
save
(
null
,
options
);
return
model
;
...
...
@@ -895,7 +1023,15 @@
// Create a new collection with an identical list of models as this one.
clone
:
function
()
{
return
new
this
.
constructor
(
this
.
models
);
return
new
this
.
constructor
(
this
.
models
,
{
model
:
this
.
model
,
comparator
:
this
.
comparator
});
},
// Define how to uniquely identify models in the collection.
modelId
:
function
(
attrs
)
{
return
attrs
[
this
.
model
.
prototype
.
idAttribute
||
'
id
'
];
},
// Private method to reset all internal state. Called when the collection
...
...
@@ -909,7 +1045,10 @@
// Prepare a hash of attributes (or other model) to be added to this
// collection.
_prepareModel
:
function
(
attrs
,
options
)
{
if
(
attrs
instanceof
Model
)
return
attrs
;
if
(
this
.
_isModel
(
attrs
))
{
if
(
!
attrs
.
collection
)
attrs
.
collection
=
this
;
return
attrs
;
}
options
=
options
?
_
.
clone
(
options
)
:
{};
options
.
collection
=
this
;
var
model
=
new
this
.
model
(
attrs
,
options
);
...
...
@@ -918,16 +1057,48 @@
return
false
;
},
// Internal method called by both remove and set.
// Returns removed models, or false if nothing is removed.
_removeModels
:
function
(
models
,
options
)
{
var
removed
=
[];
for
(
var
i
=
0
;
i
<
models
.
length
;
i
++
)
{
var
model
=
this
.
get
(
models
[
i
]);
if
(
!
model
)
continue
;
var
index
=
this
.
indexOf
(
model
);
this
.
models
.
splice
(
index
,
1
);
this
.
length
--
;
if
(
!
options
.
silent
)
{
options
.
index
=
index
;
model
.
trigger
(
'
remove
'
,
model
,
this
,
options
);
}
removed
.
push
(
model
);
this
.
_removeReference
(
model
,
options
);
}
return
removed
.
length
?
removed
:
false
;
},
// Method for checking whether an object should be considered a model for
// the purposes of adding to the collection.
_isModel
:
function
(
model
)
{
return
model
instanceof
Model
;
},
// Internal method to create a model's ties to a collection.
_addReference
:
function
(
model
,
options
)
{
this
.
_byId
[
model
.
cid
]
=
model
;
if
(
model
.
id
!=
null
)
this
.
_byId
[
model
.
id
]
=
model
;
if
(
!
model
.
collection
)
model
.
collection
=
this
;
var
id
=
this
.
modelId
(
model
.
attributes
)
;
if
(
id
!=
null
)
this
.
_byId
[
id
]
=
model
;
model
.
on
(
'
all
'
,
this
.
_onModelEvent
,
this
);
},
// Internal method to sever a model's ties to a collection.
_removeReference
:
function
(
model
,
options
)
{
delete
this
.
_byId
[
model
.
cid
];
var
id
=
this
.
modelId
(
model
.
attributes
);
if
(
id
!=
null
)
delete
this
.
_byId
[
id
];
if
(
this
===
model
.
collection
)
delete
model
.
collection
;
model
.
off
(
'
all
'
,
this
.
_onModelEvent
,
this
);
},
...
...
@@ -939,9 +1110,13 @@
_onModelEvent
:
function
(
event
,
model
,
collection
,
options
)
{
if
((
event
===
'
add
'
||
event
===
'
remove
'
)
&&
collection
!==
this
)
return
;
if
(
event
===
'
destroy
'
)
this
.
remove
(
model
,
options
);
if
(
model
&&
event
===
'
change:
'
+
model
.
idAttribute
)
{
delete
this
.
_byId
[
model
.
previous
(
model
.
idAttribute
)];
if
(
model
.
id
!=
null
)
this
.
_byId
[
model
.
id
]
=
model
;
if
(
event
===
'
change
'
)
{
var
prevId
=
this
.
modelId
(
model
.
previousAttributes
());
var
id
=
this
.
modelId
(
model
.
attributes
);
if
(
prevId
!==
id
)
{
if
(
prevId
!=
null
)
delete
this
.
_byId
[
prevId
];
if
(
id
!=
null
)
this
.
_byId
[
id
]
=
model
;
}
}
this
.
trigger
.
apply
(
this
,
arguments
);
}
...
...
@@ -951,27 +1126,23 @@
// Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented
// right here:
var
methods
=
[
'
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
'
,
'
sample
'
];
var
collectionMethods
=
{
forEach
:
3
,
each
:
3
,
map
:
3
,
collect
:
3
,
reduce
:
4
,
foldl
:
4
,
inject
:
4
,
reduceRight
:
4
,
foldr
:
4
,
find
:
3
,
detect
:
3
,
filter
:
3
,
select
:
3
,
reject
:
3
,
every
:
3
,
all
:
3
,
some
:
3
,
any
:
3
,
include
:
2
,
contains
:
2
,
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
};
// Mix in each Underscore method as a proxy to `Collection#models`.
_
.
each
(
methods
,
function
(
method
)
{
Collection
.
prototype
[
method
]
=
function
()
{
var
args
=
slice
.
call
(
arguments
);
args
.
unshift
(
this
.
models
);
return
_
[
method
].
apply
(
_
,
args
);
};
});
addUnderscoreMethods
(
Collection
,
collectionMethods
,
'
models
'
);
// Underscore methods that take a property name as an argument.
var
attributeMethods
=
[
'
groupBy
'
,
'
countBy
'
,
'
sortBy
'
,
'
indexBy
'
];
// Use attributes instead of properties.
_
.
each
(
attributeMethods
,
function
(
method
)
{
if
(
!
_
[
method
])
return
;
Collection
.
prototype
[
method
]
=
function
(
value
,
context
)
{
var
iterator
=
_
.
isFunction
(
value
)
?
value
:
function
(
model
)
{
return
model
.
get
(
value
);
...
...
@@ -995,11 +1166,9 @@
// if an existing element is not provided...
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
();
};
// Cached regex to split keys for `delegate`.
...
...
@@ -1034,21 +1203,37 @@
// Remove this view by taking the element out of the DOM, and removing any
// applicable Backbone.Events listeners.
remove
:
function
()
{
this
.
$el
.
remove
();
this
.
_removeElement
();
this
.
stopListening
();
return
this
;
},
// Change the view's element (`this.el` property), including event
// re-delegation.
setElement
:
function
(
element
,
delegate
)
{
if
(
this
.
$el
)
this
.
undelegateEvents
();
this
.
$el
=
element
instanceof
Backbone
.
$
?
element
:
Backbone
.
$
(
element
);
this
.
el
=
this
.
$el
[
0
];
if
(
delegate
!==
false
)
this
.
delegateEvents
();
// Remove this view's element from the document and all event listeners
// attached to it. Exposed for subclasses using an alternative DOM
// manipulation API.
_removeElement
:
function
()
{
this
.
$el
.
remove
();
},
// Change the view's element (`this.el` property) and re-delegate the
// view's events on the new element.
setElement
:
function
(
element
)
{
this
.
undelegateEvents
();
this
.
_setElement
(
element
);
this
.
delegateEvents
();
return
this
;
},
// Creates the `this.el` and `this.$el` references for this view using the
// given `el`. `el` can be a CSS selector or an HTML string, a jQuery
// context or an element. Subclasses can override this to utilize an
// alternative DOM manipulation API and are only required to set the
// `this.el` property.
_setElement
:
function
(
el
)
{
this
.
$el
=
el
instanceof
Backbone
.
$
?
el
:
Backbone
.
$
(
el
);
this
.
el
=
this
.
$el
[
0
];
},
// Set callbacks, where `this.events` is a hash of
//
// *{"event selector": "callback"}*
...
...
@@ -1062,37 +1247,49 @@
// pairs. Callbacks will be bound to the view, with `this` set properly.
// Uses event delegation for efficiency.
// Omitting the selector binds the event to `this.el`.
// This only works for delegate-able events: not `focus`, `blur`, and
// not `change`, `submit`, and `reset` in Internet Explorer.
delegateEvents
:
function
(
events
)
{
if
(
!
(
events
||
(
events
=
_
.
result
(
this
,
'
events
'
))))
return
this
;
events
||
(
events
=
_
.
result
(
this
,
'
events
'
));
if
(
!
events
)
return
this
;
this
.
undelegateEvents
();
for
(
var
key
in
events
)
{
var
method
=
events
[
key
];
if
(
!
_
.
isFunction
(
method
))
method
=
this
[
events
[
key
]
];
if
(
!
_
.
isFunction
(
method
))
method
=
this
[
method
];
if
(
!
method
)
continue
;
var
match
=
key
.
match
(
delegateEventSplitter
);
var
eventName
=
match
[
1
],
selector
=
match
[
2
];
method
=
_
.
bind
(
method
,
this
);
eventName
+=
'
.delegateEvents
'
+
this
.
cid
;
if
(
selector
===
''
)
{
this
.
$el
.
on
(
eventName
,
method
);
}
else
{
this
.
$el
.
on
(
eventName
,
selector
,
method
);
}
this
.
delegate
(
match
[
1
],
match
[
2
],
_
.
bind
(
method
,
this
));
}
return
this
;
},
// Clears all callbacks previously bound to the view with `delegateEvents`.
// Add a single event listener to the view's element (or a child element
// using `selector`). This only works for delegate-able events: not `focus`,
// `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
delegate
:
function
(
eventName
,
selector
,
listener
)
{
this
.
$el
.
on
(
eventName
+
'
.delegateEvents
'
+
this
.
cid
,
selector
,
listener
);
return
this
;
},
// Clears all callbacks previously bound to the view by `delegateEvents`.
// You usually don't need to use this, but may wish to if you have multiple
// Backbone views attached to the same DOM element.
undelegateEvents
:
function
()
{
this
.
$el
.
off
(
'
.delegateEvents
'
+
this
.
cid
);
if
(
this
.
$el
)
this
.
$el
.
off
(
'
.delegateEvents
'
+
this
.
cid
);
return
this
;
},
// A finer-grained `undelegateEvents` for removing a single delegated event.
// `selector` and `listener` are both optional.
undelegate
:
function
(
eventName
,
selector
,
listener
)
{
this
.
$el
.
off
(
eventName
+
'
.delegateEvents
'
+
this
.
cid
,
selector
,
listener
);
return
this
;
},
// Produces a DOM element to be assigned to your view. Exposed for
// subclasses using an alternative DOM manipulation API.
_createElement
:
function
(
tagName
)
{
return
document
.
createElement
(
tagName
);
},
// Ensure that the View has a DOM element to render into.
// If `this.el` is a string, pass it through `$()`, take the first
// matching element, and re-assign it to `el`. Otherwise, create
...
...
@@ -1102,11 +1299,17 @@
var
attrs
=
_
.
extend
({},
_
.
result
(
this
,
'
attributes
'
));
if
(
this
.
id
)
attrs
.
id
=
_
.
result
(
this
,
'
id
'
);
if
(
this
.
className
)
attrs
[
'
class
'
]
=
_
.
result
(
this
,
'
className
'
);
var
$el
=
Backbone
.
$
(
'
<
'
+
_
.
result
(
this
,
'
tagName
'
)
+
'
>
'
).
attr
(
attrs
);
this
.
setElement
(
$el
,
false
);
this
.
setElement
(
this
.
_createElement
(
_
.
result
(
this
,
'
tagName
'
))
);
this
.
_setAttributes
(
attrs
);
}
else
{
this
.
setElement
(
_
.
result
(
this
,
'
el
'
)
,
false
);
this
.
setElement
(
_
.
result
(
this
,
'
el
'
));
}
},
// Set attributes from a hash on this view's element. Exposed for
// subclasses using an alternative DOM manipulation API.
_setAttributes
:
function
(
attributes
)
{
this
.
$el
.
attr
(
attributes
);
}
});
...
...
@@ -1175,14 +1378,13 @@
params
.
processData
=
false
;
}
// If we're sending a `PATCH` request, and we're in an old Internet Explorer
// that still has ActiveX enabled by default, override jQuery to use that
// for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
if
(
params
.
type
===
'
PATCH
'
&&
noXhrPatch
)
{
params
.
xhr
=
function
()
{
return
new
ActiveXObject
(
"
Microsoft.XMLHTTP
"
);
};
}
// Pass along `textStatus` and `errorThrown` from jQuery.
var
error
=
options
.
error
;
options
.
error
=
function
(
xhr
,
textStatus
,
errorThrown
)
{
options
.
textStatus
=
textStatus
;
options
.
errorThrown
=
errorThrown
;
if
(
error
)
error
.
call
(
options
.
context
,
xhr
,
textStatus
,
errorThrown
);
};
// Make the request, allowing the user to override any Ajax options.
var
xhr
=
options
.
xhr
=
Backbone
.
ajax
(
_
.
extend
(
params
,
options
));
...
...
@@ -1190,10 +1392,6 @@
return
xhr
;
};
var
noXhrPatch
=
typeof
window
!==
'
undefined
'
&&
!!
window
.
ActiveXObject
&&
!
(
window
.
XMLHttpRequest
&&
(
new
XMLHttpRequest
).
dispatchEvent
);
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
var
methodMap
=
{
'
create
'
:
'
POST
'
,
...
...
@@ -1251,17 +1449,18 @@
var
router
=
this
;
Backbone
.
history
.
route
(
route
,
function
(
fragment
)
{
var
args
=
router
.
_extractParameters
(
route
,
fragment
);
router
.
execute
(
callback
,
args
);
router
.
trigger
.
apply
(
router
,
[
'
route:
'
+
name
].
concat
(
args
));
router
.
trigger
(
'
route
'
,
name
,
args
);
Backbone
.
history
.
trigger
(
'
route
'
,
router
,
name
,
args
);
if
(
router
.
execute
(
callback
,
args
,
name
)
!==
false
)
{
router
.
trigger
.
apply
(
router
,
[
'
route:
'
+
name
].
concat
(
args
));
router
.
trigger
(
'
route
'
,
name
,
args
);
Backbone
.
history
.
trigger
(
'
route
'
,
router
,
name
,
args
);
}
});
return
this
;
},
// Execute a route handler with the provided parameters. This is an
// excellent place to do pre-route setup or post-route cleanup.
execute
:
function
(
callback
,
args
)
{
execute
:
function
(
callback
,
args
,
name
)
{
if
(
callback
)
callback
.
apply
(
this
,
args
);
},
...
...
@@ -1334,12 +1533,6 @@
// Cached regex for stripping leading and trailing slashes.
var
rootStripper
=
/^
\/
+|
\/
+$/g
;
// Cached regex for detecting MSIE.
var
isExplorer
=
/msie
[\w
.
]
+/
;
// Cached regex for removing a trailing slash.
var
trailingSlash
=
/
\/
$/
;
// Cached regex for stripping urls of hash.
var
pathStripper
=
/#.*$/
;
...
...
@@ -1355,7 +1548,29 @@
// Are we at the app root?
atRoot
:
function
()
{
return
this
.
location
.
pathname
.
replace
(
/
[^\/]
$/
,
'
$&/
'
)
===
this
.
root
;
var
path
=
this
.
location
.
pathname
.
replace
(
/
[^\/]
$/
,
'
$&/
'
);
return
path
===
this
.
root
&&
!
this
.
getSearch
();
},
// Does the pathname match the root?
matchRoot
:
function
()
{
var
path
=
this
.
decodeFragment
(
this
.
location
.
pathname
);
var
root
=
path
.
slice
(
0
,
this
.
root
.
length
-
1
)
+
'
/
'
;
return
root
===
this
.
root
;
},
// Unicode characters in `location.pathname` are percent encoded so they're
// decoded for comparison. `%25` should not be decoded since it may be part
// of an encoded parameter.
decodeFragment
:
function
(
fragment
)
{
return
decodeURI
(
fragment
.
replace
(
/%25/g
,
'
%2525
'
));
},
// In IE6, the hash fragment and search params are incorrect if the
// fragment contains `?`.
getSearch
:
function
()
{
var
match
=
this
.
location
.
href
.
replace
(
/#.*/
,
''
).
match
(
/
\?
.+/
);
return
match
?
match
[
0
]
:
''
;
},
// Gets the true hash value. Cannot use location.hash directly due to bug
...
...
@@ -1365,14 +1580,19 @@
return
match
?
match
[
1
]
:
''
;
},
// Get the cross-browser normalized URL fragment, either from the URL,
// the hash, or the override.
getFragment
:
function
(
fragment
,
forcePushState
)
{
// Get the pathname and search params, without the root.
getPath
:
function
()
{
var
path
=
this
.
decodeFragment
(
this
.
location
.
pathname
+
this
.
getSearch
()
).
slice
(
this
.
root
.
length
-
1
);
return
path
.
charAt
(
0
)
===
'
/
'
?
path
.
slice
(
1
)
:
path
;
},
// Get the cross-browser normalized URL fragment from the path or hash.
getFragment
:
function
(
fragment
)
{
if
(
fragment
==
null
)
{
if
(
this
.
_hasPushState
||
!
this
.
_wantsHashChange
||
forcePushState
)
{
fragment
=
decodeURI
(
this
.
location
.
pathname
+
this
.
location
.
search
);
var
root
=
this
.
root
.
replace
(
trailingSlash
,
''
);
if
(
!
fragment
.
indexOf
(
root
))
fragment
=
fragment
.
slice
(
root
.
length
);
if
(
this
.
_usePushState
||
!
this
.
_wantsHashChange
)
{
fragment
=
this
.
getPath
();
}
else
{
fragment
=
this
.
getHash
();
}
...
...
@@ -1383,7 +1603,7 @@
// Start the hash change handling, returning `true` if the current URL matches
// an existing route, and `false` otherwise.
start
:
function
(
options
)
{
if
(
History
.
started
)
throw
new
Error
(
"
Backbone.history has already been started
"
);
if
(
History
.
started
)
throw
new
Error
(
'
Backbone.history has already been started
'
);
History
.
started
=
true
;
// Figure out the initial configuration. Do we need an iframe?
...
...
@@ -1391,36 +1611,16 @@
this
.
options
=
_
.
extend
({
root
:
'
/
'
},
this
.
options
,
options
);
this
.
root
=
this
.
options
.
root
;
this
.
_wantsHashChange
=
this
.
options
.
hashChange
!==
false
;
this
.
_hasHashChange
=
'
onhashchange
'
in
window
;
this
.
_useHashChange
=
this
.
_wantsHashChange
&&
this
.
_hasHashChange
;
this
.
_wantsPushState
=
!!
this
.
options
.
pushState
;
this
.
_hasPushState
=
!!
(
this
.
options
.
pushState
&&
this
.
history
&&
this
.
history
.
pushState
);
var
fragment
=
this
.
getFragment
();
var
docMode
=
document
.
documentMode
;
var
oldIE
=
(
isExplorer
.
exec
(
navigator
.
userAgent
.
toLowerCase
())
&&
(
!
docMode
||
docMode
<=
7
));
this
.
_hasPushState
=
!!
(
this
.
history
&&
this
.
history
.
pushState
);
this
.
_usePushState
=
this
.
_wantsPushState
&&
this
.
_hasPushState
;
this
.
fragment
=
this
.
getFragment
();
// Normalize root to always include a leading and trailing slash.
this
.
root
=
(
'
/
'
+
this
.
root
+
'
/
'
).
replace
(
rootStripper
,
'
/
'
);
if
(
oldIE
&&
this
.
_wantsHashChange
)
{
var
frame
=
Backbone
.
$
(
'
<iframe src="javascript:0" tabindex="-1">
'
);
this
.
iframe
=
frame
.
hide
().
appendTo
(
'
body
'
)[
0
].
contentWindow
;
this
.
navigate
(
fragment
);
}
// Depending on whether we're using pushState or hashes, and whether
// 'onhashchange' is supported, determine how we check the URL state.
if
(
this
.
_hasPushState
)
{
Backbone
.
$
(
window
).
on
(
'
popstate
'
,
this
.
checkUrl
);
}
else
if
(
this
.
_wantsHashChange
&&
(
'
onhashchange
'
in
window
)
&&
!
oldIE
)
{
Backbone
.
$
(
window
).
on
(
'
hashchange
'
,
this
.
checkUrl
);
}
else
if
(
this
.
_wantsHashChange
)
{
this
.
_checkUrlInterval
=
setInterval
(
this
.
checkUrl
,
this
.
interval
);
}
// Determine if we need to change the base url, for a pushState link
// opened by a non-pushState browser.
this
.
fragment
=
fragment
;
var
loc
=
this
.
location
;
// Transition from hashChange to pushState or vice versa if both are
// requested.
if
(
this
.
_wantsHashChange
&&
this
.
_wantsPushState
)
{
...
...
@@ -1428,27 +1628,75 @@
// If we've started off with a route from a `pushState`-enabled
// browser, but we're currently in a browser that doesn't support it...
if
(
!
this
.
_hasPushState
&&
!
this
.
atRoot
())
{
this
.
fragment
=
this
.
getFragment
(
null
,
true
)
;
this
.
location
.
replace
(
this
.
root
+
'
#
'
+
this
.
fragment
);
var
root
=
this
.
root
.
slice
(
0
,
-
1
)
||
'
/
'
;
this
.
location
.
replace
(
root
+
'
#
'
+
this
.
getPath
()
);
// Return immediately as browser will do redirect to new url
return
true
;
// Or if we've started out with a hash-based route, but we're currently
// in a browser where it could be `pushState`-based instead...
}
else
if
(
this
.
_hasPushState
&&
this
.
atRoot
()
&&
loc
.
hash
)
{
this
.
fragment
=
this
.
getHash
().
replace
(
routeStripper
,
''
);
this
.
history
.
replaceState
({},
document
.
title
,
this
.
root
+
this
.
fragment
);
}
else
if
(
this
.
_hasPushState
&&
this
.
atRoot
())
{
this
.
navigate
(
this
.
getHash
(),
{
replace
:
true
});
}
}
// Proxy an iframe to handle location events if the browser doesn't
// support the `hashchange` event, HTML5 history, or the user wants
// `hashChange` but not `pushState`.
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
body
=
document
.
body
;
// Using `appendChild` will throw on IE < 9 if the document is not ready.
var
iWindow
=
body
.
insertBefore
(
this
.
iframe
,
body
.
firstChild
).
contentWindow
;
iWindow
.
document
.
open
();
iWindow
.
document
.
close
();
iWindow
.
location
.
hash
=
'
#
'
+
this
.
fragment
;
}
// Add a cross-platform `addEventListener` shim for older browsers.
var
addEventListener
=
window
.
addEventListener
||
function
(
eventName
,
listener
)
{
return
attachEvent
(
'
on
'
+
eventName
,
listener
);
};
// Depending on whether we're using pushState or hashes, and whether
// 'onhashchange' is supported, determine how we check the URL state.
if
(
this
.
_usePushState
)
{
addEventListener
(
'
popstate
'
,
this
.
checkUrl
,
false
);
}
else
if
(
this
.
_useHashChange
&&
!
this
.
iframe
)
{
addEventListener
(
'
hashchange
'
,
this
.
checkUrl
,
false
);
}
else
if
(
this
.
_wantsHashChange
)
{
this
.
_checkUrlInterval
=
setInterval
(
this
.
checkUrl
,
this
.
interval
);
}
if
(
!
this
.
options
.
silent
)
return
this
.
loadUrl
();
},
// Disable Backbone.history, perhaps temporarily. Not useful in a real app,
// but possibly useful for unit testing Routers.
stop
:
function
()
{
Backbone
.
$
(
window
).
off
(
'
popstate
'
,
this
.
checkUrl
).
off
(
'
hashchange
'
,
this
.
checkUrl
);
// Add a cross-platform `removeEventListener` shim for older browsers.
var
removeEventListener
=
window
.
removeEventListener
||
function
(
eventName
,
listener
)
{
return
detachEvent
(
'
on
'
+
eventName
,
listener
);
};
// Remove window listeners.
if
(
this
.
_usePushState
)
{
removeEventListener
(
'
popstate
'
,
this
.
checkUrl
,
false
);
}
else
if
(
this
.
_useHashChange
&&
!
this
.
iframe
)
{
removeEventListener
(
'
hashchange
'
,
this
.
checkUrl
,
false
);
}
// Clean up the iframe if necessary.
if
(
this
.
iframe
)
{
document
.
body
.
removeChild
(
this
.
iframe
);
this
.
iframe
=
null
;
}
// Some environments will throw when clearing an undefined interval.
if
(
this
.
_checkUrlInterval
)
clearInterval
(
this
.
_checkUrlInterval
);
History
.
started
=
false
;
},
...
...
@@ -1463,9 +1711,13 @@
// calls `loadUrl`, normalizing across the hidden iframe.
checkUrl
:
function
(
e
)
{
var
current
=
this
.
getFragment
();
// If the user pressed the back button, the iframe's hash will have
// changed and we should use that for comparison.
if
(
current
===
this
.
fragment
&&
this
.
iframe
)
{
current
=
this
.
get
Fragment
(
this
.
getHash
(
this
.
iframe
)
);
current
=
this
.
get
Hash
(
this
.
iframe
.
contentWindow
);
}
if
(
current
===
this
.
fragment
)
return
false
;
if
(
this
.
iframe
)
this
.
navigate
(
current
);
this
.
loadUrl
();
...
...
@@ -1475,6 +1727,8 @@
// match, returns `true`. If no defined routes matches the fragment,
// returns `false`.
loadUrl
:
function
(
fragment
)
{
// If the root doesn't match, no routes can match either.
if
(
!
this
.
matchRoot
())
return
false
;
fragment
=
this
.
fragment
=
this
.
getFragment
(
fragment
);
return
_
.
any
(
this
.
handlers
,
function
(
handler
)
{
if
(
handler
.
route
.
test
(
fragment
))
{
...
...
@@ -1495,31 +1749,42 @@
if
(
!
History
.
started
)
return
false
;
if
(
!
options
||
options
===
true
)
options
=
{
trigger
:
!!
options
};
var
url
=
this
.
root
+
(
fragment
=
this
.
getFragment
(
fragment
||
''
));
// Normalize the fragment.
fragment
=
this
.
getFragment
(
fragment
||
''
);
// Strip the hash for matching.
fragment
=
fragment
.
replace
(
pathStripper
,
''
);
// Don't include a trailing slash on the root.
var
root
=
this
.
root
;
if
(
fragment
===
''
||
fragment
.
charAt
(
0
)
===
'
?
'
)
{
root
=
root
.
slice
(
0
,
-
1
)
||
'
/
'
;
}
var
url
=
root
+
fragment
;
// Strip the hash and decode for matching.
fragment
=
this
.
decodeFragment
(
fragment
.
replace
(
pathStripper
,
''
));
if
(
this
.
fragment
===
fragment
)
return
;
this
.
fragment
=
fragment
;
// Don't include a trailing slash on the root.
if
(
fragment
===
''
&&
url
!==
'
/
'
)
url
=
url
.
slice
(
0
,
-
1
);
// If pushState is available, we use it to set the fragment as a real URL.
if
(
this
.
_
has
PushState
)
{
if
(
this
.
_
use
PushState
)
{
this
.
history
[
options
.
replace
?
'
replaceState
'
:
'
pushState
'
]({},
document
.
title
,
url
);
// If hash changes haven't been explicitly disabled, update the hash
// fragment to store history.
}
else
if
(
this
.
_wantsHashChange
)
{
this
.
_updateHash
(
this
.
location
,
fragment
,
options
.
replace
);
if
(
this
.
iframe
&&
(
fragment
!==
this
.
getFragment
(
this
.
getHash
(
this
.
iframe
))))
{
if
(
this
.
iframe
&&
(
fragment
!==
this
.
getHash
(
this
.
iframe
.
contentWindow
)))
{
var
iWindow
=
this
.
iframe
.
contentWindow
;
// Opening and closing the iframe tricks IE7 and earlier to push a
// history entry on hash-tag change. When replace is true, we don't
// want this.
if
(
!
options
.
replace
)
this
.
iframe
.
document
.
open
().
close
();
this
.
_updateHash
(
this
.
iframe
.
location
,
fragment
,
options
.
replace
);
if
(
!
options
.
replace
)
{
iWindow
.
document
.
open
();
iWindow
.
document
.
close
();
}
this
.
_updateHash
(
iWindow
.
location
,
fragment
,
options
.
replace
);
}
// If you've told us that you explicitly don't want fallback hashchange-
...
...
@@ -1550,7 +1815,7 @@
// Helpers
// -------
// Helper function to correctly set up the prototype chain
,
for subclasses.
// Helper function to correctly set up the prototype chain for subclasses.
// Similar to `goog.inherits`, but uses a hash of prototype properties and
// class properties to be extended.
var
extend
=
function
(
protoProps
,
staticProps
)
{
...
...
@@ -1559,7 +1824,7 @@
// The constructor function for the new subclass is either defined by you
// (the "constructor" property in your `extend` definition), or defaulted
// by us to simply call the parent
's
constructor.
// by us to simply call the parent constructor.
if
(
protoProps
&&
_
.
has
(
protoProps
,
'
constructor
'
))
{
child
=
protoProps
.
constructor
;
}
else
{
...
...
@@ -1570,7 +1835,7 @@
_
.
extend
(
child
,
parent
,
staticProps
);
// Set the prototype chain to inherit from `parent`, without calling
// `parent`
's
constructor function.
// `parent` constructor function.
var
Surrogate
=
function
(){
this
.
constructor
=
child
;
};
Surrogate
.
prototype
=
parent
.
prototype
;
child
.
prototype
=
new
Surrogate
;
...
...
@@ -1598,7 +1863,7 @@
var
wrapError
=
function
(
model
,
options
)
{
var
error
=
options
.
error
;
options
.
error
=
function
(
resp
)
{
if
(
error
)
error
(
model
,
resp
,
options
);
if
(
error
)
error
.
call
(
options
.
context
,
model
,
resp
,
options
);
model
.
trigger
(
'
error
'
,
model
,
resp
,
options
);
};
};
...
...
examples/typescript-backbone/node_modules/jquery/dist/jquery.js
View file @
440ef2b1
/*!
* jQuery JavaScript Library v2.1.
3
* jQuery JavaScript Library v2.1.
4
* http://jquery.com/
*
* Includes Sizzle.js
...
...
@@ -9,7 +9,7 @@
* Released under the MIT license
* http://jquery.org/license
*
* Date: 201
4-12-18T15:1
1Z
* Date: 201
5-04-28T16:0
1Z
*/
(
function
(
global
,
factory
)
{
...
...
@@ -67,7 +67,7 @@ var
// Use the correct document accordingly with window argument (sandbox)
document
=
window
.
document
,
version
=
"
2.1.
3
"
,
version
=
"
2.1.
4
"
,
// Define a local copy of jQuery
jQuery
=
function
(
selector
,
context
)
{
...
...
@@ -531,7 +531,12 @@ jQuery.each("Boolean Number String Function Array Date RegExp Object Error".spli
});
function
isArraylike
(
obj
)
{
var
length
=
obj
.
length
,
// Support: iOS 8.2 (not reproducible in simulator)
// `in` check used to prevent JIT error (gh-2145)
// hasOwn isn't used here due to false negatives
// regarding Nodelist length in IE
var
length
=
"
length
"
in
obj
&&
obj
.
length
,
type
=
jQuery
.
type
(
obj
);
if
(
type
===
"
function
"
||
jQuery
.
isWindow
(
obj
)
)
{
...
...
examples/typescript-backbone/node_modules/lodash/index.js
View file @
440ef2b1
This source diff could not be displayed because it is too large. You can
view the blob
instead.
examples/typescript-backbone/node_modules/todomvc-common/base.js
View file @
440ef2b1
...
...
@@ -114,7 +114,12 @@
})({});
if
(
location
.
hostname
===
'
todomvc.com
'
)
{
window
.
_gaq
=
[[
'
_setAccount
'
,
'
UA-31081062-1
'
],[
'
_trackPageview
'
]];(
function
(
d
,
t
){
var
g
=
d
.
createElement
(
t
),
s
=
d
.
getElementsByTagName
(
t
)[
0
];
g
.
src
=
'
//www.google-analytics.com/ga.js
'
;
s
.
parentNode
.
insertBefore
(
g
,
s
)}(
document
,
'
script
'
));
(
function
(
i
,
s
,
o
,
g
,
r
,
a
,
m
){
i
[
'
GoogleAnalyticsObject
'
]
=
r
;
i
[
r
]
=
i
[
r
]
||
function
(){
(
i
[
r
].
q
=
i
[
r
].
q
||
[]).
push
(
arguments
)},
i
[
r
].
l
=
1
*
new
Date
();
a
=
s
.
createElement
(
o
),
m
=
s
.
getElementsByTagName
(
o
)[
0
];
a
.
async
=
1
;
a
.
src
=
g
;
m
.
parentNode
.
insertBefore
(
a
,
m
)
})(
window
,
document
,
'
script
'
,
'
https://www.google-analytics.com/analytics.js
'
,
'
ga
'
);
ga
(
'
create
'
,
'
UA-31081062-1
'
,
'
auto
'
);
ga
(
'
send
'
,
'
pageview
'
);
}
/* jshint ignore:end */
...
...
@@ -228,7 +233,7 @@
xhr
.
onload
=
function
(
e
)
{
var
parsedResponse
=
JSON
.
parse
(
e
.
target
.
responseText
);
if
(
parsedResponse
instanceof
Array
)
{
var
count
=
parsedResponse
.
length
var
count
=
parsedResponse
.
length
;
if
(
count
!==
0
)
{
issueLink
.
innerHTML
=
'
This app has
'
+
count
+
'
open issues
'
;
document
.
getElementById
(
'
issue-count
'
).
style
.
display
=
'
inline
'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment