From 422c77b131e627ec2ca69e675cf084176ef4c444 Mon Sep 17 00:00:00 2001 From: Dan Elbert Date: Sat, 30 Jan 2016 20:29:35 -0600 Subject: [PATCH] Added ingredient prep to recipe_ingredient; update to bulk editing --- app/assets/javascripts/recipe_editor.js | 95 ++++++++++++++----- app/assets/stylesheets/recipes.scss | 14 +++ app/controllers/recipes_controller.rb | 3 +- app/models/recipe_ingredient.rb | 18 +--- app/views/recipes/_form.html.erb | 4 +- .../editor/_bulk_ingredient_dialog.html.erb | 7 +- app/views/recipes/editor/_ingredient.html.erb | 38 +++++--- .../20160130231838_change_ingredients.rb | 9 ++ db/schema.rb | 10 +- 9 files changed, 137 insertions(+), 61 deletions(-) create mode 100644 db/migrate/20160130231838_change_ingredients.rb diff --git a/app/assets/javascripts/recipe_editor.js b/app/assets/javascripts/recipe_editor.js index 3780358..9db85b9 100644 --- a/app/assets/javascripts/recipe_editor.js +++ b/app/assets/javascripts/recipe_editor.js @@ -53,7 +53,6 @@ $editors.each(function(idx, elem) { var $editor = $(elem); var $ingredientId = $editor.find("input.ingredient_id"); - var $customDensity = $editor.find("input.custom_density"); var $group = $editor.find("div.typeahead-group"); $editor.find(".ingredient-typeahead").typeahead({}, @@ -66,7 +65,6 @@ }); if ($ingredientId.val().length) { - $customDensity.prop('disabled', true); $group.addClass("has-success"); } }); @@ -75,12 +73,10 @@ function ingredientItemPicked($typeahead, datum) { var $container = $typeahead.closest(".nested-fields"); var $ingredientId = $container.find("input.ingredient_id"); - var $customDensity = $container.find("input.custom_density"); var $group = $container.find("div.typeahead-group"); $ingredientId.val(datum.id); $typeahead.typeahead('val', datum.name); - $customDensity.val(datum.density).prop('disabled', true); $group.addClass("has-success"); } @@ -103,22 +99,41 @@ } } - function addIngredient(quantity, units, name, ingredient_id) { + function addIngredient(item) { $("#ingredient-list").one("cocoon:before-insert", function(e, $container) { var $ingredientId = $container.find("input.ingredient_id"); - var $name = $container.find("input.custom_name"); + var $name = $container.find("input.ingredient-typeahead.tt-input"); var $quantity = $container.find("input.quantity"); var $units = $container.find("input.units"); + var $preparation = $container.find("input.preparation"); - $ingredientId.typeahead("val", name); - $name.val(name); - $units.val(units); - $quantity.val(quantity); + $name.typeahead("val", item.name); + $ingredientId.val(item.ingredient_id); + $units.val(item.units); + $quantity.val(item.quantity); + $preparation.val(item.preparation); }); $("#addIngredientButton").trigger("click"); } + function getIngredients() { + var data = []; + $("#ingredient-list .ingredient-editor").each(function() { + var $container = $(this); + + var $ingredientId = $container.find("input.ingredient_id"); + var $name = $container.find("input.ingredient-typeahead.tt-input"); + var $quantity = $container.find("input.quantity"); + var $units = $container.find("input.units"); + var $preparation = $container.find("input.preparation"); + + data.push({ingredient_id: $ingredientId.val(), name: $name.typeahead("val"), quantity: $quantity.val(), units: $units.val(), preparation: $preparation.val()}); + }); + + return data; + } + function addStep(step) { $("#step-list").one("cocoon:before-insert", function(e, $container) { var $step = $container.find("textarea.step"); @@ -226,14 +241,7 @@ var $ingredientBulkList = $("#ingredient_bulk_parsed_list"); autosize($ingredientBulkInput); - $bulkIngredientsModal - .on('show.bs.modal', function (event) { - $ingredientBulkInput.val(''); - $ingredientBulkList.empty(); - autosize.update($ingredientBulkInput); - }); - - $ingredientBulkInput.on('keyup', function() { + var parseBulkIngredients = function() { var data = $ingredientBulkInput.val(); $ingredientBulkList.empty(); @@ -242,7 +250,7 @@ var lines = data.replace("\r", "").split("\n"); - var regex = /^(?:([\d\/.]+(?:\s+[\d\/]+)?)\s+)?(?:([\w-]+)(?:\s+of)?\s+)?(\w[\w ,\-\(\)\/'"]*)$/i; + var regex = /^(?:([\d\/.]+(?:\s+[\d\/]+)?)\s+)?(?:([\w-]+)(?:\s+of)?\s+)?([^,]*)(?:,\s*(.*))?$/i; var magicFunc = function(str) { if (str == "-") { @@ -256,10 +264,23 @@ var line = lines[x].trim(); if (line.length == 0) { continue; } + var barIndex = line.lastIndexOf("|"); + var afterBar = null; + + if (barIndex >= 0) { + afterBar = line.slice(barIndex + 1); + line = line.slice(0, barIndex); + } + var match = line.match(regex); if (match) { - parsed.push({quantity: magicFunc(match[1]), units: magicFunc(match[2]), name: magicFunc(match[3])}); + item = {quantity: magicFunc(match[1]), units: magicFunc(match[2]), name: magicFunc(match[3]), preparation: magicFunc(match[4])}; + if (afterBar) { + item.name = item.name + ", " + item.preparation; + item.preparation = afterBar; + } + parsed.push(item); } else { parsed.push(null); } @@ -275,14 +296,44 @@ .append($("").addClass("quantity").text(item.quantity)) .append($("").addClass("units").text(item.units)) .append($("").addClass("name").text(item.name)) + .append($("").addClass("preparation").text(item.preparation)) ); } else { $ingredientBulkList.append( $("") - .append($("").attr("colspan", "3").text("")) + .append($("").attr("colspan", "4").text("")) ); } } + }; + + $bulkIngredientsModal + .on('show.bs.modal', function (event) { + var data = getIngredients(); + var x; + var text = []; + + for (x = 0; x < data.length; x++) { + var item = data[x]; + + text.push( + item.quantity + " " + + (item.units || "-") + " " + + item.name + + (item.preparation ? (", " + item.preparation) : "") + ); + } + + $ingredientBulkInput.val(text.join("\n")); + + setTimeout(function() { + parseBulkIngredients(); + autosize.update($ingredientBulkInput); + }, 250); + }); + + $ingredientBulkInput.on('keyup', function() { + parseBulkIngredients(); }); $("#bulkIngredientAddSubmit").on("click", function() { @@ -293,7 +344,7 @@ for (x = 0; x < parsed.length; x++) { var item = parsed[x]; if (item) { - addIngredient(item.quantity, item.units, item.name, item.ingredient_id) + addIngredient(item) } } } diff --git a/app/assets/stylesheets/recipes.scss b/app/assets/stylesheets/recipes.scss index c7fa520..e958fe2 100644 --- a/app/assets/stylesheets/recipes.scss +++ b/app/assets/stylesheets/recipes.scss @@ -27,6 +27,7 @@ div.ingredient-editor { @include editor; + } div.step-editor { @@ -50,6 +51,19 @@ div#ingredient-list, div#step-list { padding-bottom: 15px; } +div#ingredient-list { + + @media (min-width: $screen-md-min) { + .ingredient-editor .control-label { + display: none; + } + + .ingredient-editor:first-child .control-label { + display: inline-block; + } + } +} + div.recipe-view { .source { diff --git a/app/controllers/recipes_controller.rb b/app/controllers/recipes_controller.rb index ccf7c26..1378e5a 100644 --- a/app/controllers/recipes_controller.rb +++ b/app/controllers/recipes_controller.rb @@ -24,6 +24,7 @@ class RecipesController < ApplicationController # GET /recipes/new def new @recipe = Recipe.new + @recipe.recipe_ingredients << RecipeIngredient.new end # GET /recipes/1/edit @@ -75,6 +76,6 @@ class RecipesController < ApplicationController # Never trust parameters from the scary internet, only allow the white list through. def recipe_params - params.require(:recipe).permit(:name, :description, :source, :yields, :total_time, :active_time, recipe_ingredients_attributes: [:custom_name, :custom_density, :ingredient_id, :quantity, :units, :sort_order, :id, :_destroy], recipe_steps_attributes: [:step, :sort_order, :id, :_destroy]) + params.require(:recipe).permit(:name, :description, :source, :yields, :total_time, :active_time, recipe_ingredients_attributes: [:name, :ingredient_id, :quantity, :units, :preparation, :sort_order, :id, :_destroy], recipe_steps_attributes: [:step, :sort_order, :id, :_destroy]) end end diff --git a/app/models/recipe_ingredient.rb b/app/models/recipe_ingredient.rb index b24ef2e..febd103 100644 --- a/app/models/recipe_ingredient.rb +++ b/app/models/recipe_ingredient.rb @@ -6,7 +6,7 @@ class RecipeIngredient < ActiveRecord::Base validates :sort_order, presence: true validates :custom_density, density: true, allow_blank: true - def custom_name + def name if self.ingredient_id.present? self.ingredient.name else @@ -14,23 +14,15 @@ class RecipeIngredient < ActiveRecord::Base end end - def custom_density - if self.ingredient_id.present? - self.ingredient.density - else - super - end - end - def display_name if quantity.present? && units.present? - "#{quantity} #{units} of #{custom_name}" + "#{quantity} #{units} #{name}" elsif quantity.present? - "#{quantity} #{custom_name}" + "#{quantity} #{name}" elsif units.present? - "#{units} #{custom_name}" + "#{units} #{name}" else - custom_name + name end end diff --git a/app/views/recipes/_form.html.erb b/app/views/recipes/_form.html.erb index a528b23..7b24e02 100644 --- a/app/views/recipes/_form.html.erb +++ b/app/views/recipes/_form.html.erb @@ -47,7 +47,7 @@

Ingredients

- +
<%= f.fields_for :recipe_ingredients do |ri_form| %> <%= render partial: 'recipes/editor/ingredient', locals: { f: ri_form } %> @@ -58,7 +58,7 @@

Steps

- +
<%= f.fields_for :recipe_steps do |rs_form| %> <%= render partial: 'recipes/editor/step', locals: { f: rs_form } %> diff --git a/app/views/recipes/editor/_bulk_ingredient_dialog.html.erb b/app/views/recipes/editor/_bulk_ingredient_dialog.html.erb index 53652b9..c8b9da4 100644 --- a/app/views/recipes/editor/_bulk_ingredient_dialog.html.erb +++ b/app/views/recipes/editor/_bulk_ingredient_dialog.html.erb @@ -11,19 +11,20 @@
-
+
- +
- + + diff --git a/app/views/recipes/editor/_ingredient.html.erb b/app/views/recipes/editor/_ingredient.html.erb index 8e795f4..ae4ab29 100644 --- a/app/views/recipes/editor/_ingredient.html.erb +++ b/app/views/recipes/editor/_ingredient.html.erb @@ -6,20 +6,6 @@
-
-
- <%= f.label :custom_name, "Name", class: "control-label" %> -
- <%= f.text_field :custom_name, class: 'form-control ingredient-typeahead custom_name' %> - - - -
-
-
-
<%= f.label :quantity, class: "control-label" %> @@ -30,9 +16,31 @@
<%= f.label :units, class: "control-label" %> - <%= f.text_field :units, class: 'form-control units' %> +
+ <%= f.text_field :units, class: 'form-control units' %> + + + +
+ +
+
+ <%= f.label :name, class: "control-label" %> + <%= f.text_field :name, class: 'form-control ingredient-typeahead custom' %> +
+
+ +
+
+ <%= f.label :preparation, class: "control-label" %> + <%= f.text_field :preparation, class: 'form-control preparation' %> +
+
+
diff --git a/db/migrate/20160130231838_change_ingredients.rb b/db/migrate/20160130231838_change_ingredients.rb new file mode 100644 index 0000000..00aa4b4 --- /dev/null +++ b/db/migrate/20160130231838_change_ingredients.rb @@ -0,0 +1,9 @@ +class ChangeIngredients < ActiveRecord::Migration + def change + change_table :recipe_ingredients do |t| + t.remove :custom_density + t.rename :custom_name, :name + t.text :preparation + end + end +end diff --git a/db/schema.rb b/db/schema.rb index f7a2fcb..d93b8e2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160124231837) do +ActiveRecord::Schema.define(version: 20160130231838) do create_table "ingredients", force: :cascade do |t| t.string "name" @@ -33,13 +33,13 @@ ActiveRecord::Schema.define(version: 20160124231837) do create_table "recipe_ingredients", force: :cascade do |t| t.integer "ingredient_id" t.integer "recipe_id" - t.string "custom_name" - t.string "custom_density" + t.string "name" t.integer "sort_order" t.string "quantity" t.string "units" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.text "preparation" end add_index "recipe_ingredients", ["recipe_id"], name: "index_recipe_ingredients_on_recipe_id"
Quantity# Unit NamePrep