Editable shopping category

version2
Tim Holloway 2 years ago
parent e4da9a6a71
commit ce0f354f9a
  1. 5
      pom.xml
  2. 106
      src/main/java/com/mousetech/gourmetj/EditShopcatBean.java
  3. 4
      src/main/java/com/mousetech/gourmetj/IngredientUI.java
  4. 8
      src/main/java/com/mousetech/gourmetj/JSFUtils.java
  5. 95
      src/main/java/com/mousetech/gourmetj/RecipeDetailBean.java
  6. 37
      src/main/java/com/mousetech/gourmetj/SpringPrimeFacesApplication.java
  7. 9
      src/main/java/com/mousetech/gourmetj/persistence/service/RecipeService.java
  8. 54
      src/main/resources/META-INF/resources/WEB-INF/layout/layout.xhtml
  9. 573
      src/main/resources/META-INF/resources/detailEdit.xhtml
  10. 61
      src/main/resources/META-INF/resources/editShopcat.xhtml
  11. 9
      src/main/resources/META-INF/resources/error/error.html

@ -88,6 +88,11 @@
<version>2.3.3</version> <version>2.3.3</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.apache.tomcat.embed</groupId> <groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId> <artifactId>tomcat-embed-jasper</artifactId>

@ -0,0 +1,106 @@
package com.mousetech.gourmetj;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.primefaces.event.SelectEvent;
import com.mousetech.gourmetj.persistence.dao.ShopcatRepository;
import com.mousetech.gourmetj.persistence.model.Shopcat;
@Named
@ViewScoped
public class EditShopcatBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String ingkey;
private String shopcatName;
private String shopcatSuggestion;
private List<String> shopcatSuggestionList;
@Inject
ShopcatRepository shopcatRepository;
/**
* Default Constructor.
*/
public EditShopcatBean() {
}
@PostConstruct
public void init() {
this.shopcatSuggestionList = this.shopcatRepository
.findDistinctCategoryNative();
// // Get ingkey from Flash scope
// ingkey = (String) JSFUtils.getFlash("ingkey");
// Shopcat scat = this.shopcatRepository
// .findShopcatByIngkey(ingkey);
// if (scat != null) {
// this.setShopcatName(scat.getShopcategory());
// }
}
/**
* @return the shopcatName
*/
public String getShopcatName() {
return shopcatName;
}
/**
* @param shopcatName the shopcatName to set
*/
public void setShopcatName(String shopcatName) {
this.shopcatName = shopcatName;
}
/**
* @return the shopcatSuggestion
*/
public String getShopcatSuggestion() {
return shopcatSuggestion;
}
/**
* @param shopcatSuggestion the shopcatSuggestion to set
*/
public void setShopcatSuggestion(String shopcatSuggestion) {
this.shopcatSuggestion = shopcatSuggestion;
}
/**
* @return the ingkey
*/
public String getIngkey() {
return ingkey;
}
public void setIngkey(String ingkey) {
this.ingkey = ingkey;
}
/**
* @return the shopcatSuggestionList
*/
public List<String> getShopcatSuggestionList() {
return shopcatSuggestionList;
}
public void ajaxShopcatSuggest(AjaxBehaviorEvent event) {
this.shopcatName = this.shopcatSuggestion;
}
}

@ -100,7 +100,6 @@ public class IngredientUI implements IngredientIF {
* @see #getAmount * @see #getAmount
*/ */
public String getDisplayAmount() { public String getDisplayAmount() {
// TODO
Double amt = ingredient.getAmount(); Double amt = ingredient.getAmount();
if (amt == null) { if (amt == null) {
return ""; return "";
@ -120,8 +119,7 @@ public class IngredientUI implements IngredientIF {
if (amount.isBlank()) { if (amount.isBlank()) {
ingredient.setAmount(null); ingredient.setAmount(null);
} }
IngredientDigester digester = new IngredientDigester(); Double[] amt = IngredientDigester.digestAmount(amount);
Double[] amt = digester.digestAmount(amount);
ingredient.setAmount(amt[0]); ingredient.setAmount(amt[0]);
ingredient.setRangeamount(amt[1]); ingredient.setRangeamount(amt[1]);
} }

@ -83,4 +83,12 @@ public class JSFUtils {
return (FacesContext.getCurrentInstance() return (FacesContext.getCurrentInstance()
.getExternalContext().getFlash()); .getExternalContext().getFlash());
} }
public static Object getFlash(String key) {
return flashScope().get(key);
}
public static void putFlash(String key, Object value) {
flashScope().put(key, value);
}
} }

@ -2,8 +2,11 @@ package com.mousetech.gourmetj;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@ -17,6 +20,8 @@ import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.servlet.http.Part; import javax.servlet.http.Part;
import org.apache.commons.lang3.StringUtils;
import org.primefaces.PrimeFaces;
import org.primefaces.event.FileUploadEvent; import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile; import org.primefaces.model.UploadedFile;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -30,7 +35,6 @@ import com.mousetech.gourmetj.persistence.model.Recipe;
import com.mousetech.gourmetj.persistence.model.Shopcat; import com.mousetech.gourmetj.persistence.model.Shopcat;
import com.mousetech.gourmetj.persistence.service.RecipeService; import com.mousetech.gourmetj.persistence.service.RecipeService;
import com.mousetech.gourmetj.springweb.PictureController; import com.mousetech.gourmetj.springweb.PictureController;
import com.mousetech.gourmetj.IngredientDigester;
/** /**
* Backing bean for display/edit recipe detail * Backing bean for display/edit recipe detail
@ -218,8 +222,7 @@ public class RecipeDetailBean implements Serializable {
private void init() { private void init() {
this.recipe = userSession.getRecipe(); this.recipe = userSession.getRecipe();
log.info("Using recipe: " + this.recipe);
log.info("Using recipe: " + this.recipe );
/** /**
* For "create new, this recipe is a blank constructed * For "create new, this recipe is a blank constructed
* and passed from main page. For Detail display, it's * and passed from main page. For Detail display, it's
@ -243,7 +246,7 @@ public class RecipeDetailBean implements Serializable {
getIngredients().setWrappedData( getIngredients().setWrappedData(
buildIngredientFacade(recipe.getIngredientHash())); buildIngredientFacade(recipe.getIngredientHash()));
log.info("Set recipe: " + this.recipe ); log.info("Set recipe: " + this.recipe);
} }
/** /**
@ -257,7 +260,7 @@ public class RecipeDetailBean implements Serializable {
if (recipe == null) { if (recipe == null) {
return null; return null;
} }
Set<Category> cList = recipe.getCategories(); Set<Category> cList = recipe.getCategories();
StringBuffer sb = new StringBuffer(35); StringBuffer sb = new StringBuffer(35);
boolean first = true; boolean first = true;
@ -438,6 +441,64 @@ public class RecipeDetailBean implements Serializable {
} }
} }
// =====
@Inject
EditShopcatBean editShopcatBean;
public void ajaxEditShopcat(IngredientUI item) {
// Map<String, Object> options = new HashMap<>();
// options.put("resizable", false);
// TODO: Reject if ingkey is empty/null
editShopcatBean.setIngkey(item.getIngkey());
editShopcatBean.setShopcatName(item.getShopCat());
// if ( ! StringUtils.isBlank(key) ) {
// PrimeFaces.current().dialog().openDynamic("editShopcat");
// }
}
public void doUpdateShopcat() {
final String key = editShopcatBean.getIngkey();
if ( StringUtils.isBlank(key)) {
return; // Do not set category if no ingKey
}
final String catname = editShopcatBean.getShopcatName();
Shopcat sc = this.recipeService
.findShopcatForIngredientKey(catname);
if (sc == null) {
sc = new Shopcat();
sc.setIngkey(key);
sc.setShopcategory(catname);
} else {
if (catname.equals(sc.getShopcategory())) {
// No change. Do nothing.
return;
}
}
if ( StringUtils.isBlank(catname)) {
this.recipeService.deleteShopcat(sc);
} else {
this.recipeService.saveShopcat(sc);
}
updateDisplayedShopcats(key, sc);
}
/**
* When Shopcat name changes, update the Ingredients.
* In detailEdit, an AJAX "render" will then update
* the display. In recipeDetails, nothing actually shows.
*/
private void updateDisplayedShopcats(String key, Shopcat sc) {
List<IngredientUI> ingList = this.getWrappedIngredients();
for (IngredientUI ingUI: ingList ) {
if ( key.equals(ingUI.getIngkey())) {
ingUI.setShopCat(sc);
}
}
}
/** /**
* Bulk add for ingredients. Looks for long input and if * Bulk add for ingredients. Looks for long input and if
* found, tries to split it up and add as multiple * found, tries to split it up and add as multiple
@ -581,7 +642,7 @@ public class RecipeDetailBean implements Serializable {
* it. * it.
*/ */
private boolean saveIngredients() { private boolean saveIngredients() {
if ( ! updateIngredientList()) { if (!updateIngredientList()) {
return false; return false;
} }
updateRecipeCategories(recipe, category); updateRecipeCategories(recipe, category);
@ -596,8 +657,8 @@ public class RecipeDetailBean implements Serializable {
iList.clear(); iList.clear();
for (IngredientUI iui : saveIng) { for (IngredientUI iui : saveIng) {
Ingredient ing = iui.getIngredient(); Ingredient ing = iui.getIngredient();
ing.setRecipe(recipe); ing.setRecipe(recipe);
if ( ! updateShopcat(iui) ) { if (!updateShopcat(iui)) {
return false; return false;
} }
iList.add(ing); iList.add(ing);
@ -623,7 +684,6 @@ public class RecipeDetailBean implements Serializable {
} }
} }
/** /**
* Update shopcat for Ingredient. * Update shopcat for Ingredient.
* *
@ -633,17 +693,19 @@ public class RecipeDetailBean implements Serializable {
private boolean updateShopcat(IngredientUI ingUI) { private boolean updateShopcat(IngredientUI ingUI) {
final Ingredient ing = ingUI.getIngredient(); final Ingredient ing = ingUI.getIngredient();
final String ingKey = ing.getIngkey(); final String ingKey = ing.getIngkey();
if ( (ingKey == null) || (ingKey.isBlank())) { if ((ingKey == null) || (ingKey.isBlank())) {
ing.setIngkey(null); ing.setIngkey(null);
ing.setShopCat(null); ing.setShopCat(null);
return true; return true;
} }
Shopcat scat = recipeService.findShopcatForIngredientKey(ingKey); Shopcat scat = recipeService
if ( scat == null ) { .findShopcatForIngredientKey(ingKey);
if (scat == null) {
JSFUtils.addErrorMessage( JSFUtils.addErrorMessage(
"No Shopping Category is defined for Ingredient Key "+ ingKey); "No Shopping Category is defined for Ingredient Key "
+ ingKey);
return false; return false;
} }
ing.setShopCat(scat); ing.setShopCat(scat);
return true; return true;
@ -808,9 +870,10 @@ public class RecipeDetailBean implements Serializable {
public void ajaxUpdateShopcat(IngredientUI item) { public void ajaxUpdateShopcat(IngredientUI item) {
log.warn("SHOPCAT2 "); log.warn("SHOPCAT2 ");
updateShopcat(item);; updateShopcat(item);
;
} }
// *** // ***
public String editDescription() { public String editDescription() {

@ -1,25 +1,30 @@
package com.mousetech.gourmetj; package com.mousetech.gourmetj;
import javax.inject.Qualifier;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.web.filter.HiddenHttpMethodFilter; import org.springframework.http.HttpStatus;
@SpringBootApplication @SpringBootApplication
@EntityScan(value = {"com.mousetech.gourmetj.persistence.model"}) @EntityScan(value = {
"com.mousetech.gourmetj.persistence.model" })
public class SpringPrimeFacesApplication { public class SpringPrimeFacesApplication {
public static void main(String[] args) { final String errorPage = "/error/error.html";
SpringApplication.run(SpringPrimeFacesApplication.class, args);
} public static void main(String[] args) {
SpringApplication.run(SpringPrimeFacesApplication.class,
args);
}
@Bean @Bean
public ServletContextInitializer initializer() { public ServletContextInitializer initializer() {
return new ServletContextInitializer() { return new ServletContextInitializer() {
@ -39,4 +44,20 @@ public class SpringPrimeFacesApplication {
} }
}; };
} }
@Bean
public ErrorPageRegistrar errorPageRegistrar() {
return new ErrorPageRegistrar() {
@Override
public void registerErrorPages(
ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(
HttpStatus.NOT_FOUND, errorPage));
registry.addErrorPages(new ErrorPage(
HttpStatus.INTERNAL_SERVER_ERROR,
errorPage));
}
};
}
} }

@ -88,6 +88,15 @@ public class RecipeService implements Serializable {
public Shopcat findShopcatForIngredientKey(String ingkey) { public Shopcat findShopcatForIngredientKey(String ingkey) {
return shopcatRepository.findShopcatByIngkey(ingkey); return shopcatRepository.findShopcatByIngkey(ingkey);
} }
public void saveShopcat(Shopcat sc) {
shopcatRepository.save(sc);
}
public void deleteShopcat(Shopcat sc) {
shopcatRepository.delete(sc);
}
/** /**
* CategoryService as a sub-function of RecipeService * CategoryService as a sub-function of RecipeService

@ -1,30 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns:f="http://xmlns.jcp.org/jsf/core" <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
xmlns:tc="http://myfaces.apache.org/tobago/component"
> >
<f:view> <head></head>
<h:head> <body>
<title><ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert></title> <ui:composition>
<link rel="icon" type="image/vnd.microsoft.icon" <f:view>
href="#{pageContext.contextPath}/favicon.ico" <h:head>
/> <title><ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert></title>
<link rel="icon" type="image/vnd.microsoft.icon"
<h:outputStylesheet name="css/style.css" /> href="#{pageContext.contextPath}/favicon.ico"
</h:head> />
<h:body> <h:outputStylesheet name="css/style.css" />
<h1> </h:head>
<ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert> <h:body>
</h1> <h1>
<ui:insert name="content"> <ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert>
<ui:include src="content.xhtml" /> </h1>
</ui:insert> <ui:insert name="content">
<ui:include src="content.xhtml" />
</ui:insert>
(C) 2021 Tim Holloway, Licensed under the <a (C) 2021 Tim Holloway, Licensed under the <a
href="http://www.apache.org/licenses/LICENSE-2.0" href="http://www.apache.org/licenses/LICENSE-2.0"
>Apache License, Version 2.0</a>. >Apache License, Version 2.0</a>.
<p>Based on Gourmet Recipe Manager by T. Hinkle</p> <p>Based on Gourmet Recipe Manager by T. Hinkle</p>
</h:body> </h:body>
</f:view> </f:view>
</ui:composition> </ui:composition>
</body>
</html>

@ -1,14 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui:composition template="/WEB-INF/layout/layout.xhtml" <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui" xmlns:p="http://primefaces.org/ui"
xmlns:c="http://xmlns.jcp.org/jstl" xmlns:c="http://xmlns.jcp.org/jstl"
> >
<ui:define name="title">Gourmet Recipe Manager</ui:define> <head></head>
<ui:define name="content"> <body>
<style> <ui:composition template="/WEB-INF/layout/layout.xhtml">
<ui:define name="title">Gourmet Recipe Manager</ui:define>
<ui:define name="content">
<style>
.ingSel { .ingSel {
width: 3em; width: 3em;
text-align: center; text-align: center;
@ -24,304 +28,333 @@
text-align: left; text-align: left;
} }
</style> </style>
<h:messages id="messages" /> <h:messages id="messages" />
<p:panel id="editorPanel" <p:panel id="editorPanel"
header="#{recipeDetailBean.recipe.title}" header="#{recipeDetailBean.recipe.title}"
> >
<h:form id="form1" enctype="multipart/form-data"> <h:form id="form1" enctype="multipart/form-data">
<p:tabView id="tabGroupClient" orientation="left" <p:tabView id="tabGroupClient"
activeIndex="#{userSession.detailTab}" orientation="left"
> activeIndex="#{userSession.detailTab}"
<p:tab id="overviewTab" title="Description"> >
<p:panelGrid columns="2"> <p:tab id="overviewTab"
<f:facet name="header">Description</f:facet> title="Description"
<p:outputLabel for="@next" >
value="Title" <p:panelGrid columns="2">
/> <f:facet name="header">Description</f:facet>
<p:inputText id="rtitle" size="45" <p:outputLabel for="@next"
required="true" focus="true" value="Title"
placeholder="A recipe title is required."
value="#{recipeDetailBean.recipe.title}"
>
<f:ajax execute="rtitle"
render="editorPanel"
/>
</p:inputText>
<p:outputLabel for="@next"
value="Category"
/>
<p:inputText id="rcategory"
label="Category"
value="#{recipeDetailBean.category}"
tip="One or more categories, separated by commas (ex: Entree, Soup)"
/>
<p:commandButton
value="&lt;- Suggest"
>
<f:ajax execute="rcategory bxCat"
listener="#{recipeDetailBean.ajaxSuggestCategory}"
render="rcategory"
/>
</p:commandButton>
<p:selectOneMenu id="bxCat"
value="#{recipeDetailBean.catToAdd}"
tip="Recipe category suggestions, based on previous selections"
>
<f:selectItems
value="#{recipeDetailBean.suggestCategory}"
/> />
</p:selectOneMenu> <p:inputText id="rtitle"
<p:outputLabel for="@next" size="45" required="true"
value="Cuisine" focus="true"
/> placeholder="A recipe title is required."
<p:autoComplete id="rcuisine" value="#{recipeDetailBean.recipe.title}"
value="#{recipeDetailBean.recipe.cuisine}" >
completeMethod="#{recipeDetailBean.cuisineSuggestions}" <f:ajax execute="rtitle"
/> render="editorPanel"
<p:outputLabel for="@next" />
value="Rating" </p:inputText>
/> <p:outputLabel for="@next"
<p:rating id="rrating" max="10" value="Category"
value="#{recipeDetailBean.recipe.rating}"
/>
<p:outputLabel for="@next"
value="Source"
/>
<p:inputText id="rsource" size="45"
value="#{recipeDetailBean.recipe.source}"
/>
<p:outputLabel for="@next"
value="URL"
/>
<p:inputText id="rurl" size="45"
value="#{recipeDetailBean.recipe.link}"
/>
<p:outputLabel for="@next"
value="Description"
/>
<p:inputTextarea id="description"
rows="10" cols="45"
value="#{recipeDetailBean.recipe.description}"
/>
<p:panel id="picPanel">
<img id="bigPix"
src="/img/picture/?dt=#{recipeDetailBean.currentTime}"
/> />
</p:panel> <p:inputText id="rcategory"
<p:fileUpload id="ctlUpload" label="Category"
label="Upload Image" value="#{recipeDetailBean.category}"
fileUploadListener="#{recipeDetailBean.ajaxUploadImage}" tip="One or more categories, separated by commas (ex: Entree, Soup)"
global="true" mode="advanced"
multiple="false"
update=":messages picPanel"
auto="true" sizeLimit="1000000"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
/>
<p:commandButton id="ctlDelImg"
value="Delete Image"
>
<f:ajax
listener="#{recipeDetailBean.ajaxDeleteImage}"
render="picPanel"
immediate="true"
/> />
</p:commandButton> <p:commandButton
</p:panelGrid> value="&lt;- Suggest"
</p:tab>
<p:tab id="ingredientsTab"
title="Ingredients"
>
<p:panel id="pnlIngredients">
<f:facet name="header">Ingredients</f:facet>
<h:panelGroup id="ingButtons">
<p:commandButton value="Up"
disabled="#{not recipeDetailBean.moveUpAble}"
id="ctlUp"
> >
<f:ajax <f:ajax
listener="#{recipeDetailBean.ajaxMoveUp}" execute="rcategory bxCat"
execute="ingredientTable" listener="#{recipeDetailBean.ajaxSuggestCategory}"
render="ingredientTable" render="rcategory"
/> />
</p:commandButton> </p:commandButton>
<p:commandButton value="Down" <p:selectOneMenu id="bxCat"
disabled="#{not recipeDetailBean.moveDownAble}" value="#{recipeDetailBean.catToAdd}"
id="ctlDown" tip="Recipe category suggestions, based on previous selections"
> >
<f:ajax <f:selectItems
listener="#{recipeDetailBean.ajaxMoveDown}" value="#{recipeDetailBean.suggestCategory}"
execute="ingredientTable"
render="ingredientTable"
/> />
</p:commandButton> </p:selectOneMenu>
<p:button value="Add Group" <p:outputLabel for="@next"
disabled="true" value="Cuisine"
/> />
<p:button <p:autoComplete id="rcuisine"
value="Add Recipe As Ingredient" value="#{recipeDetailBean.recipe.cuisine}"
disabled="true" completeMethod="#{recipeDetailBean.cuisineSuggestions}"
/> />
<p:button <p:outputLabel for="@next"
value="Import Ingredients" value="Rating"
disabled="true" />
<p:rating id="rrating" max="10"
value="#{recipeDetailBean.recipe.rating}"
/> />
<p:button value="Paste" /> <p:outputLabel for="@next"
<p:commandButton value="Delete" value="Source"
id="ctlDelete" />
disabled="not #{recipeDetailBean.selectionActive}" <p:inputText id="rsource"
size="45"
value="#{recipeDetailBean.recipe.source}"
/>
<p:outputLabel for="@next"
value="URL"
/>
<p:inputText id="rurl" size="45"
value="#{recipeDetailBean.recipe.link}"
/>
<p:outputLabel for="@next"
value="Description"
/>
<p:inputTextarea id="description"
rows="10" cols="45"
value="#{recipeDetailBean.recipe.description}"
/>
<p:panel id="picPanel">
<img id="bigPix"
src="/img/picture/?dt=#{recipeDetailBean.currentTime}"
/>
</p:panel>
<p:fileUpload id="ctlUpload"
label="Upload Image"
fileUploadListener="#{recipeDetailBean.ajaxUploadImage}"
global="true" mode="advanced"
multiple="false"
update=":messages picPanel"
auto="true"
sizeLimit="1000000"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
/>
<p:commandButton id="ctlDelImg"
value="Delete Image"
> >
<f:ajax <f:ajax
listener="#{recipeDetailBean.ajaxDeleteItems}" listener="#{recipeDetailBean.ajaxDeleteImage}"
render="picPanel"
immediate="true" immediate="true"
render="ingredientTable"
/> />
</p:commandButton> </p:commandButton>
</h:panelGroup> </p:panelGrid>
<p:dataTable id="ingredientTable" </p:tab>
style="width: 100%; height: 420px; margin-top: 8px" <p:tab id="ingredientsTab"
value="#{recipeDetailBean.ingredients}" title="Ingredients"
scrollable="true" >
scrollHeight="380" var="item" <p:panel id="pnlIngredients">
> <f:facet name="header">Ingredients</f:facet>
<p:column label="Sel." <h:panelGroup id="ingButtons">
align="center" <p:commandButton value="Up"
style="width: 2em" disabled="#{not recipeDetailBean.moveUpAble}"
> id="ctlUp"
<p:selectBooleanCheckbox >
id="selected" <f:ajax
value="#{item.selected}" listener="#{recipeDetailBean.ajaxMoveUp}"
execute="ingredientTable"
render="ingredientTable"
/>
</p:commandButton>
<p:commandButton value="Down"
disabled="#{not recipeDetailBean.moveDownAble}"
id="ctlDown"
>
<f:ajax
listener="#{recipeDetailBean.ajaxMoveDown}"
execute="ingredientTable"
render="ingredientTable"
/>
</p:commandButton>
<p:button value="Add Group"
disabled="true"
/>
<p:button
value="Add Recipe As Ingredient"
disabled="true"
/>
<p:button
value="Import Ingredients"
disabled="true"
/>
<p:button value="Paste" />
<p:commandButton
value="Delete"
id="ctlDelete"
disabled="not #{recipeDetailBean.selectionActive}"
> >
<f:ajax immediate="true" <f:ajax
render="pnlIngredients" listener="#{recipeDetailBean.ajaxDeleteItems}"
immediate="true"
render="ingredientTable"
/> />
</p:selectBooleanCheckbox> </p:commandButton>
</p:column> </h:panelGroup>
<p:column style="width: 3.6em"> <p:dataTable id="ingredientTable"
<f:facet name="header"> style="width: 100%; height: 420px; margin-top: 8px"
value="#{recipeDetailBean.ingredients}"
scrollable="true"
scrollHeight="380" var="item"
>
<p:column label="Sel."
align="center"
style="width: 2em"
>
<p:selectBooleanCheckbox
id="selected"
value="#{item.selected}"
>
<f:ajax
immediate="true"
render="pnlIngredients"
/>
</p:selectBooleanCheckbox>
</p:column>
<p:column
style="width: 3.6em"
>
<f:facet name="header">
Amt. Amt.
</f:facet> </f:facet>
<p:inputText id="ingAmt" <p:inputText id="ingAmt"
size="3" size="3"
value="#{item.displayAmount}" value="#{item.displayAmount}"
style="text-align: right" style="text-align: right"
rendered="#{not item.ingGroup}" rendered="#{not item.ingGroup}"
> >
</p:inputText> </p:inputText>
</p:column> </p:column>
<p:column style="width: 7em"> <p:column style="width: 7em">
<f:facet name="header"> <f:facet name="header">
Units Units
</f:facet> </f:facet>
<p:inputText id="ingUnit" <p:inputText id="ingUnit"
value="#{item.unit}" value="#{item.unit}"
size="10" size="10"
rendered="#{not item.ingGroup}" rendered="#{not item.ingGroup}"
> >
</p:inputText> </p:inputText>
</p:column> </p:column>
<p:column style="width: 26em"> <p:column style="width: 26em">
<f:facet name="header"> <f:facet name="header">
Item Item
</f:facet> </f:facet>
<p:inputText id="ingItem" <p:inputText id="ingItem"
size="42" size="42"
value="#{item.item}" value="#{item.item}"
>
</p:inputText>
</p:column>
<p:column label="Optional"
align="center"
styleClass="ingSel"
> >
</p:inputText> <f:facet name="header">
</p:column>
<p:column label="Optional"
align="center"
styleClass="ingSel"
>
<f:facet name="header">
Opt. Opt.
</f:facet> </f:facet>
<p:selectBooleanCheckbox <p:selectBooleanCheckbox
id="ingOpt" id="ingOpt"
value="#{item.optionalCB}" value="#{item.optionalCB}"
rendered="#{not item.ingGroup}" rendered="#{not item.ingGroup}"
/> />
</p:column> </p:column>
<p:column style="width: 13em"> <p:column style="width: 13em">
<f:facet name="header"> <f:facet name="header">
Ing. Key Ing. Key
</f:facet> </f:facet>
<p:inputText id="ingKey" <p:inputText id="ingKey"
value="#{item.ingkey}" value="#{item.ingkey}"
size="20" size="20"
rendered="#{not item.ingGroup}" rendered="#{not item.ingGroup}"
> >
<f:ajax event="change" <f:ajax
listener="#{recipeDetailBean.ajaxUpdateShopcat(item)}" event="change"
render="shopCat" listener="#{recipeDetailBean.ajaxUpdateShopcat(item)}"
/> render="shopCat"
</p:inputText> />
</p:column> </p:inputText>
<p:column> </p:column>
<f:facet name="header"> <p:column>
<f:facet name="header">
Shop. Cat. Shop. Cat.
</f:facet> </f:facet>
<h:outputText id="shopCat" <h:outputText
value="#{item.shopCat}" id="shopCat"
rendered="#{not item.ingGroup}" value="#{item.shopCat}"
rendered="#{not item.ingGroup}"
/>
<p:commandButton
id="eShopcat"
value="E"
action="#{recipeDetailBean.ajaxEditShopcat(item)}"
update="editShopcatDlg"
oncomplete="PF('editShopcatDlg').show()"
>
</p:commandButton>
</p:column>
</p:dataTable>
<h:panelGroup id="pnlIng">
<p:remoteCommand
name="ingButton"
action="#{recipeDetailBean.doAddIngredient}"
process="@this ctlAddIngTxt"
update="pnlIngredients"
/> />
</p:column> <p:outputLabel for="@next"
</p:dataTable> value="Add Ingredient: "
<h:panelGroup id="pnlIng"> />
<p:remoteCommand name="ingButton" <p:inputTextarea
action="#{recipeDetailBean.doAddIngredient}" id="ctlAddIngTxt"
process="@this ctlAddIngTxt" focus="true" rows="1"
update="pnlIngredients" cols="65"
/> value="#{recipeDetailBean.ingredientText}"
<p:outputLabel for="@next" title="You can paste in multiple ingredients here!"
value="Add Ingredient: " onkeydown="if (event.keyCode === 13) { ingButton(); this.focus(); return false; }"
/> />
<p:inputTextarea <p:commandButton
id="ctlAddIngTxt" id="ctlAddIng"
focus="true" rows="1" value="+ Add"
cols="65" onclick="ingButton(); return false;"
value="#{recipeDetailBean.ingredientText}" >
title="You can paste in multiple ingredients here!" </p:commandButton>
onkeydown="if (event.keyCode === 13) { ingButton(); this.focus(); return false; }" </h:panelGroup>
/> </p:panel>
<p:commandButton id="ctlAddIng" </p:tab>
value="+ Add" <p:tab id="instructionsTab"
onclick="ingButton(); return false;" title="Instructions"
> >
</p:commandButton> <p:panel header="Instructions">
</h:panelGroup> <div id="insection">
</p:panel> <p:textEditor
</p:tab> id="ctlInstructions"
<p:tab id="instructionsTab" height="320"
title="Instructions" escape="false"
> value="#{recipeDetailBean.recipe.instructions}"
<p:panel header="Instructions"> />
<div id="insection"> </div>
<p:textEditor </p:panel>
id="ctlInstructions" </p:tab>
<p:tab id="notesTab" title="Notes">
<p:panel header="Notes">
<p:textEditor id="ctlNotes"
height="320" escape="false" height="320" escape="false"
value="#{recipeDetailBean.recipe.instructions}" value="#{recipeDetailBean.recipe.modifications}"
/> />
</div> </p:panel>
</p:panel> </p:tab>
</p:tab> </p:tabView>
<p:tab id="notesTab" title="Notes"> <p:commandButton id="doSave" value="Save"
<p:panel header="Notes"> disabled="{not recipeDetailBean.dirty}"
<p:textEditor id="ctlNotes" action="#{recipeDetailBean.doSave}"
height="320" escape="false" />
value="#{recipeDetailBean.recipe.modifications}" <p:commandButton id="doCancel" value="Cancel"
/> immediate="true" action="/main.jsf"
</p:panel> />
</p:tab> </h:form>
</p:tabView> </p:panel>
<p:commandButton id="doSave" value="Save" <p:dialog id="editShopcatDlg" widgetVar="editShopcatDlg">
disabled="{not recipeDetailBean.dirty}" <ui:include src="editShopcat.xhtml" />
action="#{recipeDetailBean.doSave}" </p:dialog>
/> </ui:define>
<p:commandButton id="doCancel" value="Cancel" </ui:composition>
immediate="true" action="/main.jsf" </body>
/> </html>
</h:form>
</p:panel>
</ui:define>
</ui:composition>

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
>
<h:head>
<title>Shopping Category</title>
<style type="text/css">
html {
font-size: 14px;
}
</style>
</h:head>
<h:body>
<ui:component>
<h:form id="frmShopcat">
<p:panelGrid columns="1">
<div>Ingredient key:
#{editShopcatBean.ingkey}
</div>
<p:outputLabel for="@next"
value="Category Name" />
<p:inputText id="ctlShopcat"
value="#{editShopcatBean.shopcatName}"
>
</p:inputText>
<h:outputText
value="suggestion:" />
<p:selectOneMenu
id="ctlShopcatMenu"
value="#{editShopcatBean.shopcatSuggestion}"
>
<f:selectItems
value="#{editShopcatBean.shopcatSuggestionList}" />
<p:ajax event="change"
listener="#{editShopcatBean.ajaxShopcatSuggest}"
update="ctlShopcat" />
</p:selectOneMenu>
<p:panelGrid columns="2"
style="width: 100%"
>
<p:commandButton
id="scDlgOK" value="OK"
style="width: 6em"
action="#{recipeDetailBean.doUpdateShopcat}"
update="form1:tabGroupClient:ingredientTable"
oncomplete="PF('editShopcatDlg').hide()" />
<p:commandButton
id="scDlgCan" value="Cancel"
style="width: 6em"
onclick="PF('editShopcatDlg').hide()" />
</p:panelGrid>
</p:panelGrid>
</h:form>
</ui:component>
</h:body>
</html>

@ -0,0 +1,9 @@
<html>
<head>
<title>ERROR</title>
</head>
<body>
<h1>Uh-oh!</h1>
An error happened.
</body>
</html>
Loading…
Cancel
Save