Created
October 3, 2011 14:07
-
-
Save jvanderhoof/1259171 to your computer and use it in GitHub Desktop.
Brewershub - Backbone JS
This file contains 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
_.templateSettings = { | |
evaluate : /<\?([\s\S]+?)\?>/g, | |
interpolate : /<\?=([\s\S]+?)\?>/g | |
}; | |
(function($) { | |
////// VIEWS /////// | |
window.IngredientView = Backbone.View.extend({ | |
tagName: 'li', | |
events: { | |
'click .add': 'addIngredient' | |
}, | |
initialize: function() { | |
_.bindAll(this, 'render'); | |
this.initializeTemplate(); | |
}, | |
initializeTemplate: function() { | |
this.template = _.template($(this.template).html()); | |
}, | |
render: function() { | |
$(this.el).html(this.template(this.model.toJSON())); | |
return this; | |
} | |
}); | |
window.HopView = IngredientView.extend({ | |
template: "#hop-template", | |
className: 'hop', | |
addIngredient: function() { | |
window.recipe.hops.add(new RecipeHop({'hop': this.model, 'name': this.model.get('name')})); | |
} | |
}); | |
window.YeastView = IngredientView.extend({ | |
template: "#yeast-template", | |
className: 'yeast', | |
addIngredient: function() { | |
window.recipe.yeasts.add(new RecipeYeast({'yeast': this.model, 'name': this.model.get('name')})); | |
} | |
}); | |
window.FermentableView = IngredientView.extend({ | |
template: "#fermentable-template", | |
className: 'fermentable', | |
addIngredient: function() { | |
window.recipe.fermentables.add(new RecipeFermentable({'fermentable': this.model, 'name': this.model.get('name')})); | |
} | |
}); | |
window.PantryView = Backbone.View.extend({ | |
el: '#pantry', | |
events: { | |
'click .toggle': 'toggleIngredients' | |
}, | |
toggleIngredients: function() { | |
alert('start'); | |
$(event.target).next().toggle(); | |
alert('done'); | |
}, | |
initialize: function() { | |
_.bindAll(this, 'render', 'toggleIngredients'); | |
this.template = _.template($('#pantry-template').html()); | |
this.model.hops.bind('reset', this.render); | |
this.model.fermentables.bind('reset', this.render); | |
this.model.yeasts.bind('reset', this.render); | |
}, | |
render: function() { | |
console.log('render pantry'); | |
$(this.el).html(this.template({})); | |
this.model.hops.each(function(hop) { | |
var view = new HopView({model: hop}); | |
this.$("."+hop.get('sub_type').replace(' / ', '_').toLowerCase()).append(view.render().el); | |
}); | |
this.model.yeasts.each(function(yeast) { | |
var view = new YeastView({model: yeast}); | |
this.$("."+yeast.get('sub_type').toLowerCase()).append(view.render().el); | |
}); | |
this.model.fermentables.each(function(fermentable) { | |
var view = new FermentableView({model: fermentable}); | |
this.$("."+fermentable.get('sub_type').toLowerCase()).append(view.render().el); | |
}); | |
return this; | |
} | |
}); | |
window.RecipeView = Backbone.View.extend({ | |
el: '#recipe', | |
events: { | |
'change .action_input': 'setAttributes' | |
}, | |
initialize: function() { | |
_.bindAll(this, 'render'); | |
this.model.fermentables.bind('add', this.render, this); | |
this.model.yeasts.bind('add', this.render, this); | |
this.model.hops.bind('add', this.render, this); | |
this.template = _.template($('#recipe-template').html()); | |
}, | |
setAttributes: function(){ | |
this.model.set({ | |
'batch_size': to_number(this.$('#batch_size').val()), | |
'boil_size': to_number(this.$('#boil_size').val()), | |
'efficiency': to_number(this.$('#efficiency').val()), | |
'mash_time': to_number(this.$('#mash_time').val()), | |
'mash_temp': to_number(this.$('#mash_temp').val()), | |
'mash_thickness': to_number(this.$('#mash_thickness').val()) | |
}); | |
this.model.recalculate(); | |
}, | |
render: function() { | |
$(this.el).html(this.template({model: this.model})); | |
this.pantryView = new PantryView({model: this.options.pantry}); | |
this.model.fermentables.each(function(fermentable){ | |
var view = new RecipeFermentableView({model: fermentable}); | |
this.$('.fermentables').append(view.render().el); | |
}); | |
this.model.hops.each(function(hop){ | |
var view = new RecipeHopView({model: hop}); | |
this.$('.hops').append(view.render().el); | |
}); | |
this.model.yeasts.each(function(yeast){ | |
var view = new RecipeYeastView({model: yeast}); | |
this.$('.yeasts').append(view.render().el); | |
}); | |
return this; | |
} | |
}); | |
window.RecipeIngredientView = Backbone.View.extend({ | |
tagName: 'li', | |
events: { | |
'change .action_input': 'setAttributes', | |
'click .remove': 'removeIngredient' | |
}, | |
initialize: function() { | |
_.bindAll(this, 'render', 'removeIngredient'); | |
this.initializeTemplate(); | |
}, | |
initializeTemplate: function() { | |
this.template = _.template($(this.template).html()); | |
}, | |
render: function() { | |
$(this.el).html(this.template(this.model.toJSON())); | |
$(this.el).find('input').first().focus(); | |
return this; | |
}, | |
setAttributes: function(){ | |
var ozs = to_number(this.$('.ozs').val()); | |
this.model.set({amount_ozs: ozs}); | |
window.recipe.recalculate(); | |
} | |
}); | |
window.RecipeFermentableView = window.RecipeIngredientView.extend({ | |
template: "#recipe-fermentable-template", | |
removeIngredient: function(){ | |
window.recipe.fermentables.remove(this.model); | |
window.recipe.recalculate(); | |
}, | |
setAttributes: function(){ | |
var lbs = to_number(this.$('.lbs').val()); | |
var ozs = to_number(this.$('.ozs').val()); | |
this.model.set({amount_lbs: lbs, amount_ozs: ozs}); | |
window.recipe.recalculate(); | |
} | |
}); | |
window.RecipeHopView = window.RecipeIngredientView.extend({ | |
template: "#recipe-hop-template", | |
removeIngredient: function(){ | |
window.recipe.hops.remove(this.model); | |
window.recipe.recalculate(); | |
}, | |
setAttributes: function(){ | |
var time = to_number(this.$('.time').val()); | |
var ozs = to_number(this.$('.ozs').val()); | |
var form = this.$('.form').val(); | |
var phase = this.$('.phase').val(); | |
this.model.set({'amount_time': time, 'amount_ozs': ozs, 'form': form, 'phase': phase}); | |
window.recipe.recalculate(); | |
} | |
}); | |
window.RecipeYeastView = window.RecipeIngredientView.extend({ | |
template: "#recipe-yeast-template", | |
removeIngredient: function(){ | |
window.recipe.yeasts.remove(this.model); | |
window.recipe.recalculate(); | |
} | |
}); | |
////// MODELS /////// | |
window.Ingredient = Backbone.RelationalModel.extend({}); | |
window.Yeast = Ingredient.extend({}); | |
window.Fermentable = Ingredient.extend({}); | |
window.Hop = Ingredient.extend({}); | |
window.Pantry = Backbone.Model.extend({ | |
initialize: function() { | |
this.hops = new Hops(); | |
this.hops.fetch(); | |
this.fermentables = new Fermentables(); | |
this.fermentables.fetch(); | |
this.yeasts = new Yeasts(); | |
this.yeasts.fetch(); | |
} | |
}); | |
window.RecipeIngredient = Backbone.RelationalModel.extend({ | |
defaults: { | |
'amount_ozs': 0, | |
'amount_lbs': 0, | |
'amount_gms': 0, | |
'amount_time': 30 | |
}, | |
}); | |
window.RecipeFermentable = RecipeIngredient.extend({ | |
relations: [{ | |
type: Backbone.HasOne, | |
key: 'fermentable', | |
relatedModel: 'Fermentable' | |
}] | |
}); | |
window.RecipeHop = RecipeIngredient.extend({ | |
relations: [{ | |
type: Backbone.HasOne, | |
key: 'hop', | |
relatedModel: 'Hop' | |
}], | |
defaults: { | |
'amount_ozs': 0, | |
'amount_gms': 0, | |
'amount_time': 30, | |
'form': 'pellet', | |
'phase': 'boil' | |
} | |
}); | |
window.RecipeYeast = RecipeIngredient.extend({ | |
type: Backbone.HasOne, | |
key: 'yeast', | |
relatedModel: 'Yeast' | |
}); | |
window.Recipe = Backbone.RelationalModel.extend({ | |
relations: [{ | |
type: Backbone.HasMany, | |
key: 'fermentables', | |
relatedModel: 'RecipeFermentable', | |
collectionType: 'RecipeFermentables' | |
}, { | |
type: Backbone.HasMany, | |
key: 'hops', | |
relatedModel: 'RecipeHop', | |
collectionType: RecipeHops | |
}, { | |
type: Backbone.HasMany, | |
key: 'yeasts', | |
relatedModel: 'RecipeYeast', | |
collectionType: 'RecipeYeasts' | |
}], | |
defaults: { | |
'title': '', | |
'batch_size': 5, | |
'boil_size': 3, | |
'efficiency': 70, | |
'mash_time': 60, | |
'mash_temp': 140, | |
'mash_thickness': 1.25, | |
'original_gravity': 1.0, | |
'final_gravity': 1.0, | |
'srm': 0, | |
'abw': 0, | |
'abv': 0, | |
'ibu': 0, | |
'mash': true | |
}, | |
initialize: function() { | |
this.fermentables = new RecipeFermentables(); | |
this.hops = new RecipeHops(); | |
this.yeasts = new RecipeYeasts(); | |
}, | |
rational_tanh: function(x) { | |
if (x < -3) { return -1; } else { if (x > 3){ return 1; } else { return x * ( 27 + x * x ) / ( 27 + 9 * x * x ); } } | |
}, | |
rager: function(boil_gravity) { | |
var recipe = this; | |
var ga = 0; | |
if (boil_gravity > 1.05) { ga = (boil_gravity - 1.050) / 0.2; } | |
var temp_ibu = 0; | |
recipe.hops.each(function(hop){ | |
if (hop.get('phase') == 'boil') { | |
var amount = hop.get('amount_ozs'); | |
var ingr = hop.get('hop'); | |
var time = hop.get('amount_time'); | |
var aau = ((ingr.get('aau_low') + ingr.get('aau_high')) / 2) / 100; | |
var utilization = (18.11 + 13.86 * recipe.rational_tanh((time - 31.32) / 18.27)) / 100; | |
if (hop.get('form') == 'pellet') { utilization *= 1.15; } | |
temp_ibu += (amount * utilization * aau * 7462)/(recipe.get('batch_size') * (1 + ga)); | |
} | |
}); | |
recipe.set({'ibu': Math.round(temp_ibu)}); | |
}, | |
recalculate: function() { | |
var total_ppg = 0; | |
var total_color = 0; | |
var attenuation = 0; | |
var recipe = this; | |
this.fermentables.each(function(fermentable){ | |
var amount = fermentable.get('amount_lbs') + fermentable.get('amount_ozs')/16; | |
var ingr = fermentable.get('fermentable'); | |
if (ingr.get('fully_fermentable')) { | |
total_ppg += amount * ingr.get('typical_ppg'); | |
} else { | |
total_ppg += amount * ingr.get('typical_ppg') * recipe.get('efficiency')/100; | |
} | |
total_color += ingr.get('color') * amount/recipe.get('batch_size'); | |
}); | |
this.yeasts.each(function(yeast){ | |
var amount = 1; //yeast.get('amount_ozs'); | |
var ingr = yeast.get('yeast'); | |
if (attenuation < ingr.get('attenuation')/100) { | |
attenuation = ingr.get('attenuation')/100; | |
} | |
}); | |
var og = (1 + Math.round(total_ppg/recipe.get('batch_size'))/1000); | |
var boil_gravity = 1 + Math.round(total_ppg/recipe.get('boil_size'))/1000; | |
var final_gravity = Math.round((og*1000 - 1000) - ((og*1000-1000)*attenuation)+1000)/1000; | |
recipe.set({'original_gravity': og, | |
'final_gravity': final_gravity, | |
'srm': Math.round(1.4922 * Math.round(Math.pow(total_color,0.6859))) | |
}); | |
this.rager(boil_gravity); | |
if (window.recipeView) { window.recipeView.render() }; | |
} | |
}); | |
////// COLLECTIONS /////// | |
window.Ingredients = Backbone.Collection.extend({}); | |
window.Hops = Ingredients.extend({ | |
model: Hop, | |
url: '/hops' | |
}); | |
window.Yeasts = Ingredients.extend({ | |
model: Yeast, | |
url: '/yeasts' | |
}); | |
window.Fermentables = Ingredients.extend({ | |
model: Fermentable, | |
url: '/fermentables' | |
}); | |
window.RecipeIngredients = Backbone.Collection.extend({}); | |
window.RecipeFermentables = RecipeIngredients.extend({model: RecipeFermentable}); | |
window.RecipeHops = RecipeIngredients.extend({model: RecipeHop}); | |
window.RecipeYeasts = RecipeIngredients.extend({model: RecipeYeast}); | |
////// APP //////////// | |
window.pantry = new Pantry(); | |
window.recipe = new Recipe(); | |
$(document).ready(function() { | |
recipeView = new RecipeView({model: window.recipe, pantry: window.pantry}); | |
$('#content').append(recipeView.render().el); | |
}); | |
})(jQuery); | |
function to_number(value) { | |
return (isNaN(value) ? 0 : parseFloat(value)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment