-
-
Save stormsson/8537132 to your computer and use it in GitHub Desktop.
JS - Backbone File uploader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment