[richfaces-svn-commits] JBoss Rich Faces SVN: r13740 - trunk/docs/realworld_app_guide/en/src/main/docbook/modules.
richfaces-svn-commits at lists.jboss.org
richfaces-svn-commits at lists.jboss.org
Tue Apr 21 11:39:27 EDT 2009
Author: atsebro
Date: 2009-04-21 11:39:27 -0400 (Tue, 21 Apr 2009)
New Revision: 13740
Modified:
trunk/docs/realworld_app_guide/en/src/main/docbook/modules/hiw.xml
Log:
RF-5768: Real World Demo Application Tutorial Update for 3.3.1 release
Modified: trunk/docs/realworld_app_guide/en/src/main/docbook/modules/hiw.xml
===================================================================
--- trunk/docs/realworld_app_guide/en/src/main/docbook/modules/hiw.xml 2009-04-21 15:36:50 UTC (rev 13739)
+++ trunk/docs/realworld_app_guide/en/src/main/docbook/modules/hiw.xml 2009-04-21 15:39:27 UTC (rev 13740)
@@ -408,5 +408,394 @@
</section>
+ <section>
+ <title>Slide show</title>
+
+ <para>The slide-show feature in the Photo Album Demo can be enabled by clicking "Start Slideshow" link from two different places in the application:
+ 1) from user's album preview (<code>/web/src/main/webapp/image/albumInfo.xhtml</code>) and 2) from a particular photo preview (<code>src/main/webapp/image/imageInfo.xhtml</code>).
+ Both of two mentioned XHTML files include slideshow with the help of Facelets <<emphasis role="bold"><property>ui:include</property></emphasis> tag
+ (for more information about <<emphasis role="bold"><property>ui:include</property></emphasis> see Facelets Reference Guide —
+ <ulink url="http://www.jsftoolbox.com/documentation/facelets/01-Introduction/index.jsf">http://www.jsftoolbox.com/documentation/facelets/01-Introduction/index.jsf</ulink>).
+ </para>
+
+ <para>
+ The <code>startSlideshow()</code> method of <code>SlideshowManager.java</code> has two implementations.
+ The first implementation is designed to activate the slide-show from an album preview (<code>/image/albumInfo.xhtml</code>) when no photo is selected in the current image list.
+ The method iterates over all photos of a particular album starting from the first one in the list. Look at the <code>SlideshowManager.java</code> listing below:
+ </para>
+ <programlisting role="JAVA"><![CDATA[...
+public void startSlideshow(){
+ active = true;
+ this.slideshowIndex = 0;
+ if(model.getImages() == null || model.getImages().size() < 1){
+ stopSlideshow();
+ Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT, "No images for slideshow!");
+ return;
+ }
+ this.selectedImage = model.getImages().get(this.slideshowIndex);
+ this.selectedImage.getAlbum().visitImage(selectedImage, true);
+}
+...]]></programlisting>
+
+ <para>
+ The second implementation of the <code>startSlideshow()</code> method is activated when a link to slide-show is clicked from a particular photo preview.
+ This method iterates over the rest of photos starting from the current selected one:
+ </para>
+ <programlisting role="JAVA"><![CDATA[...
+public void startSlideshow(Image selectedImage){
+ active = true;
+ if(model.getImages() == null || model.getImages().size() < 1){
+ stopSlideshow();
+ Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT, "No images for slideshow!");
+ return;
+ }
+ this.slideshowIndex = model.getImages().indexOf(selectedImage);
+ this.selectedImage = selectedImage;
+ this.selectedImage.getAlbum().visitImage(selectedImage, true);
+}
+...]]></programlisting>
+
+ <para>
+ Both implementations of <code>startSlideshow()</code> method set active property to true.
+ This <code>true</code> makes two important slide-show parts (slide-show modal panel and slide-show poller) render.
+ </para>
+ <para>
+ The slide-show modal panel is kept in the <code>web/src/main/webapp/includes/image/slideshow.xhtml</code> file and referred from the corresponding pages with the help of <emphasis role="bold"><property><ui:include></property></emphasis> Facelets tag:
+ </para>
+
+ <programlisting role="XML"><![CDATA[...
+<ui:include src="/includes/image/slideshow.xhtml"/>
+...]]></programlisting>
+
+ <para>
+ Have a look at <code>web/src/main/webapp/includes/image/slideshow.xhtml</code> file:
+ </para>
+
+ <programlisting role="XML"><![CDATA[...
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"...>
+ <rich:modalPanel showWhenRendered="#{slideshow.active}"
+ domElementAttachment="parent"
+ id="slideShowModalPanel"
+ width="650"
+ onshow="showPictureEffect();"
+ height="650">
+ <f:facet name="controls">
+ <h:panelGroup>
+ <h:graphicImage value="/img/modal/close.png" style="cursor:pointer" id="hidelink">
+ <a4j:support event="onclick" actionListener="#{slideshow.stopSlideshow}" reRender="slideShowForm, mainArea, tree" />
+ </h:graphicImage>
+ </h:panelGroup>
+ </f:facet>
+ ...
+ </rich:modalPanel>
+</ui:composition>
+...]]></programlisting>
+
+ <para>
+ The modal panel is always rendered on the page in a hidden state.
+ Activating the slide-show renders the main area, so the slide-show modal panel appears in the closest to an observer layer.
+ </para>
+
+ <programlisting role="XML"><![CDATA[...
+<a4j:commandLink styleClass="slideshow-link"
+ actionListener="#{slideshow.startSlideshow()}"
+ reRender="slideShowForm, mainArea">
+ ...
+</a4j:commandLink>
+...]]></programlisting>
+ <para>
+ Slide-show poller is enabled if the slide-show is activated:
+ </para>
+ <programlisting role="XML"><![CDATA[...
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a4j="http://richfaces.org/a4j"
+ xmlns:richx="http://richfaces.org/richx">
+ <a4j:form id="slideShowForm">
+ <a4j:poll reRender="slideshowImage"
+ actionListener="#{slideshow.showNextImage()}"
+ interval="#{slideshow.interval}"
+ enabled="#{slideshow.active}"
+ onsubmit="hidePictureEffect()"
+ oncomplete="showPictureEffect();"/>
+ </a4j:form>
+</ui:composition>
+...]]></programlisting>
+ <para>
+ The slide-show poller sends the request for the next image (<code>showNextImage()</code> method) each four seconds.
+ The interval is defined in the interval property of the <code>SlideshowManager.java</code> and refers to a <code>INITIAL.DELAY</code> constant (<code>constants.java</code>).
+ When the <emphasis role="bold"><property><a4j:poll></property></emphasis> component receives a new image it renders the slideShowImage area (<code>/web/src/main/webapp/image/slideshow.xhtml</code>):
+ </para>
+ <programlisting role="XML"><![CDATA[...
+<h:panelGroup id="slideshowImage">
+ <a4j:mediaOutput id="imgSlideShow"
+ element="img"
+ styleClass="main-image"
+ createContent="#{imageLoader.paintImage}"
+ style="opacity: 0.1"
+ value="#{slideshow.selectedImage != null? fileManager.transformPath(slideshow.selectedImage.path, '_medium'):null}">
+ <rich:toolTip followMouse="true"
+ direction="top-right"
+ showDelay="500"
+ styleClass="tooltip">
+ <span style="white-space: nowrap"> #{slideshow.selectedImage.description} </span>
+ </rich:toolTip>
+ </a4j:mediaOutput>
+</h:panelGroup>
+...]]></programlisting>
+
+ <para>
+ The <emphasis role="bold"><property>a4j:mediaOtuput</property></emphasis> component has a value attribute that takes a path to photos as a value and renders photos with the help of a <emphasis><property>createContent</property></emphasis> attribute. The showNextImage works cyclically.
+ </para>
+
+ <para>
+ There is <emphasis role="bold"><property>rich:effect</property></emphasis> that makes rendering process look more effective (<code>web/src/main/webapp/includes/image/slideshow.xhtml</code>):
+ </para>
+ <programlisting role="XML"><![CDATA[...
+<rich:effect name="hidePictureEffect" type="Opacity" params="duration:0.4, from:1.0, to:0.0" for="imgSlideShow" />
+<rich:effect name="showPictureEffect" type="Opacity" params="duration:0.4, from:0.1, to:1.0" for="imgSlideShow" />
+...]]></programlisting>
+
+ <para>
+ The described above implements a modal panel with photos that change each other in order they store in an album.
+ </para>
+ <figure>
+ <title>Slide show</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/slide_show.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>
+ To quit the slide-show user clicks "Close window" button on the slide-show panel and <code>stopSlideshow()</code> method is activated.
+ </para>
+ <programlisting role="JAVA"><![CDATA[...
+ at Observer("stopSlideshow")
+ public void stopSlideshow(){
+ active = false;
+ this.selectedImage = null;
+ this.slideshowIndex = 0;
+ }
+...]]></programlisting>
+
+ </section>
+ <section>
+ <title>Image Size control</title>
+
+ <section>
+ <title>Building the control with <rich:inputNumberSlider></title>
+ <para>
+ The <emphasis role="bold"><property>rich:inputNumberSlider</property></emphasis> component in the Photo Album Demo is used as a control that helps a user to change photos size while previewing an album.
+ A handler position on the slider track corresponds to a particular value of image size.
+ The component is included into the page with the help of <emphasis role="bold"><property>ui:include</property></emphasis>:
+ </para>
+ <programlisting role="XML"><![CDATA[...
+<ui:include src="/includes/misc/inputNumberSlider.xhtml"/>
+...]]></programlisting>
+
+ <para>
+ Now let's have a look at <code>src/main/webapp/includes/misc/inputNumberSlider.xhtml</code> file:
+ </para>
+ <programlisting role="XML"><![CDATA[...
+<ui:composition ...>
+ <div>
+ <rich:inputNumberSlider value="#{imageSizeHelper.value}"
+ minValue="80"
+ maxValue="200"
+ step="40"
+ enableManualInput="false"
+ showArrows="false"
+ showBoundaryValues="true"
+ showInput="false">
+ <a4j:support event="onchange" reRender="userAlbumImages"/>
+ </rich:inputNumberSlider>
+ </div>
+</ui:composition>
+...]]></programlisting>
+ <para>
+ On each slider position change the <emphasis role="bold"><property>a4j:support</property></emphasis> component invokes an Ajax request that passes a new set value into the <code>ImageSizeHelper.java</code> class.
+ This class saves new photo dimensions, processes and assigns new values to photo related attributes (a CSS class for new photo size, postfix for a new file name, image background):
+ </para>
+ <programlisting role="JAVA"><![CDATA[...
+ public static enum ImageDimension {
+
+ SIZE_80(80), SIZE_120(120), SIZE_160(160), SIZE_200(200);
+
+ final static String CSS_CLASS = "preview_box_photo_";
+ final static String FILE_POSTFIX = "_small";
+ final static String IMAGE_BG = "/img/shell/frame_photo_%1$d.png";
+ final static String IMAGE_BG_STYLE = "width: %1$dpx; height: %1$dpx";
+
+ int x;
+ String bgStyle;
+ String cssClass;
+ String imageBgSrc;
+ String filePostfix;
+
+ private ImageDimension(int x) {
+ this.x = x;
+ this.bgStyle = String.format(IMAGE_BG_STYLE, x + 20);
+ cssClass = CSS_CLASS + x;
+ imageBgSrc = String.format(IMAGE_BG, (x == 160) ? 200 : x);
+ filePostfix = FILE_POSTFIX + x;
+ }
+ ...]]></programlisting>
+
+ <para>
+ After the <code>ImageSizeHelper.java</code> is worked out the <emphasis role="bold"><property>a4j:support</property></emphasis> component renders user photos
+ (more exactly, the <emphasis role="bold"><property>h:panelGroup</property></emphasis> with <code>userAlbumImages</code> id that contains user photos)
+ correspondingly to a new set value. Here is <code>web/src/main/webapp/includes/image/imageList.xhtml</code>:
+ </para>
+ <programlisting role="XML"><![CDATA[...
+<h:panelGroup id="userAlbumImages">
+ <a4j:repeat id="imageList" value="#{model.images}" var="image" rows="20">
+ <h:panelGroup layout="block" styleClass="#{imageSizeHelper.currentDimension.cssClass}">
+ <h:graphicImage styleClass="pr_photo_bg" style="#{imageSizeHelper.currentDimension.imageBgStyle}" value="#{imageSizeHelper.currentDimension.imageBg}" />
+ <h:panelGrid cellpadding="0">
+ <h:panelGroup>
+ <a4j:commandLink actionListener="#{controller.showImage(image)}" reRender="mainArea, tree">
+ <a4j:mediaOutput id="img" element="img"
+ createContent="#{imageLoader.paintImage}"
+ style="border : 1px solid #FFFFFF;"
+ value="#{fileManager.transformPath(image.fullPath, imageSizeHelper.currentDimension.filePostfix)}">
+ <f:param value="#{imageSizeHelper.currentDimension.x}" name="x" />
+ <rich:dragSupport rendered="#{controller.isUserImage(image)}" reRender="mainArea, tree" id="dragSource" dragIndicator="dragIndicator"
+ dragType="image" dragValue="#{image}">
+ <rich:dndParam id="dragParam" name="label" value="#{image.name}" />
+ </rich:dragSupport>
+ <ui:include src="/includes/contextMenu/CMForImage.xhtml" >
+ <ui:param name="image" value="#{image}" />
+ </ui:include>
+ </a4j:mediaOutput>
+ </a4j:commandLink>
+ <br/>
+ </h:panelGroup>
+ </h:panelGrid>
+ <h:panelGroup layout="block" styleClass="photo_name">#{image.name} </h:panelGroup>
+ <h:panelGroup layout="block" styleClass="photo_data">
+ <h:outputText value="#{image.created}">
+ <f:convertDateTime />
+ </h:outputText>
+ </h:panelGroup>
+ </h:panelGroup>
+ </a4j:repeat>
+</h:panelGroup>
+...]]></programlisting>
+
+ <para>
+ When the <emphasis role="bold"><property><rich:inputNumberSlider<</property></emphasis> is rendered at first its default value for image size is 120 px.
+ </para>
+
+ <figure>
+ <title>Image size control</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/image_size.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+
+ <section>
+ <title>Links in Photo Album Demo. Using the <a4j:commandLink></title>
+ <para>
+ The main difference between <emphasis role="bold"><property><h:commandLink></property></emphasis> component is a) Ajax request that is generated on a click and b) dynamic rerendering of the page after a response comes back.
+ It's not necessary to plug any support into the component, as Ajax support is already built-in.
+ </para>
+ <para>
+ The <emphasis role="bold"><property><a4j:commandLink></property></emphasis> component is used widely in the application.
+ In the following example clicking on the <Edit> link will rerender the main ares (watching area) of the application and open an album edit form.
+ Each album has its owner and only owner can edit the album contents.
+ The link <Edit> will be rendered only if the current logged-in user is the owner of this album: the <emphasis><property>"rendered"</property></emphasis> attribute refers to the owner id and compares it with the current user id:
+ </para>
+ <programlisting role="XML"><![CDATA[...
+<a4j:commandLink rendered="#{model.selectedAlbum.owner.id == user.id}"
+ value="#{messages['album.edit']} "
+ actionListener="#{controller.startEditAlbum(model.selectedAlbum)}"
+ reRender="mainArea">
+</a4j:commandLink>
+...]]></programlisting>
+ <para>
+ The <emphasis><property><value></property></emphasis> attribute (text that will appear on the link) is picked up from the <code>messages_en.properties</code> file.
+ Such property files are very useful e.g. for multi language applications.
+ Each property is saved in the format "name—value".
+ Let's have a look at this file in the JBDS:
+ </para>
+ <figure>
+ <title>Image size control</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/messages_en_property.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+
+ <section>
+ <title>Error Reports in the Real World Demo</title>
+ <para>The main page of the application <code>web/src/main/webapp/index.xhtml</code> includes <code>web/src/main/webapp/includes/misc/errorPanel.xhtml</code>.
+ The error panel itself is always rendered but hidden if no error appears. The listing below shows the part of <code>errorPanel.xhtml</code> page:
+ </para>
+ <programlisting role="XML"><![CDATA[...
+<a4j:outputPanel id="errors" ajaxRendered="true">
+ <h:panelGroup rendered="#{errorHandlerBean.errorExist}">
+ <rich:modalPanel id="errorPanel"
+ showWhenRendered="true"
+ minWidth="300"
+ minHeight="200"
+ autosized="true">
+ ...
+ </rich:modalPanel>
+ </h:panelGroup>
+</a4j:outputPanel>
+...]]></programlisting>
+ <para>
+ Error checking happens each time the Ajax request is invoked by user activity.
+ The <emphasis role="bold"><property>rich:modalPanel</property></emphasis> which wrapped with <emphasis role="bold"><property><h:panelGroup></property></emphasis> is rendered in case an error occurs,
+ its <emphasis><property>"rendered"</property></emphasis> attribute is binded with <code>isErrorExist</code> boolean method of <code>errorHandlerBean</code> class.
+ </para>
+ <programlisting role="XML"><![CDATA[...
+package org.richfaces.realworld.ui;
+...
+ at Name("errorHandlerBean")
+ at Scope(ScopeType.EVENT)
+ at AutoCreate
+public class ErrorHandlerBean {
+ private List<String> errors = new ArrayList<String>();
+
+ public List<String> getErrors() {
+ return errors;
+ }
+
+ public boolean isErrorExist(){
+ return errors.size() > 0 ;
+ }
+
+ @Observer(Constants.ADD_ERROR_EVENT)
+ public void addToErrors(String e){
+ errors.add(e);
+ }
+}
+...]]></programlisting>
+
+ <para>
+ The <code>addToErrors</code> method is annotated with <code>@Observer</code> annotation which observes all methods in the application with <code>ADD_ERROR_EVENT</code> annotation.
+ </para>
+
+ </section>
+
+
+
+ </section>
+
+
</chapter>
More information about the richfaces-svn-commits
mailing list