Recipe Editor
This commit is contained in:
parent
3b4134f684
commit
0388d428a6
@ -1,25 +1,72 @@
|
|||||||
(function($) {
|
(function($) {
|
||||||
|
|
||||||
function reorder($container) {
|
function reorder($container) {
|
||||||
|
console.log($container);
|
||||||
$container.find("div.nested-fields").each(function(idx, editor) {
|
$container.find("div.nested-fields").each(function(idx, editor) {
|
||||||
var $editor = $(editor);
|
var $editor = $(editor);
|
||||||
$editor.find('input.sort-order').val(idx + 1).trigger("changed");
|
$editor.find('input.sort_order').val(idx + 1).trigger("changed");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeIngredientEditor($container, ingredientSearchEngine) {
|
function initializeIngredientEditor($container, ingredientSearchEngine) {
|
||||||
$container.find(".ingredient-typeahead").typeahead({
|
// $container is either an element that contains many editors, or a single editor.
|
||||||
|
var $editors = $container.find(".ingredient-typeahead").closest(".nested-fields");
|
||||||
|
|
||||||
},
|
$editors.each(function(idx, elem) {
|
||||||
{
|
var $editor = $(elem);
|
||||||
name: 'ingredients',
|
var $ingredientId = $editor.find("input.ingredient_id");
|
||||||
source: ingredientSearchEngine,
|
var $customDensity = $editor.find("input.custom_density");
|
||||||
display: function(datum) {
|
var $group = $editor.find("div.typeahead-group");
|
||||||
return datum.name;
|
|
||||||
|
$editor.find(".ingredient-typeahead").typeahead({},
|
||||||
|
{
|
||||||
|
name: 'ingredients',
|
||||||
|
source: ingredientSearchEngine,
|
||||||
|
display: function(datum) {
|
||||||
|
return datum.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($ingredientId.val().length) {
|
||||||
|
$customDensity.prop('disabled', true);
|
||||||
|
$group.addClass("has-success");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
function ingredientNameChange($typeahead, ingredientSearchEngine) {
|
||||||
|
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");
|
||||||
|
|
||||||
|
var id = $ingredientId.val();
|
||||||
|
var value = $typeahead.typeahead('val');
|
||||||
|
|
||||||
|
if (id && id.length) {
|
||||||
|
var found = ingredientSearchEngine.get([id]);
|
||||||
|
if (found && found[0] && found[0].name != value) {
|
||||||
|
// User has chosen something custom
|
||||||
|
$ingredientId.val('');
|
||||||
|
$customDensity.val('').prop('disabled', false);
|
||||||
|
|
||||||
|
$group.removeClass("has-success");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(document).on("ready page:load", function() {
|
$(document).on("ready page:load", function() {
|
||||||
|
|
||||||
var ingredientSearchEngine = new Bloodhound({
|
var ingredientSearchEngine = new Bloodhound({
|
||||||
@ -66,11 +113,23 @@
|
|||||||
|
|
||||||
$ingredientList
|
$ingredientList
|
||||||
.on("cocoon:after-insert", function(e, item) {
|
.on("cocoon:after-insert", function(e, item) {
|
||||||
reorder($(this));
|
reorder($ingredientList);
|
||||||
initializeIngredientEditor(item, ingredientSearchEngine);
|
initializeIngredientEditor(item, ingredientSearchEngine);
|
||||||
})
|
})
|
||||||
.on("cocoon:after-remove", function(e, item) {
|
.on("cocoon:after-remove", function(e, item) {
|
||||||
reorder($(this));
|
reorder($ingredientList);
|
||||||
|
})
|
||||||
|
.on("typeahead:change", function(evt, value) {
|
||||||
|
console.log("changed");
|
||||||
|
ingredientNameChange($(evt.target), ingredientSearchEngine);
|
||||||
|
})
|
||||||
|
.on("typeahead:select", function(evt, value) {
|
||||||
|
console.log("selected");
|
||||||
|
ingredientItemPicked($(evt.target), value);
|
||||||
|
})
|
||||||
|
.on("typeahead:autocomplete", function(evt, value) {
|
||||||
|
console.log("autocomplete");
|
||||||
|
ingredientItemPicked($(evt.target), value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
||||||
|
|
||||||
@mixin editor {
|
@mixin editor {
|
||||||
@extend .panel-body;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.ingredient-editor {
|
div.ingredient-editor {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
class IngredientsController < ApplicationController
|
class IngredientsController < ApplicationController
|
||||||
before_action :set_ingredient, only: [:show, :edit, :update, :destroy]
|
before_action :set_ingredient, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
# GET /ingredients
|
# GET /ingredients
|
||||||
# GET /ingredients.json
|
# GET /ingredients.json
|
||||||
@ -7,11 +7,6 @@ class IngredientsController < ApplicationController
|
|||||||
@ingredients = Ingredient.all.order(:name)
|
@ingredients = Ingredient.all.order(:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /ingredients/1
|
|
||||||
# GET /ingredients/1.json
|
|
||||||
def show
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /ingredients/new
|
# GET /ingredients/new
|
||||||
def new
|
def new
|
||||||
@ingredient = Ingredient.new
|
@ingredient = Ingredient.new
|
||||||
|
@ -6,4 +6,20 @@ class RecipeIngredient < ActiveRecord::Base
|
|||||||
validates :sort_order, presence: true
|
validates :sort_order, presence: true
|
||||||
validates :custom_density, density: true, allow_blank: true
|
validates :custom_density, density: true, allow_blank: true
|
||||||
|
|
||||||
|
def custom_name
|
||||||
|
if self.ingredient_id.present?
|
||||||
|
self.ingredient.name
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def custom_density
|
||||||
|
if self.ingredient_id.present?
|
||||||
|
self.ingredient.density
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
<%= render 'form' %>
|
<%= render 'form' %>
|
||||||
|
|
||||||
<%= link_to 'Show', @ingredient, class: 'btn btn-primary' %> |
|
|
||||||
<%= link_to 'Back', ingredients_path, class: 'btn btn-primary' %>
|
<%= link_to 'Back', ingredients_path, class: 'btn btn-primary' %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<% @ingredients.each do |ingredient| %>
|
<% @ingredients.each do |ingredient| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= ingredient.name %></td>
|
<td><%= link_to ingredient.name, edit_ingredient_path(ingredient) %></td>
|
||||||
<td><%= ingredient.density %></td>
|
<td><%= ingredient.density %></td>
|
||||||
<td><%= link_to 'Show', ingredient %></td>
|
|
||||||
<td><%= link_to 'Edit', edit_ingredient_path(ingredient) %></td>
|
|
||||||
<td><%= link_to 'Destroy', ingredient, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
<td><%= link_to 'Destroy', ingredient, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-12">
|
|
||||||
|
|
||||||
<h3><%= @ingredient.name %></h3>
|
|
||||||
|
|
||||||
<p><%= @ingredient.notes %></p>
|
|
||||||
|
|
||||||
<%= link_to 'Edit', edit_ingredient_path(@ingredient), class: 'btn btn-default' %>
|
|
||||||
<%= link_to 'Back', ingredients_path, class: 'btn btn-default' %>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1 +0,0 @@
|
|||||||
json.extract! @ingredient, :id, :created_at, :updated_at
|
|
@ -1,12 +1,12 @@
|
|||||||
<div class="panel panel-default">
|
<div class="panel panel-default nested-fields ingredient-editor">
|
||||||
<div class="nested-fields ingredient-editor">
|
<div class="panel-body">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-10">
|
<div class="col-xs-10">
|
||||||
|
|
||||||
<div class="form-group form-group-sm">
|
<div class="form-group form-group-sm typeahead-group">
|
||||||
<%= f.label :custom_name, "Name" %>
|
<%= f.label :custom_name, "Name" %>
|
||||||
<%= f.text_field :custom_name, class: 'form-control ingredient-typeahead' %>
|
<%= f.text_field :custom_name, class: 'form-control ingredient-typeahead custom_name' %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<div class="col-xs-4">
|
<div class="col-xs-4">
|
||||||
<div class="form-group form-group-sm">
|
<div class="form-group form-group-sm">
|
||||||
<%= f.label :custom_density, "Density" %>
|
<%= f.label :custom_density, "Density" %>
|
||||||
<%= f.text_field :custom_density, class: 'form-control' %>
|
<%= f.text_field :custom_density, class: 'form-control custom_density' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -40,6 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= f.hidden_field :sort_order, class: 'sort-order' %>
|
<%= f.hidden_field :ingredient_id, class: 'ingredient_id' %>
|
||||||
|
<%= f.hidden_field :sort_order, class: 'sort_order' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= f.hidden_field :sort_order, class: 'sort-order' %>
|
<%= f.hidden_field :sort_order, class: 'sort_order' %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,7 +1,8 @@
|
|||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
|
|
||||||
resources :recipes
|
resources :recipes
|
||||||
resources :ingredients do
|
|
||||||
|
resources :ingredients, except: [:show] do
|
||||||
collection do
|
collection do
|
||||||
constraints format: 'json' do
|
constraints format: 'json' do
|
||||||
get :search
|
get :search
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
puts "Seeding..."
|
puts "Seeding..."
|
||||||
|
|
||||||
Ingredient.create!([
|
Ingredient.create!([
|
||||||
|
{name: 'Water', density: '1 g/ml'},
|
||||||
{name: 'Butter, Salted', density: '226 gram/cup'},
|
{name: 'Butter, Salted', density: '226 gram/cup'},
|
||||||
{name: 'Butter, Unsalted', density: '226 gram/cup'},
|
{name: 'Butter, Unsalted', density: '226 gram/cup'},
|
||||||
{name: 'Flour, Bleached All Purpose', density: '130 gram/cup'},
|
{name: 'Flour, Bleached All Purpose', density: '130 gram/cup'},
|
||||||
|
Loading…
Reference in New Issue
Block a user