You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by sommeralex <al...@gmail.com> on 2012/06/30 11:49:10 UTC

two forms on one page - persist does not work.

Hello!

I have one page with two forms (one editprofile form, one imageupload form)

If the user is editing some user-information, WITHOUT submitting the
editProfile form, but clicking on imageUploadForm (for eg. to upload an
image), the user information (from editProfile Form) is lost. What i tried
so far is to save the user state on @AfterRender - but this did not work. 

Edit Profile.tml

<t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">

	<div id="editUserAttributes">
		<div>
			<t:form t:id="profileForm" class="form" t:clientValidation="false">
				<t:textfield t:id="firstname" value="user.firstname"
					t:mixins="decoField" divclass="formElement" class="textInput textField"
/>

				<t:textfield t:id="lastname" value="user.lastname"
					t:mixins="decoField" divclass="formElement" class="textInput textField"
/>

			
				
				<t:datefield class="textInput textField datefield" t:id="birthday"
					value="user.birthday" t:mixins="decoField" divclass="formElement" />

				<t:textarea t:id="aboutMe" value="user.aboutMe" t:mixins="decoField"
					divclass="formElement" class="textInput textField" />

				<div class="buttonPanel">
					<t:linksubmit class="button">${message:save}</t:linksubmit>
					 ${message:cancel}
					 
					 ${message:change-password}
					 

				</div>
			</t:form>
		</div>
	</div>

	<div  id="editUserPhoto">
		<t:if test="user.photo">
			<t:actionlink class="button" t:id="deletePhoto">delete
photo</t:actionlink>
			<br></br>
		</t:if>

		<div>
			<t:user.photo user="user" thumb="false" />
		 <t:plugins.cropper t:id="cropper" /> 	
		</div>
	</div>
</t:layout>

EditProfile.java

package com.airwriting.frontend.pages.user;

import java.io.File;

import
org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import
org.apache.commons.fileupload.FileUploadBase.InvalidContentTypeException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.tapestry5.annotations.AfterRender;
import org.apache.tapestry5.annotations.PageAttached;
import org.apache.tapestry5.annotations.PageDetached;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.annotations.SessionState;
import org.apache.tapestry5.ioc.annotations.Inject;

import se.unbound.tapestry.breadcrumbs.BreadCrumb;

import com.airwriting.domain.User;
import com.airwriting.frontend.helper.message.DisplayMessage;
import com.airwriting.frontend.helper.message.MessageContainer;
import com.airwriting.service.ConfigurationService;
import com.airwriting.service.data.UserService;

@BreadCrumb(titleKey="user/EditProfile")
public class EditProfile {
	@SessionState
	private MessageContainer messageContainer;
	@Inject
	private UserService userService;
	@Inject
	private ConfigurationService config;
	
	@Property
	private boolean hasPhoto;
	
	@Property
	@Persist
	private User user;

	void setupRender(){

		this.user = userService.getCurrentUser();
		hasPhoto = userService.hasPhoto(user);
	}

	Object onSuccessFromProfileForm(){
		userService.createOrUpdate(user);
		messageContainer.addMessage(DisplayMessage.USER_PROFILE_SAVE_SUCCESS);
		return ShowProfile.class;
	}

	void onFailureFromProfileForm(){
		messageContainer.addMessage(DisplayMessage.USER_PROFILE_SAVE_ERROR);
	}

	void onImageCroppedFromCropper(String name){
		if(user.getPhoto() != null){
			File file = new File( config.getContextPath() +
config.getUserThumbImageFolder() + user.getPhoto() );
			file.delete();
			file = new File( config.getContextPath() + config.getUserImageFolder() +
user.getPhoto() );
			file.delete();
		}
		user.setPhoto(name);
		userService.createOrUpdate(user);
	}

	// TODO move this method into the cropper component.
	// Tapestry currently does not support handling upload exception in the
components
	public Object onUploadException(FileUploadException ex){
		messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_ERROR);
		try {
			throw ex;
		} catch (InvalidContentTypeException e){
		
messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_INVALID_TYPE_ERROR);
		} catch (FileSizeLimitExceededException e){
			messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_SIZE_ERROR,
(e.getPermittedSize() / 1000000) + "");
		} catch (FileUploadException e) {
			messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_TRY_AGAIN_ERROR);
			// TODO log this error
		}
		return this;
	}
	
	public void onActionFromDeletePhoto() {
		userService.deleteUserPhoto(user);
	}

	// ENUMS
	public Class<User.Gender> getGenderType(){
		return User.Gender.class;
	}

	@AfterRender
	public void onPageDetached(){
		System.out.println();
		userService.createOrUpdate(user);
	}
	
}


image Edit.tml

<t:container	xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
							xmlns:p="tapestry:parameter">

<t:if test="tempImageName">
	
	<t:form t:id="imageEditForm">
		<div style="float:left">
			 /img/temp/${tempImageName} 
		</div>
		<div id="cropper_preview" style="float:left; margin:8px 3px 7px
3px;"></div>
		<div style="clear:left;"></div>		
		
		
		<t:html.hidden t:id="cropper_x1" value="x1" />
		<t:html.hidden t:id="cropper_y1" value="y1" />
		<t:html.hidden t:id="cropper_x2" value="x2" />
		<t:html.hidden t:id="cropper_y2" value="y2" />
		<p class="buttonPanel"><t:submit value="Save Image" class="button"/></p>
	</t:form>
	<t:form t:id="imageEditCancelForm">
		<p class="buttonPanel"><t:submit value="Cancel" class="button" 
t:id="Cancel"/></p>
	</t:form>

	<p:else>
		<t:form t:id="imageUploadForm">
			<p><t:upload t:id="imageFile" validate="required" /></p>
			<p class="buttonPanel"><t:submit value="Upload Image"
class="button"/></p>
		</t:form>
	</p:else>
</t:if>

</t:container>

imageEdit.java

package com.airwriting.frontend.components.plugins;

import java.awt.image.BufferedImage;

import java.io.File;
import java.io.IOException;
import java.util.Random;

import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.annotations.SessionState;
import org.apache.tapestry5.internal.services.ContextResource;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.Context;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
import org.apache.tapestry5.upload.services.UploadedFile;

import com.airwriting.frontend.helper.message.DisplayMessage;
import com.airwriting.frontend.helper.message.MessageContainer;
import com.airwriting.service.ConfigurationService;
import com.airwriting.service.ImageService;
import com.airwriting.service.data.UserService;

@Import(stylesheet = { "context:plugins/cropper/cropper.css" },
	library = {
		"${tapestry.scriptaculous}/builder.js",
		"${tapestry.scriptaculous}/dragdrop.js",
		"context:plugins/cropper/cropper.js"
})
public class Cropper {
	@SessionState
	private MessageContainer messageContainer;
	@Environmental
	private JavaScriptSupport javaScriptSupport;
	@Inject
	private ConfigurationService config;
	@Inject
	private Context context;
	@Inject
	private ComponentResources resources;
	@Inject
	private ImageService imageService;
	@Inject
	private UserService userService;

	@Property
	@Persist
	private String tempImageName;
	@Persist
	private int tempImageWidth;
	@Persist
	private int tempImageHeight;

	@Property
	private UploadedFile imageFile;

	@Property
	private int x1;
	@Property
	private int y1;
	@Property
	private int x2;
	@Property
	private int y2;

	void setupRender(){
		if(tempImageName != null){
			float ratio = config.getUserImageRatio();
			int width = Math.round( tempImageHeight * ratio );
			int height = tempImageHeight;
			if(width > tempImageWidth){
				width = tempImageWidth;
				height = Math.round( tempImageWidth / ratio );
			}
			int x1 = Math.round( (tempImageWidth  - width) / 2 );
			int y1 = Math.round( (tempImageHeight - height)/ 2 );
			int x2 = Math.round( (tempImageWidth  + width) / 2 );
			int y2 = Math.round( (tempImageHeight + height)/ 2 );

			
			String cropperScript = "new Cropper.ImgWithPreview('cropper_image',"+
					"	{"+
					"		minWidth: "	+config.getUserThumbImageWidth()	+","+
					"		minHeight: "+config.getUserThumbImageHeight()	+","+
					"		ratioDim:{y:"+config.getUserThumbImageHeight()+",
x:"+config.getUserThumbImageWidth()+"},"+
					"		displayOnInit: true,"+
					"		onEndCrop: onEndCrop,"+
					"		previewWrap: 'cropper_preview',"+
					"		onloadCoords: {x1:"+x1+",y1:"+y1+",x2:"+x2+",y2:"+y2+"}"+
					"	}"+
	");";
			
			// TODO display a bigger preview window
			javaScriptSupport.addScript("Event.observe(window, 'load', function() {"+
cropperScript +"});");
			//javaScriptSupport.addScript(cropperScript);
		}
	}

	public void onSuccessFromImageUploadForm(){
		
		//userService.createOrUpdate(userService.getCurrentUser());
		
		String[] filenameParts = imageFile.getFileName().split("\\.");
		String extension = filenameParts[filenameParts.length - 1];
		tempImageName = getRandomName() + "." + extension;
		String s = config.getTempImageFolder();
		String c = config.getContextPath();
		
		String pathString = config.getRightFilePath(config.getContextPath() +
config.getTempImageFolder());
		File pathFile = new File (pathString);
		pathFile.mkdirs();
		
		String file = config.getRightFilePath(config.getContextPath() +
config.getTempImageFolder() + tempImageName);
		//TODO getRightFilePath is just a fix, different seperators on different
OS
		
		
		File copied = new File( file );

		imageFile.write(copied);
		Resource imageResource = new ContextResource(context,
config.getTempImageFolder() + tempImageName);

		// TODO remove try catches and use if statements instead
		try {
			BufferedImage image = imageService.toBufferedImage(imageResource);
			image = imageService.scaleImage(image,config.getCropperImageMaxWidth(),
config.getCropperImageMaxHeight());

			if( image.getWidth() < config.getUserThumbImageWidth() ||
image.getHeight() < config.getUserThumbImageHeight() ){
			
messageContainer.addMessage(DisplayMessage.CROPPER_IMAGE_TOO_SMALL_ERROR,
config.getUserThumbImageWidth()+"", config.getUserThumbImageHeight()+"");
				tempImageName = null;
				copied.delete();
				return;
			}

			this.tempImageWidth = image.getWidth();
			this.tempImageHeight= image.getHeight();
			imageService.saveImage(image, file, 100);
		} catch (IOException e) {
			e.printStackTrace();
			messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_TRY_AGAIN_ERROR);
			tempImageName = null;
			copied.delete();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		
messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_INVALID_TYPE_ERROR);
			tempImageName = null;
			copied.delete();
		}
	}

	//TODO handle exception
	public void onSuccessFromImageEditForm() throws IOException {
		Resource imageResource = new ContextResource(context,
config.getTempImageFolder() + tempImageName);
		BufferedImage image = imageService.toBufferedImage(imageResource);
		image = imageService.subImage(image, x1, y1, x2, y2,
config.getUserImageWidth(), config.getUserImageHeight());

		
		//SAVE USER IMAGE
		String imageFolder = config.getContextPath() +
config.getUserImageFolder();
		File f = new File(config.getRightFilePath(imageFolder));
		boolean madeDirs = f.mkdirs();
		
		String imagePath = config.getContextPath() + config.getUserImageFolder() +
tempImageName;
		if(!imageService.saveImage(image, imagePath, 85) ){
			new File(imagePath).delete();
		}
		
		//SAVE THUMB USER IMAGE
		BufferedImage thumbImage = imageService.scaleImage(	image,
config.getUserThumbImageWidth(), config.getUserThumbImageHeight());
		String thumbImageFolder = config.getContextPath() +
config.getUserThumbImageFolder();
		f = new File(config.getRightFilePath(thumbImageFolder));
		madeDirs = f.mkdirs();
		
		
		String thumbImagePath = config.getContextPath() +
config.getUserThumbImageFolder() + tempImageName;
		if(!imageService.saveImage(thumbImage, thumbImagePath, 85) ){
			new File(thumbImagePath).delete();
		}
		
		//DELETE TEMP USER IMAGE
		String fileString = config.getContextPath() + config.getTempImageFolder()
+ tempImageName;
		File file = new File( config.getRightFilePath(fileString) );
		file.delete();
		resources.triggerEvent("imageCropped", new Object[]{tempImageName}, null);
		tempImageName = null;
	}

	public void onSuccessFromImageEditCancelForm() {
		String fileString =  config.getContextPath() + config.getTempImageFolder()
+ tempImageName;
		File file = new File(config.getRightFilePath(fileString) );
		file.delete();
		tempImageName = null;
	}

	private String getRandomName(){
		String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
		Random rand = new Random();
		String result = "";
		result += alphabet.charAt( rand.nextInt( alphabet.length()-10 ) );
		for (int i = 0; i < 19; i++) {
			result += alphabet.charAt( rand.nextInt( alphabet.length() ) );
		}
		return result;
	}

}



--
View this message in context: http://tapestry.1045711.n5.nabble.com/two-forms-on-one-page-persist-does-not-work-tp5714196.html
Sent from the Tapestry - User mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: two forms on one page - persist does not work.

Posted by sommeralex <al...@gmail.com>.
ok, thx!

--
View this message in context: http://tapestry.1045711.n5.nabble.com/two-forms-on-one-page-persist-does-not-work-tp5714196p5714213.html
Sent from the Tapestry - User mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: two forms on one page - persist does not work.

Posted by Bob Harner <bo...@gmail.com>.
The other option, if you really want to keep 2 separate forms on the page,
is to use ajax (zones)  instead of regular form submissions.
On Jun 30, 2012 7:07 AM, "Steve Eynon" <st...@alienfactory.co.uk>
wrote:

> Err... yes! Of course! This is just the way HTML works, nothing to do
> with @Persist.
>
> If you submit a form, then only information pertaining to that one
> form is submitted to the server. All other user changes on the page
> are lost when the page subsequently refreshes.
>
> To keep all changes on the page, then you should only have one form,
> encompassing all data. Then use multiple submit buttons to keep track
> of what should happen on the server, a-la
>
> http://jumpstart.doublenegative.com.au/jumpstart/examples/input/multiplesubmits1
>
> Steve.
>
>
> On 30 June 2012 17:49, sommeralex <al...@gmail.com> wrote:
> > Hello!
> >
> > I have one page with two forms (one editprofile form, one imageupload
> form)
> >
> > If the user is editing some user-information, WITHOUT submitting the
> > editProfile form, but clicking on imageUploadForm (for eg. to upload an
> > image), the user information (from editProfile Form) is lost. What i
> tried
> > so far is to save the user state on @AfterRender - but this did not work.
> >
> > Edit Profile.tml
> >
> > <t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd
> ">
> >
> >        <div id="editUserAttributes">
> >                <div>
> >                        <t:form t:id="profileForm" class="form"
> t:clientValidation="false">
> >                                <t:textfield t:id="firstname"
> value="user.firstname"
> >                                        t:mixins="decoField"
> divclass="formElement" class="textInput textField"
> > />
> >
> >                                <t:textfield t:id="lastname"
> value="user.lastname"
> >                                        t:mixins="decoField"
> divclass="formElement" class="textInput textField"
> > />
> >
> >
> >
> >                                <t:datefield class="textInput textField
> datefield" t:id="birthday"
> >                                        value="user.birthday"
> t:mixins="decoField" divclass="formElement" />
> >
> >                                <t:textarea t:id="aboutMe"
> value="user.aboutMe" t:mixins="decoField"
> >                                        divclass="formElement"
> class="textInput textField" />
> >
> >                                <div class="buttonPanel">
> >                                        <t:linksubmit
> class="button">${message:save}</t:linksubmit>
> >                                         ${message:cancel}
> >
> >                                         ${message:change-password}
> >
> >
> >                                </div>
> >                        </t:form>
> >                </div>
> >        </div>
> >
> >        <div  id="editUserPhoto">
> >                <t:if test="user.photo">
> >                        <t:actionlink class="button"
> t:id="deletePhoto">delete
> > photo</t:actionlink>
> >                        <br></br>
> >                </t:if>
> >
> >                <div>
> >                        <t:user.photo user="user" thumb="false" />
> >                 <t:plugins.cropper t:id="cropper" />
> >                </div>
> >        </div>
> > </t:layout>
> >
> > EditProfile.java
> >
> > package com.airwriting.frontend.pages.user;
> >
> > import java.io.File;
> >
> > import
> >
> org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
> > import
> > org.apache.commons.fileupload.FileUploadBase.InvalidContentTypeException;
> > import org.apache.commons.fileupload.FileUploadException;
> > import org.apache.tapestry5.annotations.AfterRender;
> > import org.apache.tapestry5.annotations.PageAttached;
> > import org.apache.tapestry5.annotations.PageDetached;
> > import org.apache.tapestry5.annotations.Persist;
> > import org.apache.tapestry5.annotations.Property;
> > import org.apache.tapestry5.annotations.SessionState;
> > import org.apache.tapestry5.ioc.annotations.Inject;
> >
> > import se.unbound.tapestry.breadcrumbs.BreadCrumb;
> >
> > import com.airwriting.domain.User;
> > import com.airwriting.frontend.helper.message.DisplayMessage;
> > import com.airwriting.frontend.helper.message.MessageContainer;
> > import com.airwriting.service.ConfigurationService;
> > import com.airwriting.service.data.UserService;
> >
> > @BreadCrumb(titleKey="user/EditProfile")
> > public class EditProfile {
> >        @SessionState
> >        private MessageContainer messageContainer;
> >        @Inject
> >        private UserService userService;
> >        @Inject
> >        private ConfigurationService config;
> >
> >        @Property
> >        private boolean hasPhoto;
> >
> >        @Property
> >        @Persist
> >        private User user;
> >
> >        void setupRender(){
> >
> >                this.user = userService.getCurrentUser();
> >                hasPhoto = userService.hasPhoto(user);
> >        }
> >
> >        Object onSuccessFromProfileForm(){
> >                userService.createOrUpdate(user);
> >
>  messageContainer.addMessage(DisplayMessage.USER_PROFILE_SAVE_SUCCESS);
> >                return ShowProfile.class;
> >        }
> >
> >        void onFailureFromProfileForm(){
> >
>  messageContainer.addMessage(DisplayMessage.USER_PROFILE_SAVE_ERROR);
> >        }
> >
> >        void onImageCroppedFromCropper(String name){
> >                if(user.getPhoto() != null){
> >                        File file = new File( config.getContextPath() +
> > config.getUserThumbImageFolder() + user.getPhoto() );
> >                        file.delete();
> >                        file = new File( config.getContextPath() +
> config.getUserImageFolder() +
> > user.getPhoto() );
> >                        file.delete();
> >                }
> >                user.setPhoto(name);
> >                userService.createOrUpdate(user);
> >        }
> >
> >        // TODO move this method into the cropper component.
> >        // Tapestry currently does not support handling upload exception
> in the
> > components
> >        public Object onUploadException(FileUploadException ex){
> >
>  messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_ERROR);
> >                try {
> >                        throw ex;
> >                } catch (InvalidContentTypeException e){
> >
> >
> messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_INVALID_TYPE_ERROR);
> >                } catch (FileSizeLimitExceededException e){
> >
>  messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_SIZE_ERROR,
> > (e.getPermittedSize() / 1000000) + "");
> >                } catch (FileUploadException e) {
> >
>  messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_TRY_AGAIN_ERROR);
> >                        // TODO log this error
> >                }
> >                return this;
> >        }
> >
> >        public void onActionFromDeletePhoto() {
> >                userService.deleteUserPhoto(user);
> >        }
> >
> >        // ENUMS
> >        public Class<User.Gender> getGenderType(){
> >                return User.Gender.class;
> >        }
> >
> >        @AfterRender
> >        public void onPageDetached(){
> >                System.out.println();
> >                userService.createOrUpdate(user);
> >        }
> >
> > }
> >
> >
> > image Edit.tml
> >
> > <t:container    xmlns:t="
> http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
> >
>  xmlns:p="tapestry:parameter">
> >
> > <t:if test="tempImageName">
> >
> >        <t:form t:id="imageEditForm">
> >                <div style="float:left">
> >                         /img/temp/${tempImageName}
> >                </div>
> >                <div id="cropper_preview" style="float:left; margin:8px
> 3px 7px
> > 3px;"></div>
> >                <div style="clear:left;"></div>
> >
> >
> >                <t:html.hidden t:id="cropper_x1" value="x1" />
> >                <t:html.hidden t:id="cropper_y1" value="y1" />
> >                <t:html.hidden t:id="cropper_x2" value="x2" />
> >                <t:html.hidden t:id="cropper_y2" value="y2" />
> >                <p class="buttonPanel"><t:submit value="Save Image"
> class="button"/></p>
> >        </t:form>
> >        <t:form t:id="imageEditCancelForm">
> >                <p class="buttonPanel"><t:submit value="Cancel"
> class="button"
> > t:id="Cancel"/></p>
> >        </t:form>
> >
> >        <p:else>
> >                <t:form t:id="imageUploadForm">
> >                        <p><t:upload t:id="imageFile" validate="required"
> /></p>
> >                        <p class="buttonPanel"><t:submit value="Upload
> Image"
> > class="button"/></p>
> >                </t:form>
> >        </p:else>
> > </t:if>
> >
> > </t:container>
> >
> > imageEdit.java
> >
> > package com.airwriting.frontend.components.plugins;
> >
> > import java.awt.image.BufferedImage;
> >
> > import java.io.File;
> > import java.io.IOException;
> > import java.util.Random;
> >
> > import org.apache.tapestry5.ComponentResources;
> > import org.apache.tapestry5.annotations.Environmental;
> > import org.apache.tapestry5.annotations.Import;
> > import org.apache.tapestry5.annotations.Persist;
> > import org.apache.tapestry5.annotations.Property;
> > import org.apache.tapestry5.annotations.SessionState;
> > import org.apache.tapestry5.internal.services.ContextResource;
> > import org.apache.tapestry5.ioc.Resource;
> > import org.apache.tapestry5.ioc.annotations.Inject;
> > import org.apache.tapestry5.services.Context;
> > import org.apache.tapestry5.services.javascript.JavaScriptSupport;
> > import org.apache.tapestry5.upload.services.UploadedFile;
> >
> > import com.airwriting.frontend.helper.message.DisplayMessage;
> > import com.airwriting.frontend.helper.message.MessageContainer;
> > import com.airwriting.service.ConfigurationService;
> > import com.airwriting.service.ImageService;
> > import com.airwriting.service.data.UserService;
> >
> > @Import(stylesheet = { "context:plugins/cropper/cropper.css" },
> >        library = {
> >                "${tapestry.scriptaculous}/builder.js",
> >                "${tapestry.scriptaculous}/dragdrop.js",
> >                "context:plugins/cropper/cropper.js"
> > })
> > public class Cropper {
> >        @SessionState
> >        private MessageContainer messageContainer;
> >        @Environmental
> >        private JavaScriptSupport javaScriptSupport;
> >        @Inject
> >        private ConfigurationService config;
> >        @Inject
> >        private Context context;
> >        @Inject
> >        private ComponentResources resources;
> >        @Inject
> >        private ImageService imageService;
> >        @Inject
> >        private UserService userService;
> >
> >        @Property
> >        @Persist
> >        private String tempImageName;
> >        @Persist
> >        private int tempImageWidth;
> >        @Persist
> >        private int tempImageHeight;
> >
> >        @Property
> >        private UploadedFile imageFile;
> >
> >        @Property
> >        private int x1;
> >        @Property
> >        private int y1;
> >        @Property
> >        private int x2;
> >        @Property
> >        private int y2;
> >
> >        void setupRender(){
> >                if(tempImageName != null){
> >                        float ratio = config.getUserImageRatio();
> >                        int width = Math.round( tempImageHeight * ratio );
> >                        int height = tempImageHeight;
> >                        if(width > tempImageWidth){
> >                                width = tempImageWidth;
> >                                height = Math.round( tempImageWidth /
> ratio );
> >                        }
> >                        int x1 = Math.round( (tempImageWidth  - width) /
> 2 );
> >                        int y1 = Math.round( (tempImageHeight - height)/
> 2 );
> >                        int x2 = Math.round( (tempImageWidth  + width) /
> 2 );
> >                        int y2 = Math.round( (tempImageHeight + height)/
> 2 );
> >
> >
> >                        String cropperScript = "new
> Cropper.ImgWithPreview('cropper_image',"+
> >                                        "       {"+
> >                                        "               minWidth: "
> +config.getUserThumbImageWidth()        +","+
> >                                        "               minHeight:
> "+config.getUserThumbImageHeight()   +","+
> >                                        "
> ratioDim:{y:"+config.getUserThumbImageHeight()+",
> > x:"+config.getUserThumbImageWidth()+"},"+
> >                                        "               displayOnInit:
> true,"+
> >                                        "               onEndCrop:
> onEndCrop,"+
> >                                        "               previewWrap:
> 'cropper_preview',"+
> >                                        "               onloadCoords:
> {x1:"+x1+",y1:"+y1+",x2:"+x2+",y2:"+y2+"}"+
> >                                        "       }"+
> >        ");";
> >
> >                        // TODO display a bigger preview window
> >
>  javaScriptSupport.addScript("Event.observe(window, 'load', function() {"+
> > cropperScript +"});");
> >                        //javaScriptSupport.addScript(cropperScript);
> >                }
> >        }
> >
> >        public void onSuccessFromImageUploadForm(){
> >
> >
>  //userService.createOrUpdate(userService.getCurrentUser());
> >
> >                String[] filenameParts =
> imageFile.getFileName().split("\\.");
> >                String extension = filenameParts[filenameParts.length -
> 1];
> >                tempImageName = getRandomName() + "." + extension;
> >                String s = config.getTempImageFolder();
> >                String c = config.getContextPath();
> >
> >                String pathString =
> config.getRightFilePath(config.getContextPath() +
> > config.getTempImageFolder());
> >                File pathFile = new File (pathString);
> >                pathFile.mkdirs();
> >
> >                String file =
> config.getRightFilePath(config.getContextPath() +
> > config.getTempImageFolder() + tempImageName);
> >                //TODO getRightFilePath is just a fix, different
> seperators on different
> > OS
> >
> >
> >                File copied = new File( file );
> >
> >                imageFile.write(copied);
> >                Resource imageResource = new ContextResource(context,
> > config.getTempImageFolder() + tempImageName);
> >
> >                // TODO remove try catches and use if statements instead
> >                try {
> >                        BufferedImage image =
> imageService.toBufferedImage(imageResource);
> >                        image =
> imageService.scaleImage(image,config.getCropperImageMaxWidth(),
> > config.getCropperImageMaxHeight());
> >
> >                        if( image.getWidth() <
> config.getUserThumbImageWidth() ||
> > image.getHeight() < config.getUserThumbImageHeight() ){
> >
> > messageContainer.addMessage(DisplayMessage.CROPPER_IMAGE_TOO_SMALL_ERROR,
> > config.getUserThumbImageWidth()+"", config.getUserThumbImageHeight()+"");
> >                                tempImageName = null;
> >                                copied.delete();
> >                                return;
> >                        }
> >
> >                        this.tempImageWidth = image.getWidth();
> >                        this.tempImageHeight= image.getHeight();
> >                        imageService.saveImage(image, file, 100);
> >                } catch (IOException e) {
> >                        e.printStackTrace();
> >
>  messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_TRY_AGAIN_ERROR);
> >                        tempImageName = null;
> >                        copied.delete();
> >                } catch (IllegalArgumentException e) {
> >                        e.printStackTrace();
> >
> >
> messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_INVALID_TYPE_ERROR);
> >                        tempImageName = null;
> >                        copied.delete();
> >                }
> >        }
> >
> >        //TODO handle exception
> >        public void onSuccessFromImageEditForm() throws IOException {
> >                Resource imageResource = new ContextResource(context,
> > config.getTempImageFolder() + tempImageName);
> >                BufferedImage image =
> imageService.toBufferedImage(imageResource);
> >                image = imageService.subImage(image, x1, y1, x2, y2,
> > config.getUserImageWidth(), config.getUserImageHeight());
> >
> >
> >                //SAVE USER IMAGE
> >                String imageFolder = config.getContextPath() +
> > config.getUserImageFolder();
> >                File f = new File(config.getRightFilePath(imageFolder));
> >                boolean madeDirs = f.mkdirs();
> >
> >                String imagePath = config.getContextPath() +
> config.getUserImageFolder() +
> > tempImageName;
> >                if(!imageService.saveImage(image, imagePath, 85) ){
> >                        new File(imagePath).delete();
> >                }
> >
> >                //SAVE THUMB USER IMAGE
> >                BufferedImage thumbImage = imageService.scaleImage(
> image,
> > config.getUserThumbImageWidth(), config.getUserThumbImageHeight());
> >                String thumbImageFolder = config.getContextPath() +
> > config.getUserThumbImageFolder();
> >                f = new File(config.getRightFilePath(thumbImageFolder));
> >                madeDirs = f.mkdirs();
> >
> >
> >                String thumbImagePath = config.getContextPath() +
> > config.getUserThumbImageFolder() + tempImageName;
> >                if(!imageService.saveImage(thumbImage, thumbImagePath,
> 85) ){
> >                        new File(thumbImagePath).delete();
> >                }
> >
> >                //DELETE TEMP USER IMAGE
> >                String fileString = config.getContextPath() +
> config.getTempImageFolder()
> > + tempImageName;
> >                File file = new File( config.getRightFilePath(fileString)
> );
> >                file.delete();
> >                resources.triggerEvent("imageCropped", new
> Object[]{tempImageName}, null);
> >                tempImageName = null;
> >        }
> >
> >        public void onSuccessFromImageEditCancelForm() {
> >                String fileString =  config.getContextPath() +
> config.getTempImageFolder()
> > + tempImageName;
> >                File file = new File(config.getRightFilePath(fileString)
> );
> >                file.delete();
> >                tempImageName = null;
> >        }
> >
> >        private String getRandomName(){
> >                String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
> >                Random rand = new Random();
> >                String result = "";
> >                result += alphabet.charAt( rand.nextInt(
> alphabet.length()-10 ) );
> >                for (int i = 0; i < 19; i++) {
> >                        result += alphabet.charAt( rand.nextInt(
> alphabet.length() ) );
> >                }
> >                return result;
> >        }
> >
> > }
> >
> >
> >
> > --
> > View this message in context:
> http://tapestry.1045711.n5.nabble.com/two-forms-on-one-page-persist-does-not-work-tp5714196.html
> > Sent from the Tapestry - User mailing list archive at Nabble.com.
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > For additional commands, e-mail: users-help@tapestry.apache.org
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>

Re: two forms on one page - persist does not work.

Posted by Steve Eynon <st...@alienfactory.co.uk>.
Err... yes! Of course! This is just the way HTML works, nothing to do
with @Persist.

If you submit a form, then only information pertaining to that one
form is submitted to the server. All other user changes on the page
are lost when the page subsequently refreshes.

To keep all changes on the page, then you should only have one form,
encompassing all data. Then use multiple submit buttons to keep track
of what should happen on the server, a-la
http://jumpstart.doublenegative.com.au/jumpstart/examples/input/multiplesubmits1

Steve.


On 30 June 2012 17:49, sommeralex <al...@gmail.com> wrote:
> Hello!
>
> I have one page with two forms (one editprofile form, one imageupload form)
>
> If the user is editing some user-information, WITHOUT submitting the
> editProfile form, but clicking on imageUploadForm (for eg. to upload an
> image), the user information (from editProfile Form) is lost. What i tried
> so far is to save the user state on @AfterRender - but this did not work.
>
> Edit Profile.tml
>
> <t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
>
>        <div id="editUserAttributes">
>                <div>
>                        <t:form t:id="profileForm" class="form" t:clientValidation="false">
>                                <t:textfield t:id="firstname" value="user.firstname"
>                                        t:mixins="decoField" divclass="formElement" class="textInput textField"
> />
>
>                                <t:textfield t:id="lastname" value="user.lastname"
>                                        t:mixins="decoField" divclass="formElement" class="textInput textField"
> />
>
>
>
>                                <t:datefield class="textInput textField datefield" t:id="birthday"
>                                        value="user.birthday" t:mixins="decoField" divclass="formElement" />
>
>                                <t:textarea t:id="aboutMe" value="user.aboutMe" t:mixins="decoField"
>                                        divclass="formElement" class="textInput textField" />
>
>                                <div class="buttonPanel">
>                                        <t:linksubmit class="button">${message:save}</t:linksubmit>
>                                         ${message:cancel}
>
>                                         ${message:change-password}
>
>
>                                </div>
>                        </t:form>
>                </div>
>        </div>
>
>        <div  id="editUserPhoto">
>                <t:if test="user.photo">
>                        <t:actionlink class="button" t:id="deletePhoto">delete
> photo</t:actionlink>
>                        <br></br>
>                </t:if>
>
>                <div>
>                        <t:user.photo user="user" thumb="false" />
>                 <t:plugins.cropper t:id="cropper" />
>                </div>
>        </div>
> </t:layout>
>
> EditProfile.java
>
> package com.airwriting.frontend.pages.user;
>
> import java.io.File;
>
> import
> org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
> import
> org.apache.commons.fileupload.FileUploadBase.InvalidContentTypeException;
> import org.apache.commons.fileupload.FileUploadException;
> import org.apache.tapestry5.annotations.AfterRender;
> import org.apache.tapestry5.annotations.PageAttached;
> import org.apache.tapestry5.annotations.PageDetached;
> import org.apache.tapestry5.annotations.Persist;
> import org.apache.tapestry5.annotations.Property;
> import org.apache.tapestry5.annotations.SessionState;
> import org.apache.tapestry5.ioc.annotations.Inject;
>
> import se.unbound.tapestry.breadcrumbs.BreadCrumb;
>
> import com.airwriting.domain.User;
> import com.airwriting.frontend.helper.message.DisplayMessage;
> import com.airwriting.frontend.helper.message.MessageContainer;
> import com.airwriting.service.ConfigurationService;
> import com.airwriting.service.data.UserService;
>
> @BreadCrumb(titleKey="user/EditProfile")
> public class EditProfile {
>        @SessionState
>        private MessageContainer messageContainer;
>        @Inject
>        private UserService userService;
>        @Inject
>        private ConfigurationService config;
>
>        @Property
>        private boolean hasPhoto;
>
>        @Property
>        @Persist
>        private User user;
>
>        void setupRender(){
>
>                this.user = userService.getCurrentUser();
>                hasPhoto = userService.hasPhoto(user);
>        }
>
>        Object onSuccessFromProfileForm(){
>                userService.createOrUpdate(user);
>                messageContainer.addMessage(DisplayMessage.USER_PROFILE_SAVE_SUCCESS);
>                return ShowProfile.class;
>        }
>
>        void onFailureFromProfileForm(){
>                messageContainer.addMessage(DisplayMessage.USER_PROFILE_SAVE_ERROR);
>        }
>
>        void onImageCroppedFromCropper(String name){
>                if(user.getPhoto() != null){
>                        File file = new File( config.getContextPath() +
> config.getUserThumbImageFolder() + user.getPhoto() );
>                        file.delete();
>                        file = new File( config.getContextPath() + config.getUserImageFolder() +
> user.getPhoto() );
>                        file.delete();
>                }
>                user.setPhoto(name);
>                userService.createOrUpdate(user);
>        }
>
>        // TODO move this method into the cropper component.
>        // Tapestry currently does not support handling upload exception in the
> components
>        public Object onUploadException(FileUploadException ex){
>                messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_ERROR);
>                try {
>                        throw ex;
>                } catch (InvalidContentTypeException e){
>
> messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_INVALID_TYPE_ERROR);
>                } catch (FileSizeLimitExceededException e){
>                        messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_SIZE_ERROR,
> (e.getPermittedSize() / 1000000) + "");
>                } catch (FileUploadException e) {
>                        messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_TRY_AGAIN_ERROR);
>                        // TODO log this error
>                }
>                return this;
>        }
>
>        public void onActionFromDeletePhoto() {
>                userService.deleteUserPhoto(user);
>        }
>
>        // ENUMS
>        public Class<User.Gender> getGenderType(){
>                return User.Gender.class;
>        }
>
>        @AfterRender
>        public void onPageDetached(){
>                System.out.println();
>                userService.createOrUpdate(user);
>        }
>
> }
>
>
> image Edit.tml
>
> <t:container    xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
>                                                        xmlns:p="tapestry:parameter">
>
> <t:if test="tempImageName">
>
>        <t:form t:id="imageEditForm">
>                <div style="float:left">
>                         /img/temp/${tempImageName}
>                </div>
>                <div id="cropper_preview" style="float:left; margin:8px 3px 7px
> 3px;"></div>
>                <div style="clear:left;"></div>
>
>
>                <t:html.hidden t:id="cropper_x1" value="x1" />
>                <t:html.hidden t:id="cropper_y1" value="y1" />
>                <t:html.hidden t:id="cropper_x2" value="x2" />
>                <t:html.hidden t:id="cropper_y2" value="y2" />
>                <p class="buttonPanel"><t:submit value="Save Image" class="button"/></p>
>        </t:form>
>        <t:form t:id="imageEditCancelForm">
>                <p class="buttonPanel"><t:submit value="Cancel" class="button"
> t:id="Cancel"/></p>
>        </t:form>
>
>        <p:else>
>                <t:form t:id="imageUploadForm">
>                        <p><t:upload t:id="imageFile" validate="required" /></p>
>                        <p class="buttonPanel"><t:submit value="Upload Image"
> class="button"/></p>
>                </t:form>
>        </p:else>
> </t:if>
>
> </t:container>
>
> imageEdit.java
>
> package com.airwriting.frontend.components.plugins;
>
> import java.awt.image.BufferedImage;
>
> import java.io.File;
> import java.io.IOException;
> import java.util.Random;
>
> import org.apache.tapestry5.ComponentResources;
> import org.apache.tapestry5.annotations.Environmental;
> import org.apache.tapestry5.annotations.Import;
> import org.apache.tapestry5.annotations.Persist;
> import org.apache.tapestry5.annotations.Property;
> import org.apache.tapestry5.annotations.SessionState;
> import org.apache.tapestry5.internal.services.ContextResource;
> import org.apache.tapestry5.ioc.Resource;
> import org.apache.tapestry5.ioc.annotations.Inject;
> import org.apache.tapestry5.services.Context;
> import org.apache.tapestry5.services.javascript.JavaScriptSupport;
> import org.apache.tapestry5.upload.services.UploadedFile;
>
> import com.airwriting.frontend.helper.message.DisplayMessage;
> import com.airwriting.frontend.helper.message.MessageContainer;
> import com.airwriting.service.ConfigurationService;
> import com.airwriting.service.ImageService;
> import com.airwriting.service.data.UserService;
>
> @Import(stylesheet = { "context:plugins/cropper/cropper.css" },
>        library = {
>                "${tapestry.scriptaculous}/builder.js",
>                "${tapestry.scriptaculous}/dragdrop.js",
>                "context:plugins/cropper/cropper.js"
> })
> public class Cropper {
>        @SessionState
>        private MessageContainer messageContainer;
>        @Environmental
>        private JavaScriptSupport javaScriptSupport;
>        @Inject
>        private ConfigurationService config;
>        @Inject
>        private Context context;
>        @Inject
>        private ComponentResources resources;
>        @Inject
>        private ImageService imageService;
>        @Inject
>        private UserService userService;
>
>        @Property
>        @Persist
>        private String tempImageName;
>        @Persist
>        private int tempImageWidth;
>        @Persist
>        private int tempImageHeight;
>
>        @Property
>        private UploadedFile imageFile;
>
>        @Property
>        private int x1;
>        @Property
>        private int y1;
>        @Property
>        private int x2;
>        @Property
>        private int y2;
>
>        void setupRender(){
>                if(tempImageName != null){
>                        float ratio = config.getUserImageRatio();
>                        int width = Math.round( tempImageHeight * ratio );
>                        int height = tempImageHeight;
>                        if(width > tempImageWidth){
>                                width = tempImageWidth;
>                                height = Math.round( tempImageWidth / ratio );
>                        }
>                        int x1 = Math.round( (tempImageWidth  - width) / 2 );
>                        int y1 = Math.round( (tempImageHeight - height)/ 2 );
>                        int x2 = Math.round( (tempImageWidth  + width) / 2 );
>                        int y2 = Math.round( (tempImageHeight + height)/ 2 );
>
>
>                        String cropperScript = "new Cropper.ImgWithPreview('cropper_image',"+
>                                        "       {"+
>                                        "               minWidth: "     +config.getUserThumbImageWidth()        +","+
>                                        "               minHeight: "+config.getUserThumbImageHeight()   +","+
>                                        "               ratioDim:{y:"+config.getUserThumbImageHeight()+",
> x:"+config.getUserThumbImageWidth()+"},"+
>                                        "               displayOnInit: true,"+
>                                        "               onEndCrop: onEndCrop,"+
>                                        "               previewWrap: 'cropper_preview',"+
>                                        "               onloadCoords: {x1:"+x1+",y1:"+y1+",x2:"+x2+",y2:"+y2+"}"+
>                                        "       }"+
>        ");";
>
>                        // TODO display a bigger preview window
>                        javaScriptSupport.addScript("Event.observe(window, 'load', function() {"+
> cropperScript +"});");
>                        //javaScriptSupport.addScript(cropperScript);
>                }
>        }
>
>        public void onSuccessFromImageUploadForm(){
>
>                //userService.createOrUpdate(userService.getCurrentUser());
>
>                String[] filenameParts = imageFile.getFileName().split("\\.");
>                String extension = filenameParts[filenameParts.length - 1];
>                tempImageName = getRandomName() + "." + extension;
>                String s = config.getTempImageFolder();
>                String c = config.getContextPath();
>
>                String pathString = config.getRightFilePath(config.getContextPath() +
> config.getTempImageFolder());
>                File pathFile = new File (pathString);
>                pathFile.mkdirs();
>
>                String file = config.getRightFilePath(config.getContextPath() +
> config.getTempImageFolder() + tempImageName);
>                //TODO getRightFilePath is just a fix, different seperators on different
> OS
>
>
>                File copied = new File( file );
>
>                imageFile.write(copied);
>                Resource imageResource = new ContextResource(context,
> config.getTempImageFolder() + tempImageName);
>
>                // TODO remove try catches and use if statements instead
>                try {
>                        BufferedImage image = imageService.toBufferedImage(imageResource);
>                        image = imageService.scaleImage(image,config.getCropperImageMaxWidth(),
> config.getCropperImageMaxHeight());
>
>                        if( image.getWidth() < config.getUserThumbImageWidth() ||
> image.getHeight() < config.getUserThumbImageHeight() ){
>
> messageContainer.addMessage(DisplayMessage.CROPPER_IMAGE_TOO_SMALL_ERROR,
> config.getUserThumbImageWidth()+"", config.getUserThumbImageHeight()+"");
>                                tempImageName = null;
>                                copied.delete();
>                                return;
>                        }
>
>                        this.tempImageWidth = image.getWidth();
>                        this.tempImageHeight= image.getHeight();
>                        imageService.saveImage(image, file, 100);
>                } catch (IOException e) {
>                        e.printStackTrace();
>                        messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_TRY_AGAIN_ERROR);
>                        tempImageName = null;
>                        copied.delete();
>                } catch (IllegalArgumentException e) {
>                        e.printStackTrace();
>
> messageContainer.addMessage(DisplayMessage.FILE_UPLOAD_INVALID_TYPE_ERROR);
>                        tempImageName = null;
>                        copied.delete();
>                }
>        }
>
>        //TODO handle exception
>        public void onSuccessFromImageEditForm() throws IOException {
>                Resource imageResource = new ContextResource(context,
> config.getTempImageFolder() + tempImageName);
>                BufferedImage image = imageService.toBufferedImage(imageResource);
>                image = imageService.subImage(image, x1, y1, x2, y2,
> config.getUserImageWidth(), config.getUserImageHeight());
>
>
>                //SAVE USER IMAGE
>                String imageFolder = config.getContextPath() +
> config.getUserImageFolder();
>                File f = new File(config.getRightFilePath(imageFolder));
>                boolean madeDirs = f.mkdirs();
>
>                String imagePath = config.getContextPath() + config.getUserImageFolder() +
> tempImageName;
>                if(!imageService.saveImage(image, imagePath, 85) ){
>                        new File(imagePath).delete();
>                }
>
>                //SAVE THUMB USER IMAGE
>                BufferedImage thumbImage = imageService.scaleImage(     image,
> config.getUserThumbImageWidth(), config.getUserThumbImageHeight());
>                String thumbImageFolder = config.getContextPath() +
> config.getUserThumbImageFolder();
>                f = new File(config.getRightFilePath(thumbImageFolder));
>                madeDirs = f.mkdirs();
>
>
>                String thumbImagePath = config.getContextPath() +
> config.getUserThumbImageFolder() + tempImageName;
>                if(!imageService.saveImage(thumbImage, thumbImagePath, 85) ){
>                        new File(thumbImagePath).delete();
>                }
>
>                //DELETE TEMP USER IMAGE
>                String fileString = config.getContextPath() + config.getTempImageFolder()
> + tempImageName;
>                File file = new File( config.getRightFilePath(fileString) );
>                file.delete();
>                resources.triggerEvent("imageCropped", new Object[]{tempImageName}, null);
>                tempImageName = null;
>        }
>
>        public void onSuccessFromImageEditCancelForm() {
>                String fileString =  config.getContextPath() + config.getTempImageFolder()
> + tempImageName;
>                File file = new File(config.getRightFilePath(fileString) );
>                file.delete();
>                tempImageName = null;
>        }
>
>        private String getRandomName(){
>                String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
>                Random rand = new Random();
>                String result = "";
>                result += alphabet.charAt( rand.nextInt( alphabet.length()-10 ) );
>                for (int i = 0; i < 19; i++) {
>                        result += alphabet.charAt( rand.nextInt( alphabet.length() ) );
>                }
>                return result;
>        }
>
> }
>
>
>
> --
> View this message in context: http://tapestry.1045711.n5.nabble.com/two-forms-on-one-page-persist-does-not-work-tp5714196.html
> Sent from the Tapestry - User mailing list archive at Nabble.com.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org