diff --git a/app/assets/javascripts/checkable.js b/app/assets/javascripts/checkable.js new file mode 100644 index 0000000..42f5893 --- /dev/null +++ b/app/assets/javascripts/checkable.js @@ -0,0 +1,36 @@ +(function($) { + + var pluginName = "checkable"; + + var defaultOptions = { + childrenSelector: "li", + selectedClass: "checked" + }; + + var methods = { + initialize: function (opts, sources) { + + return this.each(function() { + var options = $.extend({}, defaultOptions, opts); + $(this).on("click", options.childrenSelector, function(evt) { + $(evt.currentTarget).toggleClass(options.selectedClass); + }); + }); + } + }; + + var privateMethods = { + + }; + + $.fn[pluginName] = function (method) { + if (methods[method]) { + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === 'object' || ! method) { + return methods.initialize.apply(this, arguments); + } else { + $.error('Method ' + method + ' does not exist on jQuery.' + pluginName); + } + }; + +})(jQuery); \ No newline at end of file diff --git a/app/assets/javascripts/recipe_editor.js b/app/assets/javascripts/recipe_editor.js new file mode 100644 index 0000000..3780358 --- /dev/null +++ b/app/assets/javascripts/recipe_editor.js @@ -0,0 +1,375 @@ +(function($) { + + var ingredientSearchEngine = new Bloodhound({ + initialize: false, + datumTokenizer: function(datum) { + return Bloodhound.tokenizers.whitespace(datum.name); + }, + queryTokenizer: Bloodhound.tokenizers.whitespace, + identify: function(datum) { return datum.id; }, + sorter: function(a, b) { + if (a.name < b.name) { + return -1; + } else if (b.name < a.name) { + return 1; + } else { + return 0; + } + }, + prefetch: { + url: '/ingredients/prefetch.json', + cache: false + }, + remote: { + url: '/ingredients/search.json?query=%QUERY', + wildcard: '%QUERY' + } + }); + + function reorder($container) { + $container.find("div.nested-fields").each(function(idx, editor) { + var $editor = $(editor); + $editor.find('input.sort_order').val(idx + 1).trigger("changed"); + }) + } + + function initializeStepEditor($container) { + // $container is either an element that contains many editors, or a single editor. + var $editors = $container.find("textarea.step").closest(".step-editor"); + + $editors.each(function(idx, elem) { + var $editor = $(elem); + var $step = $editor.find("textarea.step"); + autosize($step); + + setTimeout(function() { autosize.update($step); }, 250); + }); + } + + function initializeIngredientEditor($container, ingredientSearchEngine) { + // $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); + 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({}, + { + 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 $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(''); + + $group.removeClass("has-success"); + } + } + } + + function addIngredient(quantity, units, name, ingredient_id) { + $("#ingredient-list").one("cocoon:before-insert", function(e, $container) { + var $ingredientId = $container.find("input.ingredient_id"); + var $name = $container.find("input.custom_name"); + var $quantity = $container.find("input.quantity"); + var $units = $container.find("input.units"); + + $ingredientId.typeahead("val", name); + $name.val(name); + $units.val(units); + $quantity.val(quantity); + }); + + $("#addIngredientButton").trigger("click"); + } + + function addStep(step) { + $("#step-list").one("cocoon:before-insert", function(e, $container) { + var $step = $container.find("textarea.step"); + $step.val(step); + }); + + $("#addStepButton").trigger("click"); + } + + $(document).on("ready page:load", function() { + + var $ingredientList = $("#ingredient-list"); + var $stepList = $("#step-list"); + + if ($ingredientList.length) { + ingredientSearchEngine.initialize(false); + } + + initializeStepEditor($stepList); + + $stepList + .on("cocoon:after-insert", function(e, item) { + reorder($(this)); + initializeStepEditor(item); + }) + .on("cocoon:after-remove", function(e, item) { + reorder($(this)); + }) + .on('changed', 'input.sort_order', function() { + var $this = $(this); + var $span = $this.closest(".nested-fields").find(".sort-order-display"); + $span.html($this.val()); + }); + + + initializeIngredientEditor($ingredientList, ingredientSearchEngine); + + $ingredientList + .on("cocoon:after-insert", function(e, item) { + reorder($ingredientList); + initializeIngredientEditor(item, ingredientSearchEngine); + }) + .on("cocoon:after-remove", function(e, item) { + reorder($ingredientList); + }) + .on("typeahead:change", function(evt, value) { + ingredientNameChange($(evt.target), ingredientSearchEngine); + }) + .on("typeahead:select", function(evt, value) { + ingredientItemPicked($(evt.target), value); + }) + .on("typeahead:autocomplete", function(evt, value) { + ingredientItemPicked($(evt.target), value); + }) + .on("click", "button.ingredient_convert_btn", function(evt) { + + }); + + $('#convert_modal') + .on('show.bs.modal', function (event) { + var $button = $(event.relatedTarget); + var $modal = $(this); + + var $editor = $button.closest(".ingredient-editor"); + + $modal.data('ingredient-editor', $editor); + + var $quantity = $editor.find("input.quantity"); + var $units = $editor.find("input.units"); + var $ingredientId = $editor.find("input.ingredient_id"); + + var $modalQuantity = $modal.find("input.quantity"); + var $modalUnits = $modal.find("input.units"); + var $modalIngredientId = $modal.find("input.ingredient_id"); + + $modalQuantity.val($quantity.val()); + $modalUnits.val($units.val()); + $modalIngredientId.val($ingredientId.val()); + }) + .on("ajax:success", "form", function(evt, data, status, xhr) { + var $modal = $("#convert_modal"); + var $editor = $modal.data('ingredient-editor'); + + if (data.success) { + var $quantity = $editor.find("input.quantity"); + var $units = $editor.find("input.units"); + + var $modalOutUnits = $modal.find("input.output_units"); + + $quantity.val(data.output_quantity); + if ($modalOutUnits.val().length) { + $units.val($modalOutUnits.val()); + } + + $modal.modal('hide'); + } else { + + } + + $("#modal_form_container").replaceWith($(data.form_html)); + }); + + var $bulkIngredientsModal = $("#bulk_ingredients_modal"); + var $ingredientBulkInput = $("#ingredient_bulk_input"); + 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 data = $ingredientBulkInput.val(); + $ingredientBulkList.empty(); + + var parsed = []; + var x; + + var lines = data.replace("\r", "").split("\n"); + + var regex = /^(?:([\d\/.]+(?:\s+[\d\/]+)?)\s+)?(?:([\w-]+)(?:\s+of)?\s+)?(\w[\w ,\-\(\)\/'"]*)$/i; + + var magicFunc = function(str) { + if (str == "-") { + return ""; + } else { + return str; + } + }; + + for (x = 0; x < lines.length; x++) { + var line = lines[x].trim(); + if (line.length == 0) { continue; } + + var match = line.match(regex); + + if (match) { + parsed.push({quantity: magicFunc(match[1]), units: magicFunc(match[2]), name: magicFunc(match[3])}); + } else { + parsed.push(null); + } + } + + $bulkIngredientsModal.data("bulkData", parsed); + + for (x = 0; x < parsed.length; x++) { + var item = parsed[x]; + if (item != null) { + $ingredientBulkList.append( + $("") + .append($("").addClass("quantity").text(item.quantity)) + .append($("").addClass("units").text(item.units)) + .append($("").addClass("name").text(item.name)) + ); + } else { + $ingredientBulkList.append( + $("") + .append($("").attr("colspan", "3").text("")) + ); + } + } + }); + + $("#bulkIngredientAddSubmit").on("click", function() { + var parsed = $bulkIngredientsModal.data("bulkData"); + var x; + + if (parsed && parsed.length) { + for (x = 0; x < parsed.length; x++) { + var item = parsed[x]; + if (item) { + addIngredient(item.quantity, item.units, item.name, item.ingredient_id) + } + } + } + + $bulkIngredientsModal.modal('hide') + }); + + + // =========================================== + // =========================================== + + + var $bulkStepsModal = $("#bulk_steps_modal"); + var $stepBulkInput = $("#step_bulk_input"); + var $stepBulkList = $("#step_bulk_parsed_list"); + autosize($stepBulkInput); + + $bulkStepsModal + .on('show.bs.modal', function (event) { + $stepBulkInput.val(''); + $stepBulkList.empty(); + autosize.update($stepBulkInput); + }); + + $stepBulkInput.on('keyup', function() { + var data = $stepBulkInput.val(); + $stepBulkList.empty(); + + var parsed = []; + var x; + + var lines = data.replace("\r", "").split("\n\n"); + + for (x = 0; x < lines.length; x++) { + var line = lines[x].trim().replace(/^\d+\./, "").trim(); + if (line.length == 0) { continue; } + + parsed.push(line); + } + + $bulkStepsModal.data("bulkData", parsed); + + for (x = 0; x < parsed.length; x++) { + var item = parsed[x]; + if (item != null) { + $stepBulkList.append( + $("") + .append($("").addClass("step").text(x + 1)) + .append($("").addClass("direction").text(item)) + ); + } else { + $stepBulkList.append( + $("") + .append($("").attr("colspan", "2").text("")) + ); + } + } + }); + + $("#bulkStepAddSubmit").on("click", function() { + var parsed = $bulkStepsModal.data("bulkData"); + var x; + + if (parsed && parsed.length) { + for (x = 0; x < parsed.length; x++) { + var item = parsed[x]; + if (item) { + addStep(item); + } + } + } + + $bulkStepsModal.modal('hide') + }); + + }); + + +})(jQuery); diff --git a/app/assets/javascripts/recipes.js b/app/assets/javascripts/recipes.js index 99394d9..6a6c937 100644 --- a/app/assets/javascripts/recipes.js +++ b/app/assets/javascripts/recipes.js @@ -1,375 +1,8 @@ (function($) { - var ingredientSearchEngine = new Bloodhound({ - initialize: false, - datumTokenizer: function(datum) { - return Bloodhound.tokenizers.whitespace(datum.name); - }, - queryTokenizer: Bloodhound.tokenizers.whitespace, - identify: function(datum) { return datum.id; }, - sorter: function(a, b) { - if (a.name < b.name) { - return -1; - } else if (b.name < a.name) { - return 1; - } else { - return 0; - } - }, - prefetch: { - url: '/ingredients/prefetch.json', - cache: false - }, - remote: { - url: '/ingredients/search.json?query=%QUERY', - wildcard: '%QUERY' - } - }); - - function reorder($container) { - $container.find("div.nested-fields").each(function(idx, editor) { - var $editor = $(editor); - $editor.find('input.sort_order').val(idx + 1).trigger("changed"); - }) - } - - function initializeStepEditor($container) { - // $container is either an element that contains many editors, or a single editor. - var $editors = $container.find("textarea.step").closest(".step-editor"); - - $editors.each(function(idx, elem) { - var $editor = $(elem); - var $step = $editor.find("textarea.step"); - autosize($step); - - setTimeout(function() { autosize.update($step); }, 250); - }); - } - - function initializeIngredientEditor($container, ingredientSearchEngine) { - // $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); - 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({}, - { - 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 $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(''); - - $group.removeClass("has-success"); - } - } - } - - function addIngredient(quantity, units, name, ingredient_id) { - $("#ingredient-list").one("cocoon:before-insert", function(e, $container) { - var $ingredientId = $container.find("input.ingredient_id"); - var $name = $container.find("input.custom_name"); - var $quantity = $container.find("input.quantity"); - var $units = $container.find("input.units"); - - $ingredientId.typeahead("val", name); - $name.val(name); - $units.val(units); - $quantity.val(quantity); - }); - - $("#addIngredientButton").trigger("click"); - } - - function addStep(step) { - $("#step-list").one("cocoon:before-insert", function(e, $container) { - var $step = $container.find("textarea.step"); - $step.val(step); - }); - - $("#addStepButton").trigger("click"); - } - $(document).on("ready page:load", function() { - - var $ingredientList = $("#ingredient-list"); - var $stepList = $("#step-list"); - - if ($ingredientList.length) { - ingredientSearchEngine.initialize(false); - } - - initializeStepEditor($stepList); - - $stepList - .on("cocoon:after-insert", function(e, item) { - reorder($(this)); - initializeStepEditor(item); - }) - .on("cocoon:after-remove", function(e, item) { - reorder($(this)); - }) - .on('changed', 'input.sort_order', function() { - var $this = $(this); - var $span = $this.closest(".nested-fields").find(".sort-order-display"); - $span.html($this.val()); - }); - - - initializeIngredientEditor($ingredientList, ingredientSearchEngine); - - $ingredientList - .on("cocoon:after-insert", function(e, item) { - reorder($ingredientList); - initializeIngredientEditor(item, ingredientSearchEngine); - }) - .on("cocoon:after-remove", function(e, item) { - reorder($ingredientList); - }) - .on("typeahead:change", function(evt, value) { - ingredientNameChange($(evt.target), ingredientSearchEngine); - }) - .on("typeahead:select", function(evt, value) { - ingredientItemPicked($(evt.target), value); - }) - .on("typeahead:autocomplete", function(evt, value) { - ingredientItemPicked($(evt.target), value); - }) - .on("click", "button.ingredient_convert_btn", function(evt) { - - }); - - $('#convert_modal') - .on('show.bs.modal', function (event) { - var $button = $(event.relatedTarget); - var $modal = $(this); - - var $editor = $button.closest(".ingredient-editor"); - - $modal.data('ingredient-editor', $editor); - - var $quantity = $editor.find("input.quantity"); - var $units = $editor.find("input.units"); - var $ingredientId = $editor.find("input.ingredient_id"); - - var $modalQuantity = $modal.find("input.quantity"); - var $modalUnits = $modal.find("input.units"); - var $modalIngredientId = $modal.find("input.ingredient_id"); - - $modalQuantity.val($quantity.val()); - $modalUnits.val($units.val()); - $modalIngredientId.val($ingredientId.val()); - }) - .on("ajax:success", "form", function(evt, data, status, xhr) { - var $modal = $("#convert_modal"); - var $editor = $modal.data('ingredient-editor'); - - if (data.success) { - var $quantity = $editor.find("input.quantity"); - var $units = $editor.find("input.units"); - - var $modalOutUnits = $modal.find("input.output_units"); - - $quantity.val(data.output_quantity); - if ($modalOutUnits.val().length) { - $units.val($modalOutUnits.val()); - } - - $modal.modal('hide'); - } else { - - } - - $("#modal_form_container").replaceWith($(data.form_html)); - }); - - var $bulkIngredientsModal = $("#bulk_ingredients_modal"); - var $ingredientBulkInput = $("#ingredient_bulk_input"); - 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 data = $ingredientBulkInput.val(); - $ingredientBulkList.empty(); - - var parsed = []; - var x; - - var lines = data.replace("\r", "").split("\n"); - - var regex = /^(?:([\d\/.]+(?:\s+[\d\/]+)?)\s+)?(?:([\w-]+)(?:\s+of)?\s+)?(\w[\w ,\-\(\)\/'"]*)$/i; - - var magicFunc = function(str) { - if (str == "-") { - return ""; - } else { - return str; - } - }; - - for (x = 0; x < lines.length; x++) { - var line = lines[x].trim(); - if (line.length == 0) { continue; } - - var match = line.match(regex); - - if (match) { - parsed.push({quantity: magicFunc(match[1]), units: magicFunc(match[2]), name: magicFunc(match[3])}); - } else { - parsed.push(null); - } - } - - $bulkIngredientsModal.data("bulkData", parsed); - - for (x = 0; x < parsed.length; x++) { - var item = parsed[x]; - if (item != null) { - $ingredientBulkList.append( - $("") - .append($("").addClass("quantity").text(item.quantity)) - .append($("").addClass("units").text(item.units)) - .append($("").addClass("name").text(item.name)) - ); - } else { - $ingredientBulkList.append( - $("") - .append($("").attr("colspan", "3").text("")) - ); - } - } - }); - - $("#bulkIngredientAddSubmit").on("click", function() { - var parsed = $bulkIngredientsModal.data("bulkData"); - var x; - - if (parsed && parsed.length) { - for (x = 0; x < parsed.length; x++) { - var item = parsed[x]; - if (item) { - addIngredient(item.quantity, item.units, item.name, item.ingredient_id) - } - } - } - - $bulkIngredientsModal.modal('hide') - }); - - - // =========================================== - // =========================================== - - - var $bulkStepsModal = $("#bulk_steps_modal"); - var $stepBulkInput = $("#step_bulk_input"); - var $stepBulkList = $("#step_bulk_parsed_list"); - autosize($stepBulkInput); - - $bulkStepsModal - .on('show.bs.modal', function (event) { - $stepBulkInput.val(''); - $stepBulkList.empty(); - autosize.update($stepBulkInput); - }); - - $stepBulkInput.on('keyup', function() { - var data = $stepBulkInput.val(); - $stepBulkList.empty(); - - var parsed = []; - var x; - - var lines = data.replace("\r", "").split("\n\n"); - - for (x = 0; x < lines.length; x++) { - var line = lines[x].trim().replace(/^\d+\./, "").trim(); - if (line.length == 0) { continue; } - - parsed.push(line); - } - - $bulkStepsModal.data("bulkData", parsed); - - for (x = 0; x < parsed.length; x++) { - var item = parsed[x]; - if (item != null) { - $stepBulkList.append( - $("") - .append($("").addClass("step").text(x + 1)) - .append($("").addClass("direction").text(item)) - ); - } else { - $stepBulkList.append( - $("") - .append($("").attr("colspan", "2").text("")) - ); - } - } - }); - - $("#bulkStepAddSubmit").on("click", function() { - var parsed = $bulkStepsModal.data("bulkData"); - var x; - - if (parsed && parsed.length) { - for (x = 0; x < parsed.length; x++) { - var item = parsed[x]; - if (item) { - addStep(item); - } - } - } - - $bulkStepsModal.modal('hide') - }); - + $(".recipe-view ul.ingredients").checkable(); + $(".recipe-view ol.steps").checkable(); }); - })(jQuery); diff --git a/app/assets/stylesheets/journal_custom_colors.scss b/app/assets/stylesheets/journal_custom_colors.scss index eff77a8..ed9e16d 100644 --- a/app/assets/stylesheets/journal_custom_colors.scss +++ b/app/assets/stylesheets/journal_custom_colors.scss @@ -1,2 +1,4 @@ -$brand-primary: darken(#93C54B, 10%); \ No newline at end of file +$brand-primary: darken(#93C54B, 10%); +$text-color: #3E3F3A; + diff --git a/app/assets/stylesheets/recipes.scss b/app/assets/stylesheets/recipes.scss index 5c205fb..c7fa520 100644 --- a/app/assets/stylesheets/recipes.scss +++ b/app/assets/stylesheets/recipes.scss @@ -64,4 +64,8 @@ div.recipe-view { .steps div { padding-bottom: 15px; } + + li.checked { + text-decoration: line-through; + } } \ No newline at end of file diff --git a/app/views/ingredients/index.html.erb b/app/views/ingredients/index.html.erb index dad4916..2a89361 100644 --- a/app/views/ingredients/index.html.erb +++ b/app/views/ingredients/index.html.erb @@ -8,12 +8,14 @@

No Ingredients

<% else %> - +
+ + - + @@ -21,8 +23,14 @@ <% @ingredients.each do |ingredient| %> + + - + <% end %> diff --git a/app/views/recipes/show.html.erb b/app/views/recipes/show.html.erb index d249717..04e4748 100644 --- a/app/views/recipes/show.html.erb +++ b/app/views/recipes/show.html.erb @@ -2,7 +2,7 @@
-
+
-
- -
@@ -55,7 +42,27 @@
-

Ingredients

+ +
+

Ingredients

+ +
+ +
NameUSDA NDBNKCal per 100g Density
<%= link_to ingredient.name, edit_ingredient_path(ingredient) %><%= ingredient.ndbn %><%= ingredient.kcal %> <%= ingredient.density %><%= link_to 'Destroy', ingredient, method: :delete, data: { confirm: 'Are you sure?' } %> + <%= link_to ingredient, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-sm btn-danger' do %> + + <% end %> +