0

My question is similar to How to hide/show more text within a certain length (like youtube) or Readmore but for JSF. It's a very common metaphor on the web.

I have a page that displays a section with user-entered text, which may be short or it may be long. If it's long, the table height is unmanageable, so in those cases I'd like to show a portion of the text followed by a "(more)" link that will reveal the remaining text. After expansion, there would be a "(less)" link as well. (Note: My particular case has just text with newlines in it.)

Are there any pre-existing JSF components to do this? I've checked PrimeFaces and OmniFaces and ButterFaces and was surprised that I didn't see anything that jumped out at me as having this functionality. I'm sure I could make my own custom component using one of the techniques in the referenced StackOverflow question, but I'd rather not reinvent the wheel.

Community
  • 1
  • 1
Pixelstix
  • 702
  • 6
  • 21

2 Answers2

1

Maybe this is a good extension for ButterFaces. I will think about it.

But why do you need a JSF component? Just use Readmore.js.

Lars Michaelis
  • 559
  • 2
  • 6
  • 11
  • 1
    "But why do you need a JSF component?" (joke)Because: LAZY!(/joke) True, Readmore.js is probably a good way to go about it. And if I create my own component, I can always change out the implementation easily. I went ahead and used Readmore.js in a composite component - see other answer. – Pixelstix Mar 17 '17 at 15:35
1

Here's a quick composite component that uses readmore that can be used as a starting point for anyone else wanting something like this. There are a few unrelated features in it that are kind of hacked in (hard-coded style, hard-coded options to the readmore() function, etc.) that you would probably want to improve and customize. Suggestions for improvement welcome.

Parameters

  • value (String, Required): The text to display. Expected to be plain text with empty lines.
  • cols (integer, default=40): The number of columns to limit the width of the containing div to. If less than or equal to 0, then don't limit the width.
  • readmore (boolean, default=false): Whether to use the Readmore feature.
  • textonly (boolean, default=false): By default, the component assigns a "readonly" class to the containing div. Setting textonly to true does not assign the "readonly" class to the containing div.

Location: Under /resources/{samplelibrary}/readOnlyTextArea.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:composite="http://java.sun.com/jsf/composite"
>
    <composite:interface>
        <composite:attribute name="cols" default="40" type="java.lang.Integer"/>
        <composite:attribute name="value" required="true"/>
        <composite:attribute name="readmore" default="false" type="java.lang.Boolean"/>
        <composite:attribute name="textonly" default="false" type="java.lang.Boolean"/>
    </composite:interface>

    <composite:implementation>
        <h:outputScript library="samplelibrary" name="readmore.min.js" target="head"/>

        <div id="#{cc.clientId}_div" class="#{cc.attrs.textonly?'':'readonly'}"
                style="overflow: hidden; white-space: pre-wrap; #{cc.attrs.readmore ? '' : 'min-height: 1.3em;'} #{(cc.attrs.cols gt 0) ? 'width: '.concat(cc.attrs.cols / 2.09).concat('em; padding: 2px 2px 2px 2px;') : ''}">
            <h:outputText value="#{cc.attrs.value}"
        /></div>
        <ui:fragment rendered="#{cc.attrs.readmore}">
            <script type="text/javascript">
                $(window).ready(function() {
                    var comps = $(document.getElementById('#{cc.clientId}_div'));
                    comps.readmore({speed:300,collapsedHeight:54});
                });
            </script>
        </ui:fragment>

    </composite:implementation>
</html>

Here's some CSS for the readonly CSS class:

.readonly
{
    border: 1px solid #999;
    background-color: #eee;
    color: #333;
}
jeff
  • 3,618
  • 9
  • 48
  • 101
Pixelstix
  • 702
  • 6
  • 21