2016-01-30 17:02:19 -06:00
|
|
|
(function($) {
|
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
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'
|
|
|
|
}
|
2016-01-30 17:02:19 -06:00
|
|
|
});
|
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
// 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'
|
|
|
|
// }
|
|
|
|
// });
|
|
|
|
|
|
|
|
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");
|
|
|
|
})
|
2016-01-30 17:02:19 -06:00
|
|
|
}
|
2016-01-30 20:29:35 -06:00
|
|
|
|
2016-01-30 21:20:15 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
function ingredientItemPicked($typeahead, datum) {
|
|
|
|
var $container = $typeahead.closest(".nested-fields");
|
|
|
|
var $ingredientId = $container.find("input.ingredient_id");
|
|
|
|
var $group = $container.find("div.typeahead-group");
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
$ingredientId.val(datum.id);
|
|
|
|
$typeahead.typeahead('val', datum.name);
|
|
|
|
$group.addClass("has-success");
|
2016-01-30 17:02:19 -06:00
|
|
|
}
|
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
function ingredientNameChange($typeahead, ingredientSearchEngine) {
|
|
|
|
var $container = $typeahead.closest(".nested-fields");
|
|
|
|
var $ingredientId = $container.find("input.ingredient_id");
|
|
|
|
var $group = $container.find("div.typeahead-group");
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
var id = $ingredientId.val();
|
|
|
|
var value = $typeahead.typeahead('val');
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
if (id && id.length) {
|
|
|
|
var found = ingredientSearchEngine.get([id]);
|
|
|
|
if (found && found[0] && found[0].name != value) {
|
|
|
|
// User has chosen something custom
|
|
|
|
$ingredientId.val('');
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
$group.removeClass("has-success");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
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);
|
|
|
|
});
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
$("#addIngredientButton").trigger("click");
|
|
|
|
}
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
function getIngredients() {
|
|
|
|
var data = [];
|
|
|
|
$("#ingredient-list .ingredient-editor").each(function() {
|
|
|
|
var $container = $(this);
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
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");
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
data.push({ingredient_id: $ingredientId.val(), name: $name.typeahead("val"), quantity: $quantity.val(), units: $units.val(), preparation: $preparation.val()});
|
|
|
|
});
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
return data;
|
|
|
|
}
|
2016-01-30 17:02:19 -06:00
|
|
|
|
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
$(document).on("turbolinks:load", function() {
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
var $ingredientList = $("#ingredient-list");
|
|
|
|
var $tagInput = $("select.tag_names");
|
2017-04-14 09:01:51 -05:00
|
|
|
var $stepInput = $("textarea#recipe_step_text");
|
2016-01-30 21:20:15 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
if ($ingredientList.length) {
|
|
|
|
ingredientSearchEngine.initialize(false);
|
2016-01-30 17:02:19 -06:00
|
|
|
}
|
|
|
|
|
2017-04-14 09:01:51 -05:00
|
|
|
if ($stepInput.length) {
|
2017-04-14 16:40:38 -05:00
|
|
|
CodeMirror.fromTextArea(
|
|
|
|
$stepInput[0],
|
|
|
|
{
|
|
|
|
mode: {
|
|
|
|
name: 'markdown',
|
|
|
|
strikethrough: true
|
|
|
|
},
|
|
|
|
// config tomfoolery to enable soft tabs
|
|
|
|
extraKeys: {
|
|
|
|
Tab: function(cm) {
|
|
|
|
if (cm.somethingSelected()) {
|
|
|
|
cm.indentSelection("add");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cm.options.indentWithTabs)
|
|
|
|
cm.replaceSelection("\t", "end", "+input");
|
|
|
|
else
|
|
|
|
cm.execCommand("insertSoftTab");
|
|
|
|
},
|
|
|
|
"Shift-Tab": function(cm) {
|
|
|
|
cm.indentSelection("subtract");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
indentUnit: 2,
|
|
|
|
tabSize: 2,
|
|
|
|
indentWithTabs: false,
|
|
|
|
lineWrapping: true,
|
|
|
|
lineNumbers: true
|
|
|
|
}
|
|
|
|
);
|
2017-04-14 09:01:51 -05:00
|
|
|
}
|
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
$tagInput.tagsinput({
|
|
|
|
trimValue: true,
|
|
|
|
confirmKeys: [9, 13, 32, 44] // tab, enter, space, comma
|
|
|
|
});
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
|
|
|
|
initializeIngredientEditor($ingredientList, ingredientSearchEngine);
|
|
|
|
|
|
|
|
$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) {
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
$('#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);
|
|
|
|
|
|
|
|
var parseBulkIngredients = 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+)?([^,]*)(?:,\s*(.*))?$/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 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) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$bulkIngredientsModal.data("bulkData", parsed);
|
|
|
|
|
|
|
|
for (x = 0; x < parsed.length; x++) {
|
|
|
|
var item = parsed[x];
|
|
|
|
if (item != null) {
|
|
|
|
$ingredientBulkList.append(
|
|
|
|
$("<tr />")
|
|
|
|
.append($("<td />").addClass("quantity").text(item.quantity))
|
|
|
|
.append($("<td />").addClass("units").text(item.units))
|
|
|
|
.append($("<td />").addClass("name").text(item.name))
|
|
|
|
.append($("<td />").addClass("preparation").text(item.preparation))
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$ingredientBulkList.append(
|
|
|
|
$("<tr />")
|
|
|
|
.append($("<td />").attr("colspan", "4").text("<Cannot Parse>"))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$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();
|
|
|
|
});
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
$("#bulkIngredientAddSubmit").on("click", function() {
|
|
|
|
var parsed = $bulkIngredientsModal.data("bulkData");
|
|
|
|
var x;
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
$("#ingredient-list").find(".remove-button").trigger("click");
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
if (parsed && parsed.length) {
|
|
|
|
for (x = 0; x < parsed.length; x++) {
|
|
|
|
var item = parsed[x];
|
|
|
|
if (item) {
|
|
|
|
addIngredient(item)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-01-30 17:02:19 -06:00
|
|
|
|
2016-10-20 15:48:33 -05:00
|
|
|
$bulkIngredientsModal.modal('hide')
|
|
|
|
});
|
2016-01-30 17:02:19 -06:00
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
})(jQuery);
|