8 Replies Latest reply on Jun 27, 2011 9:44 AM by vikymorrone

    RichFaces & Slideshow

    cstefkivoila

      Does somebody know a slideshow component or javascript I could use with RichFaces.
      I tried to use the very cool SmoothGallery one, but there are conflicts with RichFaces javascript (script.aculo.us) and Mootools.
      Thanks.

        • 1. Re: RichFaces & Slideshow
          rhasselbaum

          I'm also looking for a way to implement a slideshow with RichFaces. I have it mostly working: I use <a4j:poll> to rerender an IMG element at periodic intervals. But I'd like to be able to do a smooth fade between images, and so far I've had no luck with <rich:effect>. Any suggestions?

          • 2. Re: RichFaces & Slideshow
            rhasselbaum

            FWIW, I did get this working. I created a page-scoped controller component in Seam that supplies two overlapping <h:graphicImage> elements with new images on a rotating basis each time an action method is called. I use <a4j:pll> to call the action periodically and rerender the new "active" image. And finally, a little bit of JavaScript kicks off a Fade effect and switches the z-index of the two images in response to the <a4j:poll>'s oncomplete event.

            One nice thing is that it degrades gracefully if the user has JavaScript disabled. They just see a random image when the page loads.

            • 3. Re: RichFaces & Slideshow
              cstefkivoila

              Could you please provide us an example of your code?

              Thanks.

              • 4. Re: RichFaces & Slideshow
                rhasselbaum

                I could do that, although I'm planning to revisit this code when I get some time. It works fine most of the time, but I'm also using Seam, and I've noticed that on occasion, the polling request redirects the user to the no-conversation-view page. This seems to happen when the polling request overlaps another request that is beginning or ending a Seam conversation. Need to investigate how to prevent this.

                • 5. Re: RichFaces & Slideshow

                  Hi,
                  @rhasselbaum
                  Would be great if you could share your work here or in wiki.

                  Thanks

                  • 6. Re: RichFaces & Slideshow
                    rhasselbaum

                    Sure. It would probably have been better to implement this as a JSF component, but I haven't learned how to do that. Anyway, here's the controller class (a Seam component).

                    /**
                     * Controller for a simple slideshow UI element. The controller selects images
                     * randomly from a resource folder for display. The UI is expected to consist of
                     * two overlapping image elements (called "frames", but not in the HTML sense).
                     * These are updated with new images on an alternating basis every time the
                     * {@link #transition()} method is called. The reason for having two frames
                     * instead of one is that it enables the implementation of smooth transitions
                     * such as fading on the client side. Each frame is assigned an ID that
                     * corresponds to the element (e.g. HTML) ID. The controller exposes properties
                     * that allow the view to determine which frame should be active and visible at
                     * any given time. Initially, the second frame is active, since it would be the
                     * topmost element in z-order by default.
                     */
                    @Name("slideShowController")
                    @Scope(ScopeType.PAGE)
                    public class SlideShowController implements Serializable {
                    
                     /**
                     * The path relative to the web root containing random images to be chosen.
                     * The path should begin and end with a forward slash and contain only
                     * eligible images. At least two images MUST be present in the path.
                     */
                     private static final String IMAGES_PATH = "/images/houses/";
                    
                     /**
                     * The first frame component ID.
                     */
                     private String m_firstFrameComponentId;
                    
                     /**
                     * The second frame component ID.
                     */
                     private String m_secondFrameComponentId;
                    
                     /**
                     * Resource paths to image files.
                     */
                     private List<String> m_imageFiles;
                    
                     /**
                     * Path to the image contained in the first frame.
                     */
                     private String m_firstFrameImage;
                    
                     /**
                     * Path to the image contained in the second frame.
                     */
                     private String m_secondFrameImage;
                    
                     /**
                     * True if the first frame is showing. False if the second frame is showing.
                     */
                     private boolean m_showingFirstFrame = false;
                    
                     /**
                     * The Seam context.
                     */
                     @In(value = "facesContext")
                     private FacesContext m_facesContext;
                    
                     /**
                     * Create new instance.
                     */
                     public SlideShowController() {
                     // No op.
                     }
                    
                     /**
                     * Set up initial controller state.
                     */
                     @Create
                     public void init() {
                     ExternalContext externalContext = m_facesContext.getExternalContext();
                     Set<String> resourcePaths = externalContext.getResourcePaths(IMAGES_PATH);
                     if (resourcePaths.size() < 2) {
                     // We can get into an infinite loop if there are less than two
                     // unique images.
                     throw new IllegalStateException("Image list must have at least two images.");
                     }
                     String uuid = UUID.randomUUID().toString();
                     if (m_firstFrameComponentId == null)
                     m_firstFrameComponentId = "frame1-" + uuid;
                     if (m_secondFrameComponentId == null)
                     m_secondFrameComponentId = "frame2-" + uuid;
                     m_imageFiles = Collections.unmodifiableList(new ArrayList<String>(resourcePaths));
                     m_firstFrameImage = getRandomImageFile();
                     m_secondFrameImage = m_firstFrameImage;
                     }
                    
                     /**
                     * Choose and return a random image file from the images folder.
                     */
                     private String getRandomImageFile() {
                     return m_imageFiles.get((int) (Math.random() * (double) m_imageFiles.size()));
                     }
                    
                     /**
                     * Path to the image contained in the first frame.
                     */
                     public String getFirstFrameImage() {
                     return m_firstFrameImage;
                     }
                    
                     /**
                     * Path to the image contained in the second frame.
                     */
                     public String getSecondFrameImage() {
                     return m_secondFrameImage;
                     }
                    
                     /**
                     * Get component ID of the currently active frame.
                     */
                     public String getActiveFrameComponentId() {
                     if (m_showingFirstFrame) {
                     return m_firstFrameComponentId;
                     } else {
                     return m_secondFrameComponentId;
                     }
                     }
                    
                     /**
                     * Get component ID of the currently active frame.
                     */
                     public String getInactiveFrameComponentId() {
                     if (m_showingFirstFrame) {
                     return m_secondFrameComponentId;
                     } else {
                     return m_firstFrameComponentId;
                     }
                     }
                    
                     /**
                     * True if the first frame is showing. False if the second frame is showing.
                     */
                     public boolean isShowingFirstFrame() {
                     return m_showingFirstFrame;
                     }
                    
                     /**
                     * The first frame component ID.
                     */
                     public String getFirstFrameComponentId() {
                     return m_firstFrameComponentId;
                     }
                    
                     /**
                     * The first frame component ID.
                     */
                     public void setFirstFrameComponentId(String firstFrameComponentId) {
                     m_firstFrameComponentId = firstFrameComponentId;
                     }
                    
                     /**
                     * The second frame component ID.
                     */
                     public String getSecondFrameComponentId() {
                     return m_secondFrameComponentId;
                     }
                    
                     /**
                     * The second frame component ID.
                     */
                     public void setSecondFrameComponentId(String secondFrameComponentId) {
                     m_secondFrameComponentId = secondFrameComponentId;
                     }
                    
                     /**
                     * The Faces context.
                     */
                     public FacesContext getFacesContext() {
                     return m_facesContext;
                     }
                    
                     /**
                     * The Faces context.
                     */
                     public void setFacesContext(FacesContext facesContext) {
                     m_facesContext = facesContext;
                     }
                    
                     /**
                     * Transition from one frame to the other. A new, random image is selected
                     * for the next frame, which is guaranteed to be different from the prior
                     * frame. At least two images MUST be present in the image path.
                     */
                     public void transition() {
                     if (m_showingFirstFrame) {
                     // Fetch new (unique!) image for the second frame.
                     do {
                     m_secondFrameImage = getRandomImageFile();
                     } while (m_secondFrameImage.equals(m_firstFrameImage));
                     } else {
                     // Fetch new (unique!) image for the first frame.
                     do {
                     m_firstFrameImage = getRandomImageFile();
                     } while (m_firstFrameImage.equals(m_secondFrameImage));
                     }
                     // Switch active frames.
                     m_showingFirstFrame = !m_showingFirstFrame;
                     }
                    }
                    
                    


                    Next. here is the fragment of XHTML that contains the images.

                    <div id="slideshow-container">
                    <rich:effect name="hideSlide" type="Fade" />
                    <a4j:poll action="#{slideShowController.transition()}" interval="10000" timeout="10000"
                     reRender="#{slideShowController.activeFrameComponentId}"
                     oncomplete="BHA_SlideShow.switchFrame('#{slideShowController.inactiveFrameComponentId}', '#{slideShowController.activeFrameComponentId}', hideSlide)" />
                    <h:graphicImage value="#{slideShowController.firstFrameImage}" id="#{slideShowController.firstFrameComponentId}" />
                    <h:graphicImage value="#{slideShowController.secondFrameImage}" id="#{slideShowController.secondFrameComponentId}" />
                    </div>
                    


                    Here are the CSS styles for the relevant bits:

                    #slideshow-container {
                     border: 1px solid;
                     border-color: #ffff04;
                     margin: 10px;
                     width: 180px;
                     height: 135px;
                    }
                    
                    #slideshow-container img {
                     position: absolute;
                     margin: 0px;
                     width: inherit;
                     height: inherit;
                    }


                    And finally, the bit of JavaScript that gets called for the oncomplete event.

                    /**
                     * Implement simple slideshow transition in concert with RuchFaces/Script.aculo.us.
                     * Clients should call BHA_SlideShow.switchFrame to effect a smooth transition betweenn
                     * two overlapping image (slide) elements.
                     */
                    var BHA_SlideShow = function() {
                     return {
                    
                     /**
                     * Implement transition between two overlapping slide elements.
                     * fromElementId: The slide element we're transitioning from. Its z-index should be 2 at the
                     * start of this call. It will be moved down to 1.
                     * toElementId: The slide element we're transitioning to. Its z-index should be 1 at the start
                     * of this call. It will be moved up to 2.
                     */
                     switchFrame : function(fromElementId, toElementId, hideFunction) {
                     var transitionTimeSec = 2.0
                     hideFunction({targetId:fromElementId,duration:transitionTimeSec});
                     setTimeout("BHA_SlideShow.reorderFrames('"+ fromElementId + "', '"+ toElementId +"')", transitionTimeSec * 1000);
                     },
                    
                     /**
                     * Change the z-order of two elements.
                     * newBottomElementId: The element to be moved to the bottom. It is given z-index 2.
                     * newTopElementId: The element to be moved to the top. It is given z-index 1.
                     */
                     reorderFrames : function(newBottomElementId, newTopElementId) {
                     document.getElementById(newTopElementId).style.zIndex = 2;
                     document.getElementById(newBottomElementId).style.zIndex = 1;
                     }
                     };
                    }();
                    


                    Any suggestions for improvement welcome--especially if you know how to prevent the Seam conversation problem I mentioned earlier!

                    • 7. RichFaces & Slideshow
                      arturfriesen

                      shouldnt the a4j:poll - tag be inside the h:form-tag?

                       

                      on my side its only working this way.

                      • 8. Re: RichFaces & Slideshow
                        vikymorrone

                        Hi

                        Does somebody know how to do a slideshow with a description in each image with RichFaces?.

                         

                        Thanks.