Merge remote branch 'remotes/upstream/master'

This commit is contained in:
Paul Uithol
2011-05-26 21:22:33 +02:00
5 changed files with 126 additions and 44 deletions

View File

@@ -680,8 +680,8 @@
route : function(route, name, callback) {
Backbone.history || (Backbone.history = new Backbone.History);
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
Backbone.history.route(route, _.bind(function(fragment) {
var args = this._extractParameters(route, fragment);
Backbone.history.route(route, _.bind(function(hash) {
var args = this._extractParameters(route, hash);
callback.apply(this, args);
this.trigger.apply(this, ['route:' + name].concat(args));
}, this));
@@ -689,8 +689,8 @@
// Simple proxy to `Backbone.history` to save a fragment into the history,
// without triggering routes.
saveLocation : function(fragment) {
Backbone.history.saveLocation(fragment);
saveLocation : function(hash) {
Backbone.history.saveLocation(hash);
},
// Bind all defined routes to `Backbone.history`. We have to reverse the
@@ -708,7 +708,7 @@
},
// Convert a route string into a regular expression, suitable for matching
// against the current location fragment.
// against the current location hash.
_routeToRegExp : function(route) {
route = route.replace(escapeRegExp, "\\$&")
.replace(namedParam, "([^\/]*)")
@@ -718,8 +718,8 @@
// Given a route, and a URL fragment that it matches, return the array of
// extracted parameters.
_extractParameters : function(route, fragment) {
return route.exec(fragment).slice(1);
_extractParameters : function(route, hash) {
return route.exec(hash).slice(1);
}
});
@@ -731,7 +731,6 @@
// browser does not support `onhashchange`, falls back to polling.
Backbone.History = function() {
this.handlers = [];
this.fragment = this.getFragment();
_.bindAll(this, 'checkUrl');
};
@@ -752,7 +751,7 @@
interval: 50,
// Get the cross-browser normalized URL fragment.
getFragment : function(loc) {
getHash : function(loc) {
return (loc || window.location).hash.replace(hashStrip, '');
},
@@ -760,16 +759,19 @@
// an existing route, and `false` otherwise.
start : function() {
if (historyStarted) throw new Error("Backbone.history has already been started");
var hash = this.getHash();
var docMode = document.documentMode;
var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
if (oldIE) {
this.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
this.saveLocation(hash);
}
if ('onhashchange' in window && !oldIE) {
$(window).bind('hashchange', this.checkUrl);
} else {
setInterval(this.checkUrl, this.interval);
}
this.hash = hash;
historyStarted = true;
return this.loadUrl();
},
@@ -783,15 +785,11 @@
// Checks the current URL to see if it has changed, and if it has,
// calls `loadUrl`, normalizing across the hidden iframe.
checkUrl : function() {
var current = this.getFragment();
if (current == this.fragment && this.iframe) {
current = this.getFragment(this.iframe.location);
}
if (current == this.fragment ||
current == decodeURIComponent(this.fragment)) return false;
if (this.iframe) {
window.location.hash = this.iframe.location.hash = current;
}
var hash = this.getHash();
if (hash == this.hash && this.iframe) hash = this.getHash(this.iframe.location);
if (hash == this.hash || hash == decodeURIComponent(this.hash)) return false;
if (this.iframe) this.saveLocation(hash);
this.hash = hash;
this.loadUrl();
},
@@ -799,10 +797,10 @@
// match, returns `true`. If no defined routes matches the fragment,
// returns `false`.
loadUrl : function() {
var fragment = this.fragment = this.getFragment();
var hash = this.hash;
var matched = _.any(this.handlers, function(handler) {
if (handler.route.test(fragment)) {
handler.callback(fragment);
if (handler.route.test(hash)) {
handler.callback(hash);
return true;
}
});
@@ -812,13 +810,13 @@
// Save a fragment into the hash history. You are responsible for properly
// URL-encoding the fragment in advance. This does not trigger
// a `hashchange` event.
saveLocation : function(fragment) {
fragment = (fragment || '').replace(hashStrip, '');
if (this.fragment == fragment) return;
window.location.hash = this.fragment = fragment;
if (this.iframe && (fragment != this.getFragment(this.iframe.location))) {
saveLocation : function(hash) {
hash = (hash || '').replace(hashStrip, '');
if (this.hash == hash) return;
window.location.hash = this.hash = hash;
if (this.iframe && (hash != this.getHash(this.iframe.location))) {
this.iframe.document.open().close();
this.iframe.location.hash = fragment;
this.iframe.location.hash = hash;
}
}
@@ -845,7 +843,7 @@
};
// Cached regex to split keys for `delegate`.
var eventSplitter = /^(\w+)\s*(.*)$/;
var eventSplitter = /^(\S+)\s*(.*)$/;
// List of view options to be merged as properties.
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName'];
@@ -992,7 +990,6 @@
// Default JSON-request options.
var params = _.extend({
type: type,
contentType: 'application/json',
dataType: 'json',
processData: false
}, options);
@@ -1004,6 +1001,7 @@
// Ensure that we have the appropriate request data.
if (!params.data && model && (method == 'create' || method == 'update')) {
params.contentType = 'application/json';
params.data = JSON.stringify(model.toJSON());
}

BIN
docs/images/bittorrent.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
docs/images/cloudapp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -280,9 +280,11 @@
<li> <a href="#examples-documentcloud">DocumentCloud</a></li>
<li> <a href="#examples-basecamp">Basecamp Mobile</a></li>
<li> <a href="#examples-flow">Flow</a></li>
<li> <a href="#examples-tilemill">TileMill</a></li>
<li> <a href="#examples-cloudapp">CloudApp</a></li>
<li> <a href="#examples-soundcloud">Mobile SoundCloud</a></li>
<li> <a href="#examples-tilemill">TileMill</a></li>
<li>- <a href="#examples-instagreat">Insta-great!</a></li>
<li>- <a href="#examples-bittorrent">BitTorrent</a></li>
<li>- <a href="#examples-quietwrite">QuietWrite</a></li>
<li>- <a href="#examples-tzigla">Tzigla</a></li>
<li>- <a href="#examples-substance">Substance</a></li>
@@ -1984,21 +1986,21 @@ var model = localBackbone.Model.extend(...);
<img src="docs/images/flow.png" alt="Flow" class="example_image" />
</a>
</div>
<p id="examples-tilemill">
Our fellow
<a href="http://www.newschallenge.org/">Knight Foundation News Challenge</a>
winners, <a href="http://mapbox.com/">MapBox</a>, created an open-source
map design studio with Backbone.js:
<a href="http://mapbox.github.com/tilemill/">TileMill</a>.
TileMill lets you manage map layers based on shapefiles and rasters, and
edit their appearance directly in the browser with the
<a href="https://github.com/mapbox/carto">Carto styling language</a>.
<p id="examples-cloudapp">
<a href="http://getcloudapp.com">CloudApp</a> is simple file and link
sharing for the Mac. Backbone.js powers the web tools
which consume the <a href="http://developer.getcloudapp.com">documented API</a>
to manage Drops. Data is either pulled manually or pushed by
<a href="http://pusher.com">Pusher</a> and fed to
<a href="http://github.com/janl/mustache.js">Mustache</a> templates for
rendering. Check out the <a href="http://cloudapp.github.com/engine">annotated source code</a>
to see the magic.
</p>
<div style="text-align: center;">
<a href="http://mapbox.github.com/tilemill/">
<img src="docs/images/tilemill.png" alt="TileMill" class="example_image" />
<a href="http://getcloudapp.com">
<img src="docs/images/cloudapp.png" alt="CloudApp" class="example_image" />
</a>
</div>
@@ -2027,6 +2029,23 @@ var model = localBackbone.Model.extend(...);
</a>
</div>
<p id="examples-tilemill">
Our fellow
<a href="http://www.newschallenge.org/">Knight Foundation News Challenge</a>
winners, <a href="http://mapbox.com/">MapBox</a>, created an open-source
map design studio with Backbone.js:
<a href="http://mapbox.github.com/tilemill/">TileMill</a>.
TileMill lets you manage map layers based on shapefiles and rasters, and
edit their appearance directly in the browser with the
<a href="https://github.com/mapbox/carto">Carto styling language</a>.
</p>
<div style="text-align: center;">
<a href="http://mapbox.github.com/tilemill/">
<img src="docs/images/tilemill.png" alt="TileMill" class="example_image" />
</a>
</div>
<p id="examples-instagreat">
<a href="http://twitter.com/elliottkember">Elliott Kember</a> and
<a href="http://twitter.com/dizzyup">Hector Simpson</a> built
@@ -2043,6 +2062,22 @@ var model = localBackbone.Model.extend(...);
<img src="docs/images/instagreat.png" alt="instagre.at" class="example_image" />
</a>
</div>
<p id="examples-bittorrent">
<a href="http://www.bittorrent.com">BitTorrent</a> used Backbone to
completely rework an existing Win32 UI. Models normalize access to the
client's data and views rely heavily on the <tt>change</tt> events to keep
the UI state current. Using Backbone and SCSS,
<a href="http://www.bittorrent.com/chrysalis/">our new design</a> and UX
prototypes are considerably easier to iterate, test and work with than
the original Win32 UI.
</p>
<div style="text-align: center;">
<a href="http://www.bittorrent.com/chrysalis/">
<img src="docs/images/bittorrent.jpg" alt="BitTorrent" class="example_image" />
</a>
</div>
<p id="examples-quietwrite">
<a href="http://www.twitter.com/jamesjyu">James Yu</a> used Backbone.js to
@@ -2182,6 +2217,34 @@ Inbox.messages.fetch();
represents a logical chunk of UI, responsible for the contents of a single
DOM element.
</p>
<p>
Comparing the overall structure of Backbone to a server-side MVC framework
like <b>Rails</b>, the pieces line up like so:
</p>
<ul>
<li>
<b>Backbone.Model</b> &ndash; Like a Rails model minus the class
methods. Wraps a row of data in business logic.
</li>
<li>
<b>Backbone.Collection</b> &ndash; A group of models on the client-side,
with sorting/filtering/aggregation logic.
</li>
<li>
<b>Backbone.Controller</b> &ndash; Rails <tt>routes.rb</tt> + Rails controller
actions. Maps URLs to functions.
</li>
<li>
<b>Backbone.View</b> &ndash; A logical, re-usable piece of UI. Often,
but not always, associated with a model.
</li>
<li>
<b>Client-side Templates</b> &ndash; Rails <tt>.html.erb</tt> views,
rendering a chunk of HTML.
</li>
</ul>
<p id="FAQ-this">
<b class="header">Binding "this"</b>

View File

@@ -16,8 +16,8 @@ $(document).ready(function() {
test("View: jQuery", function() {
view.el = document.body;
equals(view.$('#qunit-header a').get(0).innerHTML, ' Backbone Test Suite');
equals(view.$('#qunit-header a').get(1).innerHTML, 'Backbone Speed Suite');
ok(view.$('#qunit-header a').get(0).innerHTML.match(/Backbone Test Suite/));
ok(view.$('#qunit-header a').get(1).innerHTML.match(/Backbone Speed Suite/));
});
test("View: make", function() {
@@ -113,4 +113,25 @@ $(document).ready(function() {
$("body").trigger("click");
equals(5, count);
});
test("View: custom events, with namespaces", function() {
var count = 0;
var ViewClass = Backbone.View.extend({
el: $('body'),
events: {
"fake$event.namespaced": "run"
},
run: function() {
count++;
}
});
var view = new ViewClass;
$('body').trigger('fake$event').trigger('fake$event');
equals(count, 2);
$('body').unbind('.namespaced');
$('body').trigger('fake$event');
equals(count, 2);
});
});