Skip to content

Commit

Permalink
Merge 025612c into e05dbc1
Browse files Browse the repository at this point in the history
  • Loading branch information
ssafejava committed Sep 5, 2013
2 parents e05dbc1 + 025612c commit d3e0f6c
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 10 deletions.
65 changes: 56 additions & 9 deletions backbone.layoutmanager.js
Expand Up @@ -273,16 +273,16 @@ var LayoutManager = Backbone.View.extend({
},

// Shorthand to `setView` function with the `insert` flag set.
insertView: function(selector, view) {
insertView: function(selector, view, options) {
// If the `view` argument exists, then a selector was passed in. This code
// path will forward the selector on to `setView`.
if (view) {
return this.setView(selector, view, true);
if (view instanceof Backbone.View) {
return this.setView(selector, view, true, options);
}

// If no `view` argument is defined, then assume the first argument is the
// View, somewhat now confusingly named `selector`.
return this.setView(selector, true);
return this.setView(selector, true, options);
},

// Iterate over an object and ensure every value is wrapped in an array to
Expand Down Expand Up @@ -366,8 +366,8 @@ var LayoutManager = Backbone.View.extend({
//
// Must definitely wrap any render method passed in or defaults to a
// typical render function `return layout(this).render()`.
setView: function(name, view, insert) {
var manager, options, selector;
setView: function(name, view, insert, insertOptions) {
var manager, options, selector, existing;
// Parent view, the one you are setting a View on.
var root = this;

Expand Down Expand Up @@ -398,6 +398,9 @@ var LayoutManager = Backbone.View.extend({
// Add reference to the placement selector used.
selector = manager.selector = root.sections[name] || name;

// Reference existing views at this selector.
existing = root.views[selector];

// Code path is less complex for Views that are not being inserted. Simply
// remove existing Views and bail out with the assignment.
if (!insert) {
Expand All @@ -419,6 +422,23 @@ var LayoutManager = Backbone.View.extend({
// the end.
root.views[selector] = aConcat.call([], root.views[name] || [], view);

// If we're inserting, we need to insert into the views array. If one
// already exists, we may want to insert at a particular index.
if (insertOptions && _.isNumber(insertOptions.insertAt) && existing) {
// If an index is specified & existing views are presesnt,
// splice there.
existing.splice(insertOptions.insertAt, 0, view);
root.views[selector] = existing;

// Mark where we inserted for later reference when inserting
// into the DOM.
root.__manager__.insertAt = insertOptions.insertAt;
} else {
// If no index is supplied, ensure this.views[selector] is an array
// and push this View to the end.
root.views[selector] = aConcat.call([], existing || [], view);
}

// Put the parent view into `insert` mode.
root.__manager__.insert = true;

Expand Down Expand Up @@ -925,7 +945,7 @@ LayoutManager.prototype.options = {

// Use the insert method if the parent's `insert` argument is true.
if (rentManager.insert) {
this.insert($root, $el);
this.insert($root, $el, rentManager.insertAt);
} else {
this.html($root, $el);
}
Expand Down Expand Up @@ -974,8 +994,35 @@ LayoutManager.prototype.options = {
},

// Very similar to HTML except this one will appendChild by default.
insert: function($root, $el) {
$root.append($el);
insert: function($root, $el, insertAt) {
if(_.isNumber(insertAt)) {
// If an index is supplied, use it.
this.insertAtIndex($root, $el, insertAt);
} else {
$root.append($el);
}
},

// Called by `insert` if an `insertAt` is provided. Inserts a view
// at a particular position.
insertAtIndex: function($root, $el, insertAt) {
var $baseEl;
// If insertAt is < 0, it behaves like the index in Array#splice.
if(insertAt < 0) {
$baseEl = $root.children()
.eq(Math.max(0, $root.children().length + insertAt));
} else {
$baseEl = $root.children().eq(insertAt);
}

if($baseEl.length) {
// If a reference point is found for insertion, put this view behind it.
$baseEl.before($el);
} else {
// If no reference point is found (index is greater than the length of
// of the array of elements), append it.
this.insert($root, $el);
}
},

// Return a deferred for when all promises resolve/reject.
Expand Down
2 changes: 1 addition & 1 deletion node/index.js
Expand Up @@ -85,7 +85,7 @@ Backbone.Layout.configure({

// Use the insert method if the parent's `insert` argument is true.
if (rentManager.insert) {
this.insert($root, $el);
this.insert($root, $el, rentManager.insertAt);
} else {
this.html($root, $el);
}
Expand Down
68 changes: 68 additions & 0 deletions test/views.js
Expand Up @@ -2227,4 +2227,72 @@ test("A view's 'views' option should auto-invoke passed functions.", 3, function
});
});

test("`insertAt` parameter to View#insertView", 8, function() {
var Child = Backbone.Layout.extend({
template: _.template("<div class=\"child\"></div>"),
afterRender: function(){
this.$(".child").addClass("index-" + this.options.index);
}
});
var Parent = Backbone.Layout.extend({
id: "wrapper",
template: _.template("<div class=\"parent\"></div>"),
views: {
".parent" : [
new Child({index: 1}),
new Child({index: 2})
]
}
});

var view = new Parent();
view.render();

var expected1 = [
"<div class=\"parent\">",
"<div><div class=\"child index-1\"></div></div>",
"<div><div class=\"child index-2\"></div></div>",
"</div>"
];
equal(view.$el.html(), expected1.join(""), "expected HTML before an insert");

// Insert a few

// beginning
view.insertView(".parent", new Child({index: 3}), {insertAt: 0}).render();
// end
view.insertView(".parent", new Child({index: 4}), {insertAt: 3}).render();
// high index
view.insertView(".parent", new Child({index: 5}), {insertAt: 10}).render();
// neg index (one from end as in Array#splice)
view.insertView(".parent", new Child({index: 6}), {insertAt: -1}).render();

var expected2 = [
"<div class=\"parent\">",
"<div><div class=\"child index-3\"></div></div>",
"<div><div class=\"child index-1\"></div></div>",
"<div><div class=\"child index-2\"></div></div>",
"<div><div class=\"child index-4\"></div></div>",
"<div><div class=\"child index-6\"></div></div>",
"<div><div class=\"child index-5\"></div></div>",
"</div>"
];
equal(view.$el.html(), expected2.join(""),
"expected HTML after a few targeted inserts");
ok(view.views[".parent"][0].$el.find(".index-3").length,
"element 3 is correctly inserted in parent.views array");
ok(view.views[".parent"][1].$el.find(".index-1").length,
"element 1 is correctly inserted in parent.views array");
ok(view.views[".parent"][2].$el.find(".index-2").length,
"element 2 is correctly inserted in parent.views array");
ok(view.views[".parent"][3].$el.find(".index-4").length,
"element 4 is correctly inserted in parent.views array");
ok(view.views[".parent"][4].$el.find(".index-6").length,
"element 6 is correctly inserted in parent.views array");
ok(view.views[".parent"][5].$el.find(".index-5").length,
"element 5 is correctly inserted in parent.views array");

});


})();

0 comments on commit d3e0f6c

Please sign in to comment.