diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ed6ea4a..3ae0d91 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -15,6 +15,7 @@ //= require turbolinks //= require bootstrap-sprockets //= require bootstrap-datepicker +//= require bootstrap-tagsinput //= require cocoon //= require typeahead //= require autosize diff --git a/app/assets/javascripts/recipe_editor.js b/app/assets/javascripts/recipe_editor.js index 116af43..ea30cc8 100644 --- a/app/assets/javascripts/recipe_editor.js +++ b/app/assets/javascripts/recipe_editor.js @@ -1,458 +1,490 @@ (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); + 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 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"); + // var tagSearchEngine = 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: '/tags/prefetch.json', + // cache: false + // }, + // remote: { + // url: '/tags/search.json?query=%QUERY', + // wildcard: '%QUERY' + // } + // }); - $editors.each(function(idx, elem) { - var $editor = $(elem); - var $ingredientId = $editor.find("input.ingredient_id"); - var $group = $editor.find("div.typeahead-group"); + 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"); + }) + } - $editor.find(".ingredient-typeahead").typeahead({}, - { - name: 'ingredients', - source: ingredientSearchEngine, - display: function(datum) { - return datum.name; - } + 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 $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) { + $group.addClass("has-success"); + } + }); + } + + function ingredientItemPicked($typeahead, datum) { + var $container = $typeahead.closest(".nested-fields"); + var $ingredientId = $container.find("input.ingredient_id"); + var $group = $container.find("div.typeahead-group"); + + $ingredientId.val(datum.id); + $typeahead.typeahead('val', datum.name); + $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(item) { + $("#ingredient-list").one("cocoon:before-insert", function(e, $container) { + var $ingredientId = $container.find("input.ingredient_id"); + var $name = $container.find("input.ingredient-typeahead"); + var $quantity = $container.find("input.quantity"); + var $units = $container.find("input.units"); + var $preparation = $container.find("input.preparation"); + + $name.val(item.name); + $ingredientId.val(item.ingredient_id); + $units.val(item.units); + $quantity.val(item.quantity); + $preparation.val(item.preparation); }); - if ($ingredientId.val().length) { - $group.addClass("has-success"); - } - }); - } - - function ingredientItemPicked($typeahead, datum) { - var $container = $typeahead.closest(".nested-fields"); - var $ingredientId = $container.find("input.ingredient_id"); - var $group = $container.find("div.typeahead-group"); - - $ingredientId.val(datum.id); - $typeahead.typeahead('val', datum.name); - $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(item) { - $("#ingredient-list").one("cocoon:before-insert", function(e, $container) { - var $ingredientId = $container.find("input.ingredient_id"); - var $name = $container.find("input.ingredient-typeahead"); - var $quantity = $container.find("input.quantity"); - var $units = $container.find("input.units"); - var $preparation = $container.find("input.preparation"); - - $name.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"); - $step.val(step); - }); - - $("#addStepButton").trigger("click"); - } - - function getSteps() { - var data = []; - $("#step-list .step-editor").each(function() { - var $container = $(this); - - var $step = $container.find("textarea.step"); - - data.push($step.val()); - }); - - return data; - } - - $(document).on("turbolinks:load", function() { - - var $ingredientList = $("#ingredient-list"); - var $stepList = $("#step-list"); - - if ($ingredientList.length) { - ingredientSearchEngine.initialize(false); + $("#addIngredientButton").trigger("click"); } - initializeStepEditor($stepList); + function getIngredients() { + var data = []; + $("#ingredient-list .ingredient-editor").each(function() { + var $container = $(this); - $stepList - .on("cocoon:after-insert", function(e, item) { - reorder($(this)); - initializeStepEditor(item); - }) - .on("cocoon:after-remove", function(e, item) { - if (item.find(".remove-button.existing").length) { - item.detach().appendTo("#deleted_steps"); - } - 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()); - }); + 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()}); + }); - initializeIngredientEditor($ingredientList, ingredientSearchEngine); + return data; + } - $ingredientList - .on("cocoon:after-insert", function(e, item) { - reorder($ingredientList); - initializeIngredientEditor(item, ingredientSearchEngine); - }) - .on("cocoon:after-remove", function(e, item) { - if (item.find(".remove-button.existing").length) { - item.detach().appendTo("#deleted_ingredients"); - } - 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) { + function addStep(step) { + $("#step-list").one("cocoon:before-insert", function(e, $container) { + var $step = $container.find("textarea.step"); + $step.val(step); + }); - }); + $("#addStepButton").trigger("click"); + } - $('#convert_modal') - .on('show.bs.modal', function (event) { - var $button = $(event.relatedTarget); - var $modal = $(this); + function getSteps() { + var data = []; + $("#step-list .step-editor").each(function() { + var $container = $(this); - var $editor = $button.closest(".ingredient-editor"); + var $step = $container.find("textarea.step"); - $modal.data('ingredient-editor', $editor); + data.push($step.val()); + }); - var $quantity = $editor.find("input.quantity"); - var $units = $editor.find("input.units"); - var $ingredientId = $editor.find("input.ingredient_id"); + return data; + } - var $modalQuantity = $modal.find("input.quantity"); - var $modalUnits = $modal.find("input.units"); - var $modalIngredientId = $modal.find("input.ingredient_id"); + $(document).on("turbolinks:load", function() { - $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 { + var $ingredientList = $("#ingredient-list"); + var $stepList = $("#step-list"); + var $tagInput = $("select.tag_names"); + if ($ingredientList.length) { + ingredientSearchEngine.initialize(false); } - $("#modal_form_container").replaceWith($(data.form_html)); - }); + $tagInput.tagsinput({ + trimValue: true, + confirmKeys: [9, 13, 32, 44] // tab, enter, space, comma + }); - var $bulkIngredientsModal = $("#bulk_ingredients_modal"); - var $ingredientBulkInput = $("#ingredient_bulk_input"); - var $ingredientBulkList = $("#ingredient_bulk_parsed_list"); - autosize($ingredientBulkInput); + initializeStepEditor($stepList); - var parseBulkIngredients = function() { - var data = $ingredientBulkInput.val(); - $ingredientBulkList.empty(); + $stepList + .on("cocoon:after-insert", function(e, item) { + reorder($(this)); + initializeStepEditor(item); + }) + .on("cocoon:after-remove", function(e, item) { + if (item.find(".remove-button.existing").length) { + item.detach().appendTo("#deleted_steps"); + } + 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()); + }); - var parsed = []; - var x; - var lines = data.replace("\r", "").split("\n"); + initializeIngredientEditor($ingredientList, ingredientSearchEngine); - var regex = /^(?:([\d\/.]+(?:\s+[\d\/]+)?)\s+)?(?:([\w-]+)(?:\s+of)?\s+)?([^,]*)(?:,\s*(.*))?$/i; + $ingredientList + .on("cocoon:after-insert", function(e, item) { + reorder($ingredientList); + initializeIngredientEditor(item, ingredientSearchEngine); + }) + .on("cocoon:after-remove", function(e, item) { + if (item.find(".remove-button.existing").length) { + item.detach().appendTo("#deleted_ingredients"); + } + 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) { - 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; } + $('#convert_modal') + .on('show.bs.modal', function (event) { + var $button = $(event.relatedTarget); + var $modal = $(this); - var barIndex = line.lastIndexOf("|"); - var afterBar = null; + var $editor = $button.closest(".ingredient-editor"); - if (barIndex >= 0) { - afterBar = line.slice(barIndex + 1); - line = line.slice(0, barIndex); - } + $modal.data('ingredient-editor', $editor); - var match = line.match(regex); + var $quantity = $editor.find("input.quantity"); + var $units = $editor.find("input.units"); + var $ingredientId = $editor.find("input.ingredient_id"); - if (match) { - 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); - } - } + var $modalQuantity = $modal.find("input.quantity"); + var $modalUnits = $modal.find("input.units"); + var $modalIngredientId = $modal.find("input.ingredient_id"); - $bulkIngredientsModal.data("bulkData", parsed); + $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'); - for (x = 0; x < parsed.length; x++) { - var item = parsed[x]; - if (item != null) { - $ingredientBulkList.append( - $("