Skip to content
Browse files

Editable recipe title and removed some of the addClass/removeClass

hidden excessiveness. Show/hide has been factored into css
  • Loading branch information...
1 parent bbf8465 commit a968ea8bb3c7fc2d452786b930fa27da1fce3ade @lashleigh committed Mar 22, 2012
View
90 app/assets/javascripts/recipes/index.js
@@ -15,13 +15,15 @@ truncate = function(num) {
}
App.Models.Recipe = Backbone.Model.extend({
+ url: '/recipes',
initialize: function() {
this.parts = new App.Collections.PartList;
this.notes = new App.Collections.NoteList;
this.view = new App.Views.Recipe({model: this, el: document.getElementById('recipe_container')});
this.view.render();
this.view.$el = $('#recipe_container'); //TODO not getting defined on its own - why it that?
+ this.url = '/recipes/'+this.id;
this.parts.url = '/recipes/'+this.id+'/parts';
this.parts.recipeView = this.view;
this.parts.reset(this.get('parts'));
@@ -36,6 +38,13 @@ App.Models.Recipe = Backbone.Model.extend({
});
App.Views.Recipe = Backbone.View.extend({
events: {
+ 'click .editable span' : 'editField',
+ 'blur .editable input': 'exitEditField',
+ 'keyup .editable input': 'updateTitle',
+ //'click #recipe-title h1' : 'editTitle',
+ //'blue #title input': 'exitEditTitle',
+ //'keyup #title input': 'updateTitle',
+
'click #hydration' : 'editHydration',
'blur #hydration input' : 'exitEditHydration',
'keyup #hydration input' : 'updateHydrationOnEnter',
@@ -58,11 +67,30 @@ App.Views.Recipe = Backbone.View.extend({
newNote: function() {
this.model.notes.newNote();
},
+ editField: function(e) {
+ $(e.currentTarget).next().focus().parent().addClass('editing');
+ this.$el.find('#recipe-title input').val(this.model.get('title')).focus();
+ },
+ exitEditField: function(e) {
+ $(e.currentTarget).parent().removeClass('editing');
+ },
+ updateTitle: function(e) {
+ if(e.keyCode === 13) {
+ var title = this.$el.find('#recipe-title input')
+ this.model.save({title : title.val()});
+ title.prev().text(title.val()).parent().removeClass('editing');
+ }
+ },
+ editTitle: function(e) {
+ this.$el.find('#recip-title span').parent().addClass('editing');
+ this.$el.find('#recipe-title input').focus();
+ //this.$el.find('#title').addClass('editing-title').find('input').focus();
+ },
editInnoculation: function() {
- this.$el.find('#innoculation').addClass('editing-innoculation').find('input').focus();
+ this.$el.find('#innoculation').addClass('editing').find('input').focus();
},
exitEditInnoculation: function() {
- this.$el.find('#innoculation').removeClass('editing-innoculation');
+ this.$el.find('#innoculation').removeClass('editing');
},
updateInnoculation: function(e) {
if(e.keyCode === 13) {
@@ -77,17 +105,16 @@ App.Views.Recipe = Backbone.View.extend({
starter.save({amount: truncate(half_starter*2)})
flour.save({amount: truncate(total_flour - half_starter)})
water.save({amount: truncate(hydration / 100.0 * total_flour - half_starter)})
- console.log(total_flour, half_starter, hydration)
this.exitEditInnoculation();
this.update_stats();
}
},
editHydration: function() {
- this.hydration.addClass('editing-hydration');
+ this.hydration.addClass('editing');
this.hydration_input.focus();
},
exitEditHydration: function() {
- this.hydration.removeClass('editing-hydration');
+ this.hydration.removeClass('editing');
},
newWaterMass: function() {
var water = this.model.parts.filter(function(p) { return p.get('ingredient').name === 'water'; })[0];
@@ -168,6 +195,7 @@ App.Views.Note = Backbone.View.extend({
$('#new-note').after(this.render().el);
this.model.bind('change', this.render, this);
this.setHeight();
+ this.$el = $(this.el);
},
events: {
'click .body' : 'editBody',
@@ -181,13 +209,11 @@ App.Views.Note = Backbone.View.extend({
$(this.el).remove();
},
editBody: function() {
- this.note_body.addClass('hidden');
- this.edit_body.removeClass('hidden');
+ this.$el.addClass('editing');
this.body_input.focus();
},
exitEditBody: function() {
- this.note_body.removeClass('hidden');
- this.edit_body.addClass('hidden');
+ this.$el.removeClass('editing');
},
updateBody: function() {
this.model.save({'body' : this.body_input.val()});
@@ -229,7 +255,6 @@ App.Views.Note = Backbone.View.extend({
$(this.el).find('.time').text(this.localTime());
this.note_body = $(this.el).find('.body');
this.body_input = $(this.el).find('.body-input');
- this.edit_body = $(this.el).find('.edit-body');
this.setHeight();
return this;
}
@@ -244,9 +269,7 @@ App.Views.Part = Backbone.View.extend({
this.model.bind('destroy', this.remove, this);
},
events: {
- 'click .amount' : 'editAmount',
- 'click .percent': 'editPercent',
- 'click .name' : 'editName',
+ 'click .editable span' : 'editField',
'click .remove': 'clear',
'click .fixed-percent-input': 'toggleFixedPercent',
"keypress .edit-amount" : "updateAmountOnEnter",
@@ -256,24 +279,8 @@ App.Views.Part = Backbone.View.extend({
toggleFixedPercent: function() {
this.model.save({'fixed_percent': !this.model.get('fixed_percent')});
},
- editAmount: function(event) {
- this.resetFields('editing-amount');
- this.input_amount.parent().addClass('editing');
- this.input_amount.removeClass('hidden').focus();
- },
- editPercent: function() {
- this.resetFields('editing-percent');
- this.input_percent.parent().addClass('editing');
- this.input_percent.removeClass('hidden').focus();
- },
- editName: function() {
- this.resetFields('editing-name');
- this.input_name.parent().addClass('editing');
- this.input_name.removeClass('hidden').focus();
- },
- resetFields: function(editing_field) {
- //$('.recipe').removeClass('not-editing');
- $(this.el).addClass(editing_field);
+ editField: function(e) {
+ $(e.currentTarget).next().focus().parent().addClass('editing');
this.input_name.val(this.model.get('ingredient').name);
this.input_amount.val(this.model.get('amount'));
this.input_percent.val(this.model.get('percent'));
@@ -283,15 +290,13 @@ App.Views.Part = Backbone.View.extend({
var percent = truncate(this.input_percent.val());
var amount = truncate(percent / 100 * this.model.collection.flour_mass());
this.model.save({amount: amount, percent: percent});
- this.exitEditing();
}
},
updateAmountOnEnter: function(e) {
if(e.keyCode == 13) {
- var amount = this.input_amount.val();
+ var amount = truncate(this.input_amount.val());
var percent = as_percent(amount / this.model.collection.flour_mass());
this.model.save({amount: amount, percent: percent});
- this.exitEditing();
}
},
updateIngredientOnEnter: function(e) {
@@ -306,14 +311,9 @@ App.Views.Part = Backbone.View.extend({
name: this.input_name.val()
}
})
- this.exitEditing();
},
- exitEditing: function() {
- //$('.recipe').addClass('not-editing');
- this.input_amount.addClass('hidden').parent().removeClass('editing');
- this.input_name.addClass('hidden').parent().removeClass('editing');
- this.input_percent.addClass('hidden').parent().removeClass('editing');
- $(this.el).removeClass("editing-amount editing-name editing-percent");
+ exitEditing: function(e) {
+ $(e.currentTarget).parent().removeClass('editing');
},
remove: function() {
$(this.el).remove();
@@ -338,11 +338,6 @@ App.Views.Part = Backbone.View.extend({
}
}
},
- truncate: function(hash) {
- hash.amount = truncate(hash.amount);
- hash.percent = truncate(hash.percent);
- return hash
- },
render: function() {
var template = _.template(this.template);
$(this.el).html(template(this.model.toJSON()));
@@ -356,8 +351,7 @@ App.Views.Part = Backbone.View.extend({
this.input_amount.bind('blur', _.bind(this.exitEditing, this)).val(attrs.amount);
this.input_percent.bind('blur', _.bind(this.exitEditing, this)).val(attrs.percent);
this.input_name.bind('blur', _.bind(this.exitEditing, this)).val(attrs.ingredient.name).autocomplete(this.autocomplete());
- if(this.model.get('primary')) {
- } else {
+ if(!this.model.get('primary')) {
this.el.getElementsByClassName('fixed-percent-input')[0].checked = this.model.get('fixed_percent');
}
return this;
View
60 app/assets/stylesheets/recipe.css.less
@@ -2,41 +2,41 @@
.recipe {
float: left;
padding: 20px;
+ #recipe-title {
+ padding: 12px;
+ span, input {
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 25px;
+ line-height: 18px;
+ width: 100%;
+ }
+ }
+ .editable:hover, .editing {
+ background: #ffffd3;
+ }
+ .editing {
+ span, h1 {
+ display:none;
+ }
+ input {
+ display: inline !important;
+ }
+ }
}
.part input, #hydration, #innoculation {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
background: transparent;
}
- .editable:hover, .editing {
- background: #ffffd3;
- }
- #hydration, #innoculation {
+ #hydration, #innoculation, #recipe-title {
span, input {
width: 3em;
}
input {
display: none;
}
}
- .editing-hydration, .editing-innoculation {
- span {
- display:none
- }
- input {
- display: inline !important;
- }
- }
- .editing-amount .amount {
- display: none;
- }
- .editing-name .name {
- display: none;
- }
- .editing-percent .percent {
- display: none;
- }
.amount-col {
width: 50px;
.amount, input.edit-amount, input#new-amount {
@@ -78,9 +78,10 @@
#part-list {
.part {
height: 2.5em;
- }
- .part:hover {
- //background: #bab;
+ width: 300px;
+ .editable input {
+ display: none;
+ }
}
tr:nth-child(odd) {
background: #ddd;
@@ -116,9 +117,20 @@
overflow: hidden;
}
}
+ .note.editing {
+ .show-body .body {
+ display: none;
+ }
+ .edit-body {
+ display: inline !important;
+ }
+ }
.note {
border: gray 1px dashed;
padding: 12px;
+ .edit-body {
+ display: none;
+ }
.body {
width: 100%;
overflow: auto;
View
19 app/controllers/recipes_controller.rb
@@ -14,7 +14,6 @@ def index
# GET /recipes/1.xml
def show
@recipe = Recipe.find(params[:id])
- @ingredients = Ingredient.autocomplete_list
respond_to do |format|
format.html # show.html.erb
@@ -36,6 +35,7 @@ def new
# GET /recipes/1/edit
def edit
@recipe = Recipe.find(params[:id])
+ @ingredients = Ingredient.autocomplete_list
end
# POST /recipes
@@ -54,16 +54,15 @@ def create
# PUT /recipes/1
# PUT /recipes/1.xml
def update
- @recipe = Recipe.find(params[:id])
+ recipe = Recipe.find(params[:id])
+ if !params[:title].blank?
+ recipe.title = params[:title]
+ end
- respond_to do |format|
- if @recipe.update_attributes(params[:recipe])
- format.html { redirect_to(@recipe, :notice => 'Recipe was successfully updated.') }
- format.xml { head :ok }
- else
- format.html { render :action => "edit" }
- format.xml { render :xml => @recipe.errors, :status => :unprocessable_entity }
- end
+ if recipe.save
+ render :json => recipe
+ else
+ render :json => {'message' => 'failed to save'}
end
end
View
1 app/models/recipe.rb
@@ -3,6 +3,7 @@ class Recipe
before_create :basic_parts
key :title, String, :default => 'bread'
+ key :photo, String
many :parts
many :notes
timestamps!
View
142 app/views/recipes/edit.html.erb
@@ -0,0 +1,142 @@
+<div id="recipe_container" >
+ <div class="recipe">
+ <div id="recipe-title" class="editable">
+ <span><%= @recipe.title %></span>
+ <input value=<%= @recipe.title %> />
+ </div>
+ <%= @recipe.photo ? @recipe.photo.html_safe : ''%>
+ <table>
+ <tbody id="part-list">
+ </tbody>
+ <tfoot>
+ <tr id="new-part">
+ <td class="amount-col"> <input id="new-amount" placeholder="12" /> </td>
+ <td class="unit-col">g</td>
+ <td class="name-col">
+ <input id="new-name" placeholder="salt" />
+ <input id="new-name-id" type="hidden" />
+ </td>
+ <td class='percent-col'>
+ <input id="new-percent" />
+ </td>
+ <td class="fixed-percent"> </td>
+ <td class="button-col"> <button class='icon icononly add button'></button> </td>
+ </tr>
+ </tfoot>
+ </table>
+ <span class="stats"> </span>
+ </div>
+ <div id="notes_container">
+ <div id="new-note" class="note">
+ <textarea id="new-note-body" ></textarea></br>
+ <input class="new-note button" type="button" value='New Note' />
+ </div>
+ </div>
+</div>
+
+<script type="text/javascript">
+ var Recipe;
+ var ingredients = <%= @ingredients.to_json.html_safe %>;
+ $(function() {
+ // By default, Underscore uses ERB-style template delimiters, this change
+ // makes it use mustache style.
+ _.templateSettings = {
+ interpolate : /\{\{([\s\S]+?)\}\}/g
+ };
+ Recipe = new App.Models.Recipe(<%= @recipe.to_json(:include => {:parts => {:include => {:ingredient => {:only => :name}}}} ).html_safe %>);
+
+ $( "#new-name" ).autocomplete({
+ minLength: 0,
+ source: ingredients,
+ focus: function( event, ui ) {
+ $( "#new-name" ).val( ui.item.label );
+ return false;
+ },
+ select: function( event, ui ) {
+ $( "#new-name" ).val( ui.item.label );
+ $( "#new-name-id" ).val( ui.item.value );
+
+ return false;
+ }
+ })
+ $.ui.autocomplete.prototype._renderItem = function( ul, item ) {
+ return $( "<li></li>" )
+ .data( "item.autocomplete", item )
+ .append( "<a>" + item.label + "</a>" )
+ .appendTo( ul );
+ };
+ });
+</script>
+
+<script type="text/template" id="primary-part-li">
+ <td class='amount-col editable'>
+ <span class="amount"> {{amount}} </span>
+ <input class="edit-amount" value={{amount}} />
+ </td>
+ <td class='unit-col'> g </td>
+
+ <td class='name-col'>
+ <span class="primary-name"> {{ingredient.name}} </span>
+ </td>
+ <td class='percent-col'> </td>
+ <td class="fixed-percent"> </td>
+ <td class='button-col'> </td>
+</script>
+
+<script type="text/template" id="part-li">
+ <td class='amount-col editable'>
+ <span class="amount"> {{amount}} </span>
+ <input class="edit-amount" value={{amount}} />
+ </td>
+
+ <td class='unit-col'> g </td>
+
+ <td class='name-col editable'>
+ <span class="name"> {{ingredient.name}} </span>
+ <input class="edit-name" type="text" value={{ingredient.name}} />
+ <input class="edit-name-id" type="hidden" value={{ingredient_id}} />
+ </td>
+ <td class='percent-col editable'>
+ <span class="percent">{{percent}}</span>
+ <input class="edit-percent " value={{percent}} />
+ </td>
+ <td class="fixed-percent">
+ <input class="fixed-percent-input" type="checkbox" value={{fixed_percent}} />
+ </td>
+ <td class='button-col'>
+ <button class='icon icononly remove danger button'></button>
+ </td>
+</script>
+
+<script type="text/template" id="recipe-stats">
+ <div id="hydration" class="editable">
+ <span >{{hydration}}</span>
+ <input value={{hydration}} />% hydration
+ </div>
+ <div id="innoculation">
+ <span >{{innoculation}}</span>
+ <input value={{innoculation}} />
+ % innoculation
+ </div>
+ <div class="timing">
+ Doubled in
+ <span class="doubling"> {{doubling}} </span> hrs
+ at
+ <span class="temp"> {{temp}} </span>
+ degrees F
+ </div>
+</script>
+
+<script type="text/template" id="note-li">
+ <div class="show-body">
+ <span class="time">{{time}}</span>
+ <button class='icon icononly remove danger button'></button>
+ <div class="body">{{body}}</div>
+ </div>
+ <div class="edit-body">
+ <textarea class="body-input" >{{body}}</textarea>
+ <input class="body-submit button" type="button" value = 'Save' />
+ <input class="body-cancel button" type="button" value = 'Cancel' />
+ </div>
+</script>
+
View
2 app/views/recipes/index.html.erb
@@ -2,7 +2,7 @@
<div id="notice"></div>
<div id="recipe_container">
<% @recipes.each do |r| %>
- <%= link_to r.title, r %></br>
+ <%= link_to r.title, edit_recipe_path(r) %></br>
<%end%>
</div>
View
148 app/views/recipes/show.html.erb
@@ -1,143 +1,27 @@
<div id="recipe_container" >
<div class="recipe">
- <div id="recipe-title">
- <span> <%= @recipe.title %> </span>
- <input class="hidden" value=<%= @recipe.title %> />
- </div>
+ <h1> <%= @recipe.title %> </h1></br>
+ <%= @recipe.photo ? @recipe.photo.html_safe : ''%>
<table>
<tbody id="part-list">
+ <% @recipe.parts.each do |p| %>
+ <tr class="part">
+ <td class='amount-col'> <span class="amount"><%=p.amount%> </span></td>
+ <td class='unit-col'> g </td>
+ <td class='name-col'> <%= p.ingredient.name %> </td>
+ <td class='percent-col'> <%= p.primary ? '' : p.percent.to_s+'%' %> </td>
+ </tr>
+ <% end %>
</tbody>
- <tfoot>
- <tr id="new-part">
- <td class="amount-col"> <input id="new-amount" placeholder="12" /> </td>
- <td class="unit-col">g</td>
- <td class="name-col">
- <input id="new-name" placeholder="salt" />
- <input id="new-name-id" type="hidden" />
- </td>
- <td class='percent-col'>
- <input id="new-percent" />
- </td>
- <td class="fixed-percent"> </td>
- <td class="button-col"> <button class='icon icononly add button'></button> </td>
- </tr>
- </tfoot>
</table>
<span class="stats"> </span>
</div>
<div id="notes_container">
- <div id="new-note" class="note">
- <textarea id="new-note-body" ></textarea></br>
- <input class="new-note button" type="button" value='New Note' />
- </div>
+ <% @recipe.notes.reverse.each do |n| %>
+ <div class="note">
+ <span class="time"> <%= time_ago_in_words(n.time) %> ago </span></br>
+ <span class="body"> <%= n.body %> </span>
+ </div>
+ <% end %>
</div>
</div>
-
-<script type="text/javascript">
- var Recipe;
- var ingredients = <%= @ingredients.to_json.html_safe %>;
- $(function() {
- // By default, Underscore uses ERB-style template delimiters, this change
- // makes it use mustache style.
- _.templateSettings = {
- interpolate : /\{\{([\s\S]+?)\}\}/g
- };
- Recipe = new App.Models.Recipe(<%= @recipe.to_json(:include => {:parts => {:include => {:ingredient => {:only => :name}}}} ).html_safe %>);
-
- $( "#new-name" ).autocomplete({
- minLength: 0,
- source: ingredients,
- focus: function( event, ui ) {
- $( "#new-name" ).val( ui.item.label );
- return false;
- },
- select: function( event, ui ) {
- $( "#new-name" ).val( ui.item.label );
- $( "#new-name-id" ).val( ui.item.value );
-
- return false;
- }
- })
- $.ui.autocomplete.prototype._renderItem = function( ul, item ) {
- return $( "<li></li>" )
- .data( "item.autocomplete", item )
- .append( "<a>" + item.label + "</a>" )
- .appendTo( ul );
- };
- });
-</script>
-
-<script type="text/template" id="primary-part-li">
- <td class='amount-col editable'>
- <span class="amount"> {{amount}} </span>
- <input class="edit-amount hidden" value={{amount}} />
- </td>
- <td class='unit-col'> g </td>
-
- <td class='name-col'>
- <span class="primary-name"> {{ingredient.name}} </span>
- </td>
- <td class='percent-col'> </td>
- <td class="fixed-percent"> </td>
- <td class='button-col'> </td>
-</script>
-
-<script type="text/template" id="part-li">
- <td class='amount-col editable'>
- <span class="amount"> {{amount}} </span>
- <input class="edit-amount hidden" value={{amount}} />
- </td>
-
- <td class='unit-col'> g </td>
-
- <td class='name-col editable'>
- <span class="name"> {{ingredient.name}} </span>
- <input class="edit-name hidden" value={{ingredient.name}} />
- <input class="edit-name-id" type="hidden" value={{ingredient_id}} />
- </td>
- <td class='percent-col editable'>
- <span class="percent">{{percent}}</span>
- <input class="edit-percent hidden" value={{percent}} />
- </td>
- <td class="fixed-percent">
- <input class="fixed-percent-input" type="checkbox" value={{fixed_percent}} />
- </td>
- <td class='button-col'>
- <button class='icon icononly remove danger button'></button>
- </td>
-</script>
-
-<script type="text/template" id="recipe-stats">
- <div id="hydration" class="editable">
- <span >{{hydration}}</span>
- <input value={{hydration}} />% hydration
- </div>
- <div id="innoculation">
- <span >{{innoculation}}</span>
- <input value={{innoculation}} />
- % innoculation
- </div>
- <div class="timing">
- Doubled in
- <span class="doubling"> {{doubling}} </span> hrs
- <input class="edit-doubling hidden" value={{doubling}} />
- at
- <span class="temp"> {{temp}} </span>
- <input class="edit-temp hidden" value={{temp}} />
- degrees F
- </div>
-</script>
-
-<script type="text/template" id="note-li">
- <div class="show-body">
- <span class="time">{{time}}</span>
- <button class='icon icononly remove danger button'></button>
- <div class="body">{{body}}</div>
- </div>
- <div class="edit-body hidden">
- <textarea class="body-input" >{{body}}</textarea>
- <input class="body-submit button" type="button" value = 'Save' />
- <input class="body-cancel button" type="button" value = 'Cancel' />
- </div>
-</script>
-

0 comments on commit a968ea8

Please sign in to comment.
Something went wrong with that request. Please try again.