### Images Scroller

The Images Scroller implementation in the Photo Album application is basically <r:repeat> with the value attribute bound to `{model.selectedAlbum.images}` , which is a collection of images of the selected album and the <r:dataScroller> component tied to the <r:repeat> .

The source code you can find in the includes/images/imageScroller.xhtml file. Now let's go deeper into the details. The main component here is <r:repeat>:

                <r:repeat value="#{'#{'}model.selectedAlbum.images}" rows="5" var="img" id="repeat" rowKeyVar="rk">
                    <r:outputPanel layout="block"
                        styleClass="preview_box_photo_nav #{'#{'}model.selectedImage == img ? 'preview_box_photo_current' : 'preview_box_photo_default'}">
                        <h:panelGroup layout="block" styleClass="preview_box_photo_80">
                            <h:graphicImage styleClass="pr_photo_bg" value="/img/shell/frame_photo_80.png" />
                            <h:panelGrid cellpadding="0" cellspacing="2">
                                <h:panelGroup layout="block">
                                    <r:mediaOutput element="img" createContent="#{'#{'}imageLoader.paintImage}"
                                        value="#{'#{'}fileManager.transformPath(img.fullPath, '_small80')}" mimeType="image/jpeg" />
                                    <br />
                                </h:panelGroup>
                            </h:panelGrid>
                            <h:panelGroup layout="block" styleClass="photo_name">
                                <h:outputText value="#{'#{'}img.name}" />
                            </h:panelGroup>
                            <h:panelGroup layout="block" styleClass="photo_data">
                                <h:outputText value="#{'#{'}rk + 1}" />
                            </h:panelGroup>
                        </h:panelGroup>

                        <r:ajax event="click" render="mainImage, treePanel, imagesTable" listener="#{'#{'}controller.showImage(img)}" />
                    </r:outputPanel>
                </r:repeat>

Each element of the <r:repeat> has a corresponding <r:outputPanel> with the <r:mediaOutput> as a nested element. <r:mediaOutput> renders the thumbnail of the image. As the rows attribute is set to "5" ( `rows="5"` ), only 5 images are displayed on the page at a time.

As you've noticed, the currently selected image in the images scroller has different style, namely: a red frame around thumbnail, which is implemented with the highlighted code.

As you can see from the code snippet, identification of whether the currently selected image is the same image displayed by the <r:repeat> is performed in the styleClass, if it returns "true", different style is applied.

Each <r:repeat> has a corresponding <r:ajax> configured like this:

            <r:ajax disabled="#{'#{'}model.selectedImage == img}"
                event="click"
                render="mainImage, treePanel, imagesTable"
                listener="#{'#{'}controller.showImage(img)}" />

On every click <r:ajax> calls `{controller.showImage(img)}` method that sets the current image, thumbnail of which has just been clicked on. For more details please see Controller.java class.

To implement thumbnails scrolling effect the <r:datascroller> is attached to the <r:repeat>:

            <h:panelGrid columns="3">
                <h:panelGroup styleClass="image-scroller-left-arrow"
                    style="width: 56px; height:34px; display: inline-block;
                        filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/shell/arr_left.png',sizingMethod='scale');">
                    <h:graphicImage styleClass="ie6transparency" value="img/shell/arr_left.png"
                        onclick="#{'#{'}r:component('scroller')}.fastRewind()" />
                </h:panelGroup>

                <r:dataScroller page="#{'#{'}controller.page}" styleClass="image-scroller" lastPageMode="full" for="repeat"
                    render="imagesTable" boundaryControls="hide" stepControls="hide" id="scroller" fastControls="hide">
                </r:dataScroller>

                <h:panelGroup styleClass="image-scroller-right-arrow"
                    style="width: 56px; height:34px; display: inline-block;
                        filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/shell/arr_right.png',sizingMethod='scale');">
                    <h:graphicImage value="img/shell/arr_right.png" styleClass="ie6transparency" height="34" width="56" border="0"
                        onclick="#{'#{'}r:component('scroller')}.fastForward()" />
                </h:panelGroup>
            </h:panelGrid>

The page attribute identifies which page should be displayed right now. For instance, if you have only 20 images and the current image has the 12th index in the collection, then the 3rd page will be displayed:

                public Integer getPage() {
                    if (currentPage == 0) {
                        Integer index = model.getSelectedAlbum().getIndex(model.getSelectedImage());
                        currentPage = index / 5 + 1;
                    }
                    return currentPage;
                }

The `lastPageMode="full"` attribute ensures that 5 thumbnails are always shown on the page. If this attribute hadn't been configured like this, in case the 19th thumbnail out of 20 had been selected then only 2 last thumbnails would have been displayed.

As you can see, <r:dataScroller> has a slightly different look-and-feel, the trick is in hiding the original controls - `stepControls="hide"` , `fastControls="hide"` - and using custom elements to control the scrolling through JavaScript: `onclick="#{r:component('scroller')}.fastRewind()"` .

To get more details about the <r:repeat> and <r:dataScroller> components please visit Showcase web page and RichFaces Developer Guide