Editable shopping category
This commit is contained in:
parent
e4da9a6a71
commit
ce0f354f9a
5
pom.xml
5
pom.xml
|
@ -88,6 +88,11 @@
|
|||
<version>2.3.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-jasper</artifactId>
|
||||
|
|
106
src/main/java/com/mousetech/gourmetj/EditShopcatBean.java
Normal file
106
src/main/java/com/mousetech/gourmetj/EditShopcatBean.java
Normal file
|
@ -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
|
||||
*/
|
||||
public String getDisplayAmount() {
|
||||
// TODO
|
||||
Double amt = ingredient.getAmount();
|
||||
if (amt == null) {
|
||||
return "";
|
||||
|
@ -120,8 +119,7 @@ public class IngredientUI implements IngredientIF {
|
|||
if (amount.isBlank()) {
|
||||
ingredient.setAmount(null);
|
||||
}
|
||||
IngredientDigester digester = new IngredientDigester();
|
||||
Double[] amt = digester.digestAmount(amount);
|
||||
Double[] amt = IngredientDigester.digestAmount(amount);
|
||||
ingredient.setAmount(amt[0]);
|
||||
ingredient.setRangeamount(amt[1]);
|
||||
}
|
||||
|
|
|
@ -83,4 +83,12 @@ public class JSFUtils {
|
|||
return (FacesContext.getCurrentInstance()
|
||||
.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.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -17,6 +20,8 @@ import javax.inject.Inject;
|
|||
import javax.inject.Named;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.primefaces.PrimeFaces;
|
||||
import org.primefaces.event.FileUploadEvent;
|
||||
import org.primefaces.model.UploadedFile;
|
||||
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.service.RecipeService;
|
||||
import com.mousetech.gourmetj.springweb.PictureController;
|
||||
import com.mousetech.gourmetj.IngredientDigester;
|
||||
|
||||
/**
|
||||
* Backing bean for display/edit recipe detail
|
||||
|
@ -218,8 +222,7 @@ public class RecipeDetailBean implements Serializable {
|
|||
private void init() {
|
||||
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
|
||||
* and passed from main page. For Detail display, it's
|
||||
|
@ -243,7 +246,7 @@ public class RecipeDetailBean implements Serializable {
|
|||
|
||||
getIngredients().setWrappedData(
|
||||
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) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Set<Category> cList = recipe.getCategories();
|
||||
StringBuffer sb = new StringBuffer(35);
|
||||
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
|
||||
* found, tries to split it up and add as multiple
|
||||
|
@ -581,7 +642,7 @@ public class RecipeDetailBean implements Serializable {
|
|||
* it.
|
||||
*/
|
||||
private boolean saveIngredients() {
|
||||
if ( ! updateIngredientList()) {
|
||||
if (!updateIngredientList()) {
|
||||
return false;
|
||||
}
|
||||
updateRecipeCategories(recipe, category);
|
||||
|
@ -596,8 +657,8 @@ public class RecipeDetailBean implements Serializable {
|
|||
iList.clear();
|
||||
for (IngredientUI iui : saveIng) {
|
||||
Ingredient ing = iui.getIngredient();
|
||||
ing.setRecipe(recipe);
|
||||
if ( ! updateShopcat(iui) ) {
|
||||
ing.setRecipe(recipe);
|
||||
if (!updateShopcat(iui)) {
|
||||
return false;
|
||||
}
|
||||
iList.add(ing);
|
||||
|
@ -623,7 +684,6 @@ public class RecipeDetailBean implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update shopcat for Ingredient.
|
||||
*
|
||||
|
@ -633,17 +693,19 @@ public class RecipeDetailBean implements Serializable {
|
|||
private boolean updateShopcat(IngredientUI ingUI) {
|
||||
final Ingredient ing = ingUI.getIngredient();
|
||||
final String ingKey = ing.getIngkey();
|
||||
if ( (ingKey == null) || (ingKey.isBlank())) {
|
||||
if ((ingKey == null) || (ingKey.isBlank())) {
|
||||
ing.setIngkey(null);
|
||||
ing.setShopCat(null);
|
||||
return true;
|
||||
}
|
||||
Shopcat scat = recipeService.findShopcatForIngredientKey(ingKey);
|
||||
if ( scat == null ) {
|
||||
Shopcat scat = recipeService
|
||||
.findShopcatForIngredientKey(ingKey);
|
||||
if (scat == null) {
|
||||
JSFUtils.addErrorMessage(
|
||||
"No Shopping Category is defined for Ingredient Key "+ ingKey);
|
||||
"No Shopping Category is defined for Ingredient Key "
|
||||
+ ingKey);
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
ing.setShopCat(scat);
|
||||
return true;
|
||||
|
@ -808,9 +870,10 @@ public class RecipeDetailBean implements Serializable {
|
|||
|
||||
public void ajaxUpdateShopcat(IngredientUI item) {
|
||||
log.warn("SHOPCAT2 ");
|
||||
updateShopcat(item);;
|
||||
updateShopcat(item);
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
// ***
|
||||
|
||||
public String editDescription() {
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
package com.mousetech.gourmetj;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
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.context.annotation.Bean;
|
||||
import org.springframework.web.filter.HiddenHttpMethodFilter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
@SpringBootApplication
|
||||
@EntityScan(value = {"com.mousetech.gourmetj.persistence.model"})
|
||||
@EntityScan(value = {
|
||||
"com.mousetech.gourmetj.persistence.model" })
|
||||
public class SpringPrimeFacesApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringPrimeFacesApplication.class, args);
|
||||
}
|
||||
|
||||
final String errorPage = "/error/error.html";
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringPrimeFacesApplication.class,
|
||||
args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletContextInitializer initializer() {
|
||||
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) {
|
||||
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
|
||||
|
|
|
@ -1,30 +1,36 @@
|
|||
<?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:h="http://java.sun.com/jsf/html"
|
||||
xmlns:tc="http://myfaces.apache.org/tobago/component"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
>
|
||||
<f:view>
|
||||
<h:head>
|
||||
<title><ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert></title>
|
||||
<link rel="icon" type="image/vnd.microsoft.icon"
|
||||
href="#{pageContext.contextPath}/favicon.ico"
|
||||
/>
|
||||
|
||||
<h:outputStylesheet name="css/style.css" />
|
||||
</h:head>
|
||||
<h:body>
|
||||
<h1>
|
||||
<ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert>
|
||||
</h1>
|
||||
<ui:insert name="content">
|
||||
<ui:include src="content.xhtml" />
|
||||
</ui:insert>
|
||||
<head></head>
|
||||
<body>
|
||||
<ui:composition>
|
||||
<f:view>
|
||||
<h:head>
|
||||
<title><ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert></title>
|
||||
<link rel="icon" type="image/vnd.microsoft.icon"
|
||||
href="#{pageContext.contextPath}/favicon.ico"
|
||||
/>
|
||||
<h:outputStylesheet name="css/style.css" />
|
||||
</h:head>
|
||||
<h:body>
|
||||
<h1>
|
||||
<ui:insert name="title">Gourmet Recipe Manager (web version)</ui:insert>
|
||||
</h1>
|
||||
<ui:insert name="content">
|
||||
<ui:include src="content.xhtml" />
|
||||
</ui:insert>
|
||||
|
||||
(C) 2021 Tim Holloway, Licensed under the <a
|
||||
href="http://www.apache.org/licenses/LICENSE-2.0"
|
||||
>Apache License, Version 2.0</a>.
|
||||
href="http://www.apache.org/licenses/LICENSE-2.0"
|
||||
>Apache License, Version 2.0</a>.
|
||||
<p>Based on Gourmet Recipe Manager by T. Hinkle</p>
|
||||
</h:body>
|
||||
</f:view>
|
||||
</ui:composition>
|
||||
</h:body>
|
||||
</f:view>
|
||||
</ui:composition>
|
||||
</body>
|
||||
</html>
|
|
@ -1,14 +1,18 @@
|
|||
<?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:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
xmlns:c="http://xmlns.jcp.org/jstl"
|
||||
>
|
||||
<ui:define name="title">Gourmet Recipe Manager</ui:define>
|
||||
<ui:define name="content">
|
||||
<style>
|
||||
<head></head>
|
||||
<body>
|
||||
<ui:composition template="/WEB-INF/layout/layout.xhtml">
|
||||
<ui:define name="title">Gourmet Recipe Manager</ui:define>
|
||||
<ui:define name="content">
|
||||
<style>
|
||||
.ingSel {
|
||||
width: 3em;
|
||||
text-align: center;
|
||||
|
@ -24,304 +28,333 @@
|
|||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
<h:messages id="messages" />
|
||||
<p:panel id="editorPanel"
|
||||
header="#{recipeDetailBean.recipe.title}"
|
||||
>
|
||||
<h:form id="form1" enctype="multipart/form-data">
|
||||
<p:tabView id="tabGroupClient" orientation="left"
|
||||
activeIndex="#{userSession.detailTab}"
|
||||
>
|
||||
<p:tab id="overviewTab" title="Description">
|
||||
<p:panelGrid columns="2">
|
||||
<f:facet name="header">Description</f:facet>
|
||||
<p:outputLabel for="@next"
|
||||
value="Title"
|
||||
/>
|
||||
<p:inputText id="rtitle" size="45"
|
||||
required="true" focus="true"
|
||||
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="<- 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:outputLabel for="@next"
|
||||
value="Cuisine"
|
||||
/>
|
||||
<p:autoComplete id="rcuisine"
|
||||
value="#{recipeDetailBean.recipe.cuisine}"
|
||||
completeMethod="#{recipeDetailBean.cuisineSuggestions}"
|
||||
/>
|
||||
<p:outputLabel for="@next"
|
||||
value="Rating"
|
||||
/>
|
||||
<p:rating id="rrating" max="10"
|
||||
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: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
|
||||
listener="#{recipeDetailBean.ajaxDeleteImage}"
|
||||
render="picPanel"
|
||||
immediate="true"
|
||||
/>
|
||||
</p:commandButton>
|
||||
</p:panelGrid>
|
||||
</p:tab>
|
||||
<p:tab id="ingredientsTab"
|
||||
title="Ingredients"
|
||||
<h:messages id="messages" />
|
||||
<p:panel id="editorPanel"
|
||||
header="#{recipeDetailBean.recipe.title}"
|
||||
>
|
||||
<h:form id="form1" enctype="multipart/form-data">
|
||||
<p:tabView id="tabGroupClient"
|
||||
orientation="left"
|
||||
activeIndex="#{userSession.detailTab}"
|
||||
>
|
||||
<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"
|
||||
<p:tab id="overviewTab"
|
||||
title="Description"
|
||||
>
|
||||
<p:panelGrid columns="2">
|
||||
<f:facet name="header">Description</f:facet>
|
||||
<p:outputLabel for="@next"
|
||||
value="Title"
|
||||
/>
|
||||
<p:inputText id="rtitle"
|
||||
size="45" required="true"
|
||||
focus="true"
|
||||
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="<- Suggest"
|
||||
>
|
||||
<f:ajax
|
||||
listener="#{recipeDetailBean.ajaxMoveUp}"
|
||||
execute="ingredientTable"
|
||||
render="ingredientTable"
|
||||
execute="rcategory bxCat"
|
||||
listener="#{recipeDetailBean.ajaxSuggestCategory}"
|
||||
render="rcategory"
|
||||
/>
|
||||
</p:commandButton>
|
||||
<p:commandButton value="Down"
|
||||
disabled="#{not recipeDetailBean.moveDownAble}"
|
||||
id="ctlDown"
|
||||
<p:selectOneMenu id="bxCat"
|
||||
value="#{recipeDetailBean.catToAdd}"
|
||||
tip="Recipe category suggestions, based on previous selections"
|
||||
>
|
||||
<f:ajax
|
||||
listener="#{recipeDetailBean.ajaxMoveDown}"
|
||||
execute="ingredientTable"
|
||||
render="ingredientTable"
|
||||
<f:selectItems
|
||||
value="#{recipeDetailBean.suggestCategory}"
|
||||
/>
|
||||
</p:commandButton>
|
||||
<p:button value="Add Group"
|
||||
disabled="true"
|
||||
</p:selectOneMenu>
|
||||
<p:outputLabel for="@next"
|
||||
value="Cuisine"
|
||||
/>
|
||||
<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
|
||||
listener="#{recipeDetailBean.ajaxDeleteItems}"
|
||||
immediate="true"
|
||||
render="ingredientTable"
|
||||
/>
|
||||
</p:commandButton>
|
||||
</h:panelGroup>
|
||||
<p:dataTable id="ingredientTable"
|
||||
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.
|
||||
</f:facet>
|
||||
<p:inputText id="ingAmt"
|
||||
size="3"
|
||||
value="#{item.displayAmount}"
|
||||
style="text-align: right"
|
||||
rendered="#{not item.ingGroup}"
|
||||
>
|
||||
</p:inputText>
|
||||
</p:column>
|
||||
<p:column style="width: 7em">
|
||||
<f:facet name="header">
|
||||
Units
|
||||
</f:facet>
|
||||
<p:inputText id="ingUnit"
|
||||
value="#{item.unit}"
|
||||
size="10"
|
||||
rendered="#{not item.ingGroup}"
|
||||
>
|
||||
</p:inputText>
|
||||
</p:column>
|
||||
<p:column style="width: 26em">
|
||||
<f:facet name="header">
|
||||
Item
|
||||
</f:facet>
|
||||
<p:inputText id="ingItem"
|
||||
size="42"
|
||||
value="#{item.item}"
|
||||
>
|
||||
</p:inputText>
|
||||
</p:column>
|
||||
<p:column label="Optional"
|
||||
align="center"
|
||||
styleClass="ingSel"
|
||||
>
|
||||
<f:facet name="header">
|
||||
Opt.
|
||||
</f:facet>
|
||||
<p:selectBooleanCheckbox
|
||||
id="ingOpt"
|
||||
value="#{item.optionalCB}"
|
||||
rendered="#{not item.ingGroup}"
|
||||
/>
|
||||
</p:column>
|
||||
<p:column style="width: 13em">
|
||||
<f:facet name="header">
|
||||
Ing. Key
|
||||
</f:facet>
|
||||
<p:inputText id="ingKey"
|
||||
value="#{item.ingkey}"
|
||||
size="20"
|
||||
rendered="#{not item.ingGroup}"
|
||||
>
|
||||
<f:ajax event="change"
|
||||
listener="#{recipeDetailBean.ajaxUpdateShopcat(item)}"
|
||||
render="shopCat"
|
||||
/>
|
||||
</p:inputText>
|
||||
</p:column>
|
||||
<p:column>
|
||||
<f:facet name="header">
|
||||
Shop. Cat.
|
||||
</f:facet>
|
||||
<h:outputText id="shopCat"
|
||||
value="#{item.shopCat}"
|
||||
rendered="#{not item.ingGroup}"
|
||||
/>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
<h:panelGroup id="pnlIng">
|
||||
<p:remoteCommand name="ingButton"
|
||||
action="#{recipeDetailBean.doAddIngredient}"
|
||||
process="@this ctlAddIngTxt"
|
||||
update="pnlIngredients"
|
||||
<p:autoComplete id="rcuisine"
|
||||
value="#{recipeDetailBean.recipe.cuisine}"
|
||||
completeMethod="#{recipeDetailBean.cuisineSuggestions}"
|
||||
/>
|
||||
<p:outputLabel for="@next"
|
||||
value="Add Ingredient: "
|
||||
value="Rating"
|
||||
/>
|
||||
<p:inputTextarea
|
||||
id="ctlAddIngTxt"
|
||||
focus="true" rows="1"
|
||||
cols="65"
|
||||
value="#{recipeDetailBean.ingredientText}"
|
||||
title="You can paste in multiple ingredients here!"
|
||||
onkeydown="if (event.keyCode === 13) { ingButton(); this.focus(); return false; }"
|
||||
<p:rating id="rrating" max="10"
|
||||
value="#{recipeDetailBean.recipe.rating}"
|
||||
/>
|
||||
<p:commandButton id="ctlAddIng"
|
||||
value="+ Add"
|
||||
onclick="ingButton(); return false;"
|
||||
<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: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
|
||||
listener="#{recipeDetailBean.ajaxDeleteImage}"
|
||||
render="picPanel"
|
||||
immediate="true"
|
||||
/>
|
||||
</p:commandButton>
|
||||
</h:panelGroup>
|
||||
</p:panel>
|
||||
</p:tab>
|
||||
<p:tab id="instructionsTab"
|
||||
title="Instructions"
|
||||
>
|
||||
<p:panel header="Instructions">
|
||||
<div id="insection">
|
||||
<p:textEditor
|
||||
id="ctlInstructions"
|
||||
</p:panelGrid>
|
||||
</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
|
||||
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
|
||||
listener="#{recipeDetailBean.ajaxDeleteItems}"
|
||||
immediate="true"
|
||||
render="ingredientTable"
|
||||
/>
|
||||
</p:commandButton>
|
||||
</h:panelGroup>
|
||||
<p:dataTable id="ingredientTable"
|
||||
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.
|
||||
</f:facet>
|
||||
<p:inputText id="ingAmt"
|
||||
size="3"
|
||||
value="#{item.displayAmount}"
|
||||
style="text-align: right"
|
||||
rendered="#{not item.ingGroup}"
|
||||
>
|
||||
</p:inputText>
|
||||
</p:column>
|
||||
<p:column style="width: 7em">
|
||||
<f:facet name="header">
|
||||
Units
|
||||
</f:facet>
|
||||
<p:inputText id="ingUnit"
|
||||
value="#{item.unit}"
|
||||
size="10"
|
||||
rendered="#{not item.ingGroup}"
|
||||
>
|
||||
</p:inputText>
|
||||
</p:column>
|
||||
<p:column style="width: 26em">
|
||||
<f:facet name="header">
|
||||
Item
|
||||
</f:facet>
|
||||
<p:inputText id="ingItem"
|
||||
size="42"
|
||||
value="#{item.item}"
|
||||
>
|
||||
</p:inputText>
|
||||
</p:column>
|
||||
<p:column label="Optional"
|
||||
align="center"
|
||||
styleClass="ingSel"
|
||||
>
|
||||
<f:facet name="header">
|
||||
Opt.
|
||||
</f:facet>
|
||||
<p:selectBooleanCheckbox
|
||||
id="ingOpt"
|
||||
value="#{item.optionalCB}"
|
||||
rendered="#{not item.ingGroup}"
|
||||
/>
|
||||
</p:column>
|
||||
<p:column style="width: 13em">
|
||||
<f:facet name="header">
|
||||
Ing. Key
|
||||
</f:facet>
|
||||
<p:inputText id="ingKey"
|
||||
value="#{item.ingkey}"
|
||||
size="20"
|
||||
rendered="#{not item.ingGroup}"
|
||||
>
|
||||
<f:ajax
|
||||
event="change"
|
||||
listener="#{recipeDetailBean.ajaxUpdateShopcat(item)}"
|
||||
render="shopCat"
|
||||
/>
|
||||
</p:inputText>
|
||||
</p:column>
|
||||
<p:column>
|
||||
<f:facet name="header">
|
||||
Shop. Cat.
|
||||
</f:facet>
|
||||
<h:outputText
|
||||
id="shopCat"
|
||||
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:outputLabel for="@next"
|
||||
value="Add Ingredient: "
|
||||
/>
|
||||
<p:inputTextarea
|
||||
id="ctlAddIngTxt"
|
||||
focus="true" rows="1"
|
||||
cols="65"
|
||||
value="#{recipeDetailBean.ingredientText}"
|
||||
title="You can paste in multiple ingredients here!"
|
||||
onkeydown="if (event.keyCode === 13) { ingButton(); this.focus(); return false; }"
|
||||
/>
|
||||
<p:commandButton
|
||||
id="ctlAddIng"
|
||||
value="+ Add"
|
||||
onclick="ingButton(); return false;"
|
||||
>
|
||||
</p:commandButton>
|
||||
</h:panelGroup>
|
||||
</p:panel>
|
||||
</p:tab>
|
||||
<p:tab id="instructionsTab"
|
||||
title="Instructions"
|
||||
>
|
||||
<p:panel header="Instructions">
|
||||
<div id="insection">
|
||||
<p:textEditor
|
||||
id="ctlInstructions"
|
||||
height="320"
|
||||
escape="false"
|
||||
value="#{recipeDetailBean.recipe.instructions}"
|
||||
/>
|
||||
</div>
|
||||
</p:panel>
|
||||
</p:tab>
|
||||
<p:tab id="notesTab" title="Notes">
|
||||
<p:panel header="Notes">
|
||||
<p:textEditor id="ctlNotes"
|
||||
height="320" escape="false"
|
||||
value="#{recipeDetailBean.recipe.instructions}"
|
||||
value="#{recipeDetailBean.recipe.modifications}"
|
||||
/>
|
||||
</div>
|
||||
</p:panel>
|
||||
</p:tab>
|
||||
<p:tab id="notesTab" title="Notes">
|
||||
<p:panel header="Notes">
|
||||
<p:textEditor id="ctlNotes"
|
||||
height="320" escape="false"
|
||||
value="#{recipeDetailBean.recipe.modifications}"
|
||||
/>
|
||||
</p:panel>
|
||||
</p:tab>
|
||||
</p:tabView>
|
||||
<p:commandButton id="doSave" value="Save"
|
||||
disabled="{not recipeDetailBean.dirty}"
|
||||
action="#{recipeDetailBean.doSave}"
|
||||
/>
|
||||
<p:commandButton id="doCancel" value="Cancel"
|
||||
immediate="true" action="/main.jsf"
|
||||
/>
|
||||
</h:form>
|
||||
</p:panel>
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
</p:panel>
|
||||
</p:tab>
|
||||
</p:tabView>
|
||||
<p:commandButton id="doSave" value="Save"
|
||||
disabled="{not recipeDetailBean.dirty}"
|
||||
action="#{recipeDetailBean.doSave}"
|
||||
/>
|
||||
<p:commandButton id="doCancel" value="Cancel"
|
||||
immediate="true" action="/main.jsf"
|
||||
/>
|
||||
</h:form>
|
||||
</p:panel>
|
||||
<p:dialog id="editShopcatDlg" widgetVar="editShopcatDlg">
|
||||
<ui:include src="editShopcat.xhtml" />
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
</body>
|
||||
</html>
|
61
src/main/resources/META-INF/resources/editShopcat.xhtml
Normal file
61
src/main/resources/META-INF/resources/editShopcat.xhtml
Normal file
|
@ -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>
|
9
src/main/resources/META-INF/resources/error/error.html
Normal file
9
src/main/resources/META-INF/resources/error/error.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>ERROR</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Uh-oh!</h1>
|
||||
An error happened.
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user