addRecipe.jsp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. <%@page contentType="text/html" pageEncoding="UTF-8"%>
  2. <%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
  3. <t:template>
  4. <jsp:attribute name="title">Add Recipe</jsp:attribute>
  5. <jsp:attribute name="head">
  6. <script type="text/javascript" src="static/ieat-ui.js"></script>
  7. <script type="text/javascript" src="static/ndbDatabase.js"></script>
  8. <script type="text/javascript" src="static/basicFoodEditor.js"></script>
  9. <script type="text/javascript" src="static/Food.js"></script>
  10. <script type="text/javascript" src="static/units.js"></script>
  11. <script type="text/javascript" src="static/searchBar.js"></script>
  12. <script type="text/javascript" src="static/nutritionLabel.js"></script>
  13. <base href="/ieat-2.0.0/" />
  14. <script type="text/javascript">
  15. var app = angular.module('recipe',
  16. ['ui.bootstrap', 'Food', 'ieat.ui', 'ndbDatabase',
  17. 'ieat.ui.editors'])
  18. .config(['$locationProvider', function($locationProvider) {
  19. $locationProvider.html5Mode(true);
  20. }]);
  21. app.controller('SearchController',
  22. ['$scope', '$location', '$uibModal', '$q',
  23. 'Food', 'Recipe', 'Unit', 'NDBList',
  24. function($scope, $location, $uibModal, $q,
  25. Food, Recipe, Unit, NDBList) {
  26. var loadRecipe = function(id) {
  27. return Recipe.get({"id": id}, function(r) {
  28. r.ingredients = r.ingredients.map(function(pair) {
  29. return {
  30. amount: pair.amount,
  31. item: Food.get({"id": pair.item})
  32. };
  33. });
  34. $scope.amount = r.result_amount;
  35. });
  36. };
  37. var id = $location.search()["id"];
  38. $scope.recipe = id? loadRecipe(id) : new Recipe({
  39. steps: [],
  40. ingredients: []
  41. });
  42. var ingredientSum = {calories: 0, grams: 0, nutrition: {}};
  43. var toGrams = function (amount, food) {
  44. switch (food.unit_type) {
  45. case "mass":
  46. return amount;
  47. case "volume":
  48. return amount * food.density;
  49. case "count":
  50. throw "Not yet implemented!";
  51. //return amount * food.mass_p_unit;
  52. }
  53. };
  54. var updateNutritionInfo = function() {
  55. var grams = 0, calories = 0, nutrition = {};
  56. $scope.recipe.ingredients.forEach(function(i) {
  57. grams += toGrams(i.amount, i.item);
  58. calories += i.amount * i.item.calories_p_100;
  59. for (var n in i.item.nutrients) {
  60. nutrition[n] = i.amount * i.item.nutrients[n] +
  61. (nutrition[n] || 0);
  62. }
  63. });
  64. var rGrams = toGrams($scope.recipe.result_amount, $scope.recipe);
  65. $scope.recipe.calories_p_100 = calories / rGrams;
  66. $scope.recipe.nutrients = {};
  67. for (var n in nutrition) {
  68. $scope.recipe.nutrients[n] = nutrition[n] / rGrams;
  69. }
  70. };
  71. $scope.updateResultAmount = function() {
  72. $scope.recipe.result_amount =
  73. $scope.unit.normalize($scope.recipe, $scope.amount);
  74. updateNutritionInfo();
  75. };
  76. $scope.categories = NDBList.get({
  77. key: "${ndbKey}",
  78. type: "g"
  79. });
  80. $scope.queryFoods = function(q) {
  81. return Food.query({query: q}).$promise;
  82. };
  83. var primeUnits = $scope.primeUnits = {};
  84. var unitList = Unit.query(function(units) {
  85. $scope.unit = units.find(function(u) {
  86. return u.symbol == "";
  87. });
  88. $scope.recipe.unit_type = $scope.recipe.unit_type
  89. || $scope.unit.type;
  90. $scope.unitList = units;
  91. units.forEach(function(u) {
  92. if (u.conversion == 1) {
  93. $scope.primeUnits[u.type] = u;
  94. }
  95. });
  96. });
  97. $q.all([unitList.$promise, $scope.recipe.$promise]).then(function() {
  98. $scope.unit = primeUnits[$scope.recipe.unit_type];
  99. });
  100. var newIngredientCtrl = [
  101. '$scope', '$uibModalInstance', 'food', 'units',
  102. function($scope, $uibModalInstance, food, units) {
  103. $scope.food = food;
  104. $scope.units = units;
  105. $scope.unit = primeUnits[food.unit_type];
  106. $scope.submit = $uibModalInstance.close;
  107. $scope.dismiss = $uibModalInstance.dismiss;
  108. }];
  109. $scope.addIngredient = function($item) {
  110. $uibModal.open({
  111. // TODO: Figure out what these are and how they work
  112. //ariaLabelledBy: 'modal-title',
  113. //ariaDescribedBy: 'modal-body',
  114. templateUrl: "newIngredient",
  115. resolve: {
  116. food: function() {return $item;},
  117. units: function() {return unitList;}
  118. },
  119. controller: newIngredientCtrl,
  120. size: "md"
  121. }).result.then(function(amount) {
  122. $scope.recipe.ingredients.push({
  123. amount: parseFloat(amount),
  124. item: $item
  125. });
  126. updateNutritionInfo();
  127. }, function(reason) {
  128. console.debug(reason);
  129. });
  130. };
  131. $scope.removeIngredient = function(index) {
  132. $scope.recipe.ingredients.splice(index, 1);
  133. updateNutritionInfo();
  134. };
  135. $scope.addStep = function(step) {
  136. $scope.recipe.steps.push(step);
  137. };
  138. $scope.removeStep = function(index) {
  139. $scope.recipe.steps.splice(index, 1);
  140. };
  141. $scope.saveRecipe = function() {
  142. var recipe = new Recipe($scope.recipe);
  143. recipe.ingredients = recipe.ingredients.map(function(pair) {
  144. return {amount: pair.amount, item: pair.item.id};
  145. });
  146. recipe.$save(function () {
  147. window.location = "/ieat-2.0.0";
  148. }, function (err) {
  149. // TODO: Proper error handling
  150. console.error(err);
  151. });
  152. };
  153. $scope.deleteRecipe = function() {
  154. $scope.recipe.$delete(function () {
  155. window.location = "/ieat-2.0.0/browseFood";
  156. }, function (err) {
  157. // TODO: Proper error handling
  158. console.error(err);
  159. });
  160. };
  161. }]);
  162. </script>
  163. </jsp:attribute>
  164. <jsp:body>
  165. <div class="section container" data-ng-app="recipe"
  166. data-ng-controller="SearchController">
  167. <h2>Add Recipe</h2>
  168. <div>
  169. <label for="recipeName">Name:</label>
  170. <input id="recipeName" type="text" data-ng-model="recipe.name" />
  171. </div>
  172. <div style="float: right;">
  173. <nutrition-label food="recipe"></nutrition-label>
  174. </div>
  175. <div>
  176. <label for="amount">Creates:</label>
  177. <input id="amount" type="number" data-ng-model="amount"
  178. data-ng-change="updateResultAmount();" />
  179. <select data-ng-model="unit"
  180. data-ng-change="recipe.dry = unit.type != 'volume';
  181. recipe.unit_type = unit.type;
  182. updateResultAmount();"
  183. data-ng-options="u as u.symbol for u in unitList">
  184. </select>
  185. </div>
  186. <div>
  187. <label for="group">Food Group:</label>
  188. <select id="group" data-ng-model="recipe.food_group"
  189. data-ng-options="c.name.trim() as c.name.trim()
  190. for c in categories">
  191. </select>
  192. </div>
  193. <div class="checkbox">
  194. <label for="dry">
  195. <input id="dry" type="checkbox" data-ng-model="recipe.dry" />
  196. Dry
  197. </label>
  198. </div>
  199. <div>
  200. <label for="density">Density (g/ml):</label>
  201. <input id="density" type="number" data-ng-model="recipe.density" />
  202. </div>
  203. <input type="button" value="Add" class="btn"
  204. data-ng-click="saveRecipe()" />
  205. <input type="button" value="Delete" class="btn btn-danger"
  206. data-ng-show="recipe.id" data-ng-click="deleteRecipe()" />
  207. <table style="width: 100%;">
  208. <tr>
  209. <td style="width: 50%;">
  210. <ol>
  211. <li data-ng-repeat="step in recipe.steps track by $index">
  212. {{step}}
  213. <span class="glyphicon glyphicon-remove"
  214. data-ng-click="removeStep($index);"></span>
  215. </li>
  216. </ol>
  217. </td>
  218. <td style="width: 50%;" colspan="2">
  219. <ul>
  220. <li data-ng-repeat="ingredient in recipe.ingredients">
  221. {{::ingredient.amount | number:0}}
  222. {{primeUnits[ingredient.item.unit_type].symbol}}
  223. {{::ingredient.item.name}}
  224. <span class="glyphicon glyphicon-remove"
  225. data-ng-click="removeIngredient($index);"></span>
  226. </li>
  227. </ul>
  228. </td>
  229. </tr>
  230. <tr>
  231. <td>
  232. <input type="text"
  233. style="width: 100%;"
  234. placeholder="Next step..."
  235. data-ng-model="nextStep"
  236. data-my-on-enter="addStep(nextStep); nextStep='';" />
  237. </td>
  238. <td>
  239. <input type="text"
  240. class="form-control"
  241. placeholder="Next ingredient..."
  242. data-ng-model="nextIngredient"
  243. data-uib-typeahead="food.name for food in queryFoods($viewValue)"
  244. data-typeahead-editable="false"
  245. data-typeahead-min-length="3"
  246. data-typeahead-on-select="addIngredient($item)"
  247. data-typeahead-loading="loadingFoods"
  248. data-typeahead-no-results="ingredientNotFound" />
  249. <i ng-show="loadingFoods" class="glyphicon glyphicon-refresh"></i>
  250. <div ng-show="ingredientNotFound">
  251. <i class="glyphicon glyphicon-remove"></i> No Results Found
  252. </div>
  253. </td>
  254. </tr>
  255. </table>
  256. <script type="text/ng-template" id="newIngredient">
  257. <div style="width: 100%; text-align: center; padding: 0 1em 1em 0;">
  258. <span style="font-weight: bold;">{{::food.name}}: </span>
  259. <input type="number" min="0" required="required"
  260. data-ng-model="amount" />
  261. <select required="required" data-ng-model="unit"
  262. data-ng-options="u.name for u in units">
  263. </select>
  264. <button type="button"
  265. class="btn btn-success"
  266. data-ng-click="submit(unit.normalize(food, amount));">
  267. Submit
  268. </button>
  269. <button type="button" class="btn" data-ng-click="dismiss();">
  270. Cancel
  271. </button>
  272. </div>
  273. </script>
  274. </jsp:body>
  275. </t:template>