ko.bindingHandlers.numericText = { update: function (element, valueAccessor, allBindingsAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || ko.bindingHandlers.numericText.defaultPrecision, precision = 1; formattedValue = value == 0 ? "0" : value.toFixed(precision); ko.bindingHandlers.text.update(element, function () { return formattedValue; }); }, defaultPrecision: 2 }; var FoundProduct = function (productId, name, seoName, calories, fat, protein, carbon, amount, portionTypeId, portionTypeName, portionSize, portionSizeId, portions, isCustom, isFavorite, brand, losses) { var self = this; self.productId = productId; self.name = name; self.amount = ko.observable(amount); self.calories = calories; self.protein = protein; self.carbon = carbon; self.fat = fat; self.portionTypeId = ko.observable(portionTypeId); self.portionTypeName = portionTypeName; self.portionSize = ko.observable(portionSize); self.portionSizeId = portionSizeId; self.portions = portions; this.portionTypeWeight = ko.observable(portionTypeId + '_' + portionSize); self.isEdit = ko.observable(false); self.isCustom = isCustom; self.isFavorite = ko.observable(isFavorite); self.seoName = seoName; self.brand = brand; self.selected = ko.observable(false); self.link = ko.computed(function () { return self.isCustom ? '/Личный-дневник/Мои-продукты' : '/Продукты/Калорийность/' + self.seoName; }); self.losses = ko.observableArray(losses); this.portionTypeWeight.subscribe(function (value) { //sizeid_portiontype_portionweight if (value == '') { return; } var portionData = (value + '').split('_'); self.portionSizeId = portionData[0]; self.portionTypeId(portionData[1]); if (self.portionTypeId() == 1) { self.amount(100); } else { self.amount(1); } self.portionSize(portionData[2]); }); self.grammsComput = ko.pureComputed(function () { if (self.portionSize() == null) { return self.amount(); } else { return self.amount() * self.portionSize(); } }); self.caloriesComput = ko.pureComputed(function () { if (self.portionSize() == null) { return self.calories * self.amount(); } else { return self.calories * self.amount() * self.portionSize(); } }); self.fatComput = ko.pureComputed(function () { if (self.portionSize() == null) { return self.fat * self.amount(); } else { return self.fat * self.amount() * self.portionSize(); } }); self.carbonComput = ko.pureComputed(function () { if (self.portionSize() == null) { return self.carbon * self.amount(); } else { return self.carbon * self.amount() * self.portionSize(); } }); self.proteinComput = ko.pureComputed(function () { if (self.portionSize() == null) { return self.protein * self.amount(); } else { return self.protein * self.amount() * self.portionSize(); } }); self.selectClick = function (product) { product.selected(!product.selected()); } }; var AddedProduct = function (product, ingredientId) { var self = this; this.ingredientId = ingredientId; self.product = product; self.isVarka = ko.observable(false); self.isVarkaSliv = ko.observable(false); self.isTushenie = ko.observable(false); self.isZharka = ko.observable(false); self.isZapekanie = ko.observable(false); self.isPripuskanie = ko.observable(false); self.isPasserovanie = ko.observable(false); self.varkaD = ko.observable(true); self.varkaSlivD = ko.observable(true); self.tushenieD = ko.observable(true); self.zharkaD = ko.observable(true); self.zapekanieD = ko.observable(true); self.pripuskanieD = ko.observable(true); self.passerovanieD = ko.observable(true); self.caloriesAfter = ko.observable(self.product.caloriesComput()); self.proteinAfter = ko.observable(self.product.proteinComput()); self.fatAfter = ko.observable(self.product.fatComput()); self.carbonAfter = ko.observable(self.product.carbonComput()); self.amountAfter = ko.observable(self.product.grammsComput()); for (var i = 0; i < self.product.losses().length; i++) { switch (self.product.losses()[i].cm) { case 1: self.varkaD(false); break; case 2: self.varkaSlivD(false); break; case 3: self.tushenieD(false); break; case 4: self.pripuskanieD(false); break; case 5: self.zharkaD(false); break; case 6: self.zapekanieD(false); break; case 7: self.passerovanieD(false); break; } } /*self.isVarka(!self.varkaD() && self.isVarka()); self.isVarkaSliv(!self.varkaSlivD() && self.isVarkaSliv()); self.isTushenie(!self.tushenieD() && self.isTushenie()); self.isZharka(!self.zharkaD() && self.isZharka()); self.isZapekanie(!self.zapekanieD() && self.isZapekanie()); self.isPripuskanie(!self.pripuskanieD() && self.isPripuskanie()); self.isPasserovanie(!self.passerovanieD() && self.isPasserovanie());*/ /* None = 0, Varka = 1, VarkaSoSlivom = 2, Tushenie = 3, Pripuskanie = 4, Zharka = 5, Zapekanie = 6, Passerovanie = 7*/ this.product.amount.subscribe(function (value) { self.updateValuesAfter(); }); this.isVarka.subscribe(function (value) { self.updateValuesAfter(); }); this.isVarkaSliv.subscribe(function (value) { self.updateValuesAfter(); }); this.isTushenie.subscribe(function (value) { self.updateValuesAfter(); }); this.isZharka.subscribe(function (value) { self.updateValuesAfter(); }); this.isZapekanie.subscribe(function (value) { self.updateValuesAfter(); }); this.isPripuskanie.subscribe(function (value) { self.updateValuesAfter(); }); this.isPasserovanie.subscribe(function (value) { self.updateValuesAfter(); }); self.selectedLosses = function () { var selCooking = self.isVarka() ? 1 : self.isVarkaSliv() ? 2 : self.isTushenie() ? 3 : self.isPripuskanie() ? 4 : self.isZharka() ? 5 : self.isZapekanie() ? 6 : self.isPasserovanie() ? 7 : 0; var selectedLoss = ko.utils.arrayFilter(self.product.losses(), function (loss) { return loss.cm == selCooking; }); if (selectedLoss == null || selectedLoss.length == 0) { return null; } return selectedLoss[0]; } self.updateValuesAfter = function () { var selectedLoss = self.selectedLosses(); if (selectedLoss == null) { self.proteinAfter(self.product.proteinComput()); self.fatAfter(self.product.fatComput()); self.carbonAfter(self.product.carbonComput()); self.amountAfter(self.product.grammsComput()); self.caloriesAfter(self.product.caloriesComput()); } else { var amountPercent = (100 - selectedLoss.m)/100; self.proteinAfter(self.product.proteinComput() * (100 - selectedLoss.p) / 100); self.fatAfter(self.product.fatComput() * (100 - selectedLoss.f) / 100); self.carbonAfter(self.product.carbonComput() * (100 - selectedLoss.c) / 100); self.amountAfter(self.product.grammsComput() * amountPercent); self.caloriesAfter(self.proteinAfter()*4 + self.fatAfter()*9 + self.carbonAfter()*4); } }; }; function PortionModel(portionTypeId, portionWeight, recipeModel) { var self = this; this.portionKoeff = ko.observable(0); this.portionTypeId = ko.observable(portionTypeId); this.portionSize = ko.observable(portionWeight); this.recipeModel = recipeModel; this.portionTypeWeight = ko.observable(self.portionTypeId()); this.portions = ko.observableArray(allPortions); this.portionSize.subscribe(function (value) { var amount = self.recipeModel.amountAfter(); var koeff = amount == 0 ? 0 : (self.portionSize() / amount); self.portionKoeff(koeff); }); this.caloriesPortion = ko.pureComputed(function () { return self.recipeModel.caloriesAfterSum() * self.portionKoeff(); }); this.proteinPortion = ko.pureComputed(function () { return self.recipeModel.proteinAfterSum() * self.portionKoeff(); }); this.fatPortion = ko.pureComputed(function () { return self.recipeModel.fatAfterSum() * self.portionKoeff(); }); this.carbonPortion = ko.pureComputed(function () { return self.recipeModel.carbonAfterSum() * self.portionKoeff(); }); } function FindProductModel() { var self = this; this.portions = ko.observableArray([]); this.categories = categories; this.lastAjaxRequest = null; this.foundProducts = ko.observableArray([]); this.dishProducts = ko.observableArray([]); this.notFound = ko.observable(false); this.recipeModel = new RecipeModel(); this.addPortion = function (val) { val = val != 100 ? 0 : val; this.portions.push(new PortionModel(1, val, self)); } if (recipeToEdit == null || recipeToEdit.Id == 0) { this.id = ko.observable(0); this.amountManual = ko.observable(0); this.factAmountKoeff = ko.observable(1); this.recipeName = ko.observable(''); this.publicState = ko.observable(1); this.selectedCategoryId = ko.observable(undefined).extend({ required: { params: true, message: 'Выберите категорию' } }); this.addPortion(100); var descr = new RecipeStepModel(0); var step1 = new RecipeStepModel(1); this.recipeModel.recipeSteps.push(descr); this.recipeModel.recipeSteps.push(step1); } else { this.id = ko.observable(recipeToEdit.Id); this.portions = ko.observableArray([]); this.recipeName = ko.observable(recipeToEdit.Name); this.selectedCategoryId = ko.observable(recipeToEdit.CategoryId).extend({ required: { params: true, message: 'Выберите категорию' } }); this.publicState = ko.observable(recipeToEdit.PublicState); var descr = new RecipeStepModel(0, recipeToEdit.Description); this.recipeModel.recipeSteps.push(descr); for (var i = 0; i < recipeToEdit.PortionSize1.length; i++) { var portionSize = recipeToEdit.PortionSize1[i]; var weight = portionSize.PortionTypeId == 1 ? 100 : portionSize.Weight; this.portions.push(new PortionModel(portionSize.PortionTypeId, weight, self)); } for (var i = 0; i < recipeToEdit.RecipeIngredient1.length; i++) { var ingr = recipeToEdit.RecipeIngredient1[0]; var ingrSourcePr = ingr.Product; var ingrProduct = new FoundProduct(ingrSourcePr.Id, ingrSourcePr.Name, ingrSourcePr.SeoName, ingrSourcePr.Calorie, ingrSourcePr.Fat, ingrSourcePr.Protein, ingrSourcePr.Carbon, ingr.amount, ingr.PortionSize.PortionTypeId, ingr.PortionSize.PortionTypeName, ingr.PortionSize.Weight, ingr.PortionSize.Id, null, ingrSourcePr.IsCustom, ingrSourcePr.IsFavorite, ingrSourcePr.Brand, null); var addedProduct = new AddedProduct(ingrProduct, ingr.Id); self.dishProducts.push(addedProduct); } for (var i = 0; i < recipeToEdit.RecipeStep.length; i++) { var step = recipeToEdit.RecipeStep[i]; var step1 = new RecipeStepModel( step.Id, step.Text); this.recipeModel.recipeSteps().push({ id: step.Id, text: step.Text }); } this.factAmountKoeff = ko.observable(1); this.amountManual = ko.observable(0); } self.isPublicDB = ko.computed(function () { return self.publicState() == 1 || self.publicState() == 2; }); this.enableSearch = function () { typewatch(function () { if ($("#query").val().length >= 0) { self.findProducts(); } }, 500); } this.findProducts = function () { if (self.lastAjaxRequest != null) { self.lastAjaxRequest.abort(); self.lastAjaxRequest = null; } self.lastAjaxRequest = $.ajax({ url: '/Analysis/GetProducts', type: 'POST', data: { search: $("#query").val() }, success: function (data) { self.bindFoundProducts(data); self.notFound(data.products.length == 0) }, error: function (xhr, ajaxOptions, thrownError) { } }); } this.amountManual.subscribe(function (value) { var amount = self.amountAfter(); var koeff = self.amountManual() == 0 ? 1 : (self.amountManual() / amount) self.factAmountKoeff(koeff); for (var i = 0; i < self.portions().length; i++) { var koeff = amount == 0 ? 0 : (self.portions()[i].portionSize() / amount); self.portions()[i].portionKoeff(koeff); } }); this.amountAfter = ko.computed(function () { var sum = 0; for (var i = 0; i < self.dishProducts().length; i++) { sum += self.dishProducts()[i].amountAfter()*1; } for (var i = 0; i < self.portions().length; i++) { var koeff = sum == 0 ? 0 : (self.portions()[i].portionSize() / sum); self.portions()[i].portionKoeff(koeff); } return sum; }); this.caloriesAfterSum = ko.pureComputed(function () { var sum = 0; for (var i = 0; i < self.dishProducts().length; i++) { sum += self.dishProducts()[i].caloriesAfter(); } return sum; }); this.proteinAfterSum = ko.pureComputed(function () { var sum = 0; for (var i = 0; i < self.dishProducts().length; i++) { sum += self.dishProducts()[i].proteinAfter(); } return sum; }); this.fatAfterSum = ko.pureComputed(function () { var sum = 0; for (var i = 0; i < self.dishProducts().length; i++) { sum += self.dishProducts()[i].fatAfter(); } return sum; }); this.carbonAfterSum = ko.pureComputed(function () { var sum = 0; for (var i = 0; i < self.dishProducts().length; i++) { sum += self.dishProducts()[i].carbonAfter(); } return sum; }); this.caloriesWithAmount = ko.pureComputed(function () { return self.caloriesAfterSum() * self.factAmountKoeff(); }); this.proteinWithAmount = ko.pureComputed(function () { return self.proteinAfterSum() *self.factAmountKoeff(); }); this.fatWithAmount = ko.pureComputed(function () { return self.fatAfterSum()* self.factAmountKoeff(); }); this.carbonWithAmount = ko.pureComputed(function () { return self.carbonAfterSum() * self.factAmountKoeff(); }); this.bindFoundProducts = function (data) { self.foundProducts.removeAll(); var foundProducts = ko.utils.arrayMap(data.products, function (p) { return new FoundProduct(p.id, p.n, p.sN, p.c, p.f, p.p, p.cr, p.a, p.ptI, p.ptn, p.pw, p.psI, p.pp, p.iC, p.iF, p.b, p.pcl); }); self.foundProducts(foundProducts); } self.foundProductsVisible = ko.pureComputed(function () { return self.foundProducts().length > 0 && $("#query").val().length > 0; }); this.deleteProduct = function (product) { self.dishProducts.remove(product); } this.deletePortion = function (portion) { self.portions.remove(portion); } this.addProductToDish = function (product) { var addedProduct = new AddedProduct(product, 0); self.dishProducts.push(addedProduct); self.foundProducts.removeAll(); } if ($("#query").val().length > 0) { self.findProducts(); } this.clearFound = function (data) { self.foundProducts.removeAll(); $("#query").val(''); } this.setPublicDB = function () { var isPublic = self.isPublicDB(); if (isPublic) { self.publicState(0); } else { self.publicState(1); } return true; } this.addRecipe = function () { var portionSizes = []; for (var i = 0; i < self.portions().length; i++) { var portion = self.portions()[i]; var size = portion.portionTypeId() == 1 ? 1 : portion.portionSize() * 1; portionSizes.push({ Id: portion.id, ProductId: self.id, PortionTypeId: portion.portionTypeId(), Weight: size }); } var desc = self.recipeModel.recipeSteps()[0].text(); desc = desc == '' ? null : desc; var steps = []; for (var i = 1; i < self.recipeModel.recipeSteps().length; i++) { var step = self.recipeModel.recipeSteps()[i]; steps.push({ Id: step.id(), ProductId: self.id, StepNumber: i, Text: step.text() }); } var ingrs = []; for (var i = 0; i < self.dishProducts().length; i++) { var pr = self.dishProducts()[i]; ingrs.push({ Id: pr.ingredientId, ProductId: self.id, IngredientProductId: pr.product.productId, Amount: pr.amountAfter() * 1, PortionSizeId: pr.product.portionSizeId, Varka: pr.isVarka(), VarkaSliv: pr.isVarkaSliv(), Tushenie: pr.isTushenie(), Zharka: pr.isZharka(), Zapekanie: pr.isZapekanie(), Pripuskanie: pr.isPripuskanie(), Passerovanie: pr.isPasserovanie() }); } var data = { recipe: { Id: self.id, Name: self.recipeName(), Description: desc, Protein: self.proteinWithAmount(), Fat: self.fatWithAmount(), Carbon: self.carbonWithAmount(), Calorie: self.caloriesWithAmount(), IsCustom: true, CategoryId: self.selectedCategoryId(), Source: 7, PublicState: self.publicState(), PortionSize1: portionSizes, RecipeIngredient: ingrs, IsRecipe: true }, }; $.ajax({ //url: self.isEdit() ? '/Analysis/UpdateRecipe' : '/Analysis/AddRecipe', url: '/Analysis/AddRecipe', type: 'POST', dataType: "json", contentType: "application/json; charset=utf-8", data: JSON.stringify(data), traditional: true, success: function (p) { /* if (!self.isEdit()) { vm.foundProducts.push(new FoundProduct(p.id, p.n, p.cI, p.c, p.f, p.p, p.cr, p.pp, p.pu, p.b, p.sn, p.s, p.sc, false, true)); vm.newProduct(new FoundProduct(0, null, null, null, null, null, null, null, 1, null, null, null, null, true, true)); vm.similarProducts([]); showMessage("Продукт добавлен"); } else { self.portions(self.convertPortions(p.pp)); showMessage("Продукт обновлен"); self.isEdit(false); }*/ }, error: function (xhr, ajaxOptions, thrownError) { showMessage("Не удалось сохранить продукт"); } }); } $(document).on('drop dragover', function (e) { e.preventDefault(); }); } function RecipeModel() { var self = this; this.recipeSteps = ko.observableArray([]); this.lastId = 1; this.handleAfterRender = function (elements, data) { data.initStep(); } this.addStep = function (data) { self.lastId = self.lastId + 1; var step = new RecipeStepModel(self.lastId); self.recipeSteps.push(step); } this.deleteStep = function (step) { self.lastId = self.lastId - 1; self.recipeSteps.remove(step); for (var i = 0; i < self.recipeSteps().length; i++) { self.recipeSteps()[i].id(i); } } } function RecipeStepModel(id, text) { var self = this; this.id = ko.observable(id); this.text = ko.observable(text); this.img = ko.observable(); this.formId = ko.pureComputed(function () { return 'form_' + self.id(); }); this.dropId = ko.pureComputed(function () { return 'drop_' + self.id(); }); this.imageId = ko.pureComputed(function () { return 'img_' + self.id(); }); this.stepName = ko.pureComputed(function () { return self.id() == 0 ? 'Описание рецепта' : 'Шаг ' + self.id(); }); this.initStep = function () { var ul = $('#' + self.formId() + ' ul'); $('#' + self.dropId() + ' a').click(function () { $(this).parent().find('input').click(); }); $('#' + self.formId()).fileupload({ dropZone: $('#' + self.dropId()), add: function (e, data) { var goUpload = true; var uploadFile = data.files[0]; if (!(/\.(gif|jpg|jpeg|tiff|png)$/i).test(uploadFile.name)) { showMessage('Закачивать можно только изображения'); goUpload = false; } if (uploadFile.size > 4000000) { // 4mb showMessage('Максимальный размер 4 MB'); goUpload = false; } var tpl = $('