Skip to content

Instantly share code, notes, and snippets.

@FestivalBobcats
Created October 27, 2011 15:33
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save FestivalBobcats/1319903 to your computer and use it in GitHub Desktop.
Save FestivalBobcats/1319903 to your computer and use it in GitHub Desktop.
Multi image uploader in Backbone.js
(function($){
//
//-------------------------------------- Model : Image
//
Image = Backbone.Model.extend({
defaults: {
'delete' : false
}
});
//
//-------------------------------------- Collection : ProductImages
//
ProductImages = Backbone.Collection.extend({
model: Image,
url: '#{ admin_product_images_path(product.id) }',
allMarked: function(){
return this.filter(function(image){ return image.get('delete'); });
}
});
//
//-------------------------------------- View : Image
//
ImageView = Backbone.View.extend({
tagName: 'li',
events: {
'click a.img_delete' : 'markForDestroy'
},
initialize: function(){
this.template = ich.product_image;
this.model.bind('change:delete', this.render, this);
},
render: function(){
var self = this,
attr = this.model.toJSON(),
elem = $(self.el),
marked = this.model.get('delete');
if (marked) {
attr.cssState = 'marked';
attr.btnTitle = 'undo';
} else {
attr.cssState = null;
attr.btnTitle = 'delete';
}
elem.html(
self.template(attr)
);
// display red-tinted overlay if marked
if (marked) {
var img = this.$('a.img_thumb'),
offset = img.offset();
this.$('.img_overlay').css({
display: 'block',
width: img.css('width'),
height: img.css('height'),
top: offset.top + 'px',
left: offset.left + 'px'
});
}
return elem;
},
markForDestroy: function(){
var model = this.model;
model.set({ delete: !model.get('delete') });
return false;
}
});
//
//-------------------------------------- View : UploaderSidebar
//
UploaderSidebar = Backbone.View.extend({
className: 'span-4',
events: {
'click a.delete_imgs' : 'destroySelected'
},
initialize: function(){
this.template = ich.multi_img_upload;
this.collection.bind('change:delete', this.render, this);
this.collection.bind('reset', this.render, this);
},
render: function(){
var self = this,
elem = $(this.el),
collection = self.collection,
control = self.model;
elem.html(
self.template()
);
// File uploader
self.$('#img_drop').html5Uploader({
name: 'images[]',
postUrl: '#{ admin_product_images_path(product.id) }',
// When the files are read by the browser
onClientLoad: function(){
control.startLoad();
},
// This is a funky callback, thanks to XmlHttpRequest.
onServerReadyStateChange: function(request){
if (request.readyState == 4) {
control.stopLoad();
if (request.status == 200) {
collection.reset(
JSON.parse(request.responseText)
)
} else {
throw new Error('File upload request error');
}
}
}
});
// Delete button
var markedCount = collection.allMarked().length;
if (markedCount) {
var btn = self.$('a.delete_imgs');
btn.html('Delete selected (' + markedCount + ')');
btn.css({ display: 'block' });
}
return elem;
},
destroySelected: function(){
var collection = this.collection,
control = this.model;
control.startLoad();
$.ajax({
type: 'POST',
url: '#{ destroy_admin_product_images_path(product.id) }',
data: {
images: collection.allMarked().pluck('id')
},
success: function(resp){
collection.reset(resp);
control.stopLoad();
}
});
return false;
}
});
//
//-------------------------------------- View : ProductImages
//
ProductImagesView = Backbone.View.extend({
className: 'span-16',
initialize: function(){
this.collection.bind('reset', this.render, this);
},
render: function(){
var self = this,
elem = $(self.el);
// Clear the element and insert the new product <ul>
elem.html('').append(
$('<ul class="product_images">')
);
// Append image_views to product_images <ul>
self.collection.each(function(image){
self.$('ul.product_images').append(
new ImageView({ model: image }).render()
);
});
return elem;
}
});
//
//-------------------------------------- View : ImageUploader (main view)
//
UploaderControl = Backbone.Model.extend({
defaults: {
loadState: false
},
startLoad: function(){ return this.set({ loadState: true }); },
stopLoad: function(){ return this.set({ loadState: false }); }
});
//
//-------------------------------------- View : ImageUploader (main view)
//
ImageUploader = Backbone.View.extend({
initialize: function(selector){
var control = this.model = new UploaderControl(),
images = new ProductImages(#{ @images.to_json }),
imagesView = new ProductImagesView({ collection: images }),
sidebar = new UploaderSidebar({ collection: images, model: control }),
elem = $(selector);
// Insert views
elem
.append(sidebar.render())
.append(imagesView.render());
// Bind loader
loader = $('<div class="mask_loader">');
elem.append(loader);
control.bind('change:loadState', function(){
if (control.get('loadState'))
loader.css({
display: 'block',
height: elem.height() + 'px'
})
else
loader.hide()
});
}
});
// Document ready
$(function(){
new ImageUploader('#multi_img_upload');
});
})(jQuery);
@nitinhayaran
Copy link

Can you please tell me what is url on line 18

'#{ admin_product_images_path(product.id) }'

Is this some code generated from server side ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment