    001/*
    002    Licensed to the Apache Software Foundation (ASF) under one
    003    or more contributor license agreements.  See the NOTICE file
    004    distributed with this work for additional information
    005    regarding copyright ownership.  The ASF licenses this file
    006    to you under the Apache License, Version 2.0 (the
    007    "License"); you may not use this file except in compliance
    008    with the License.  You may obtain a copy of the License at
    009
    010       http://www.apache.org/licenses/LICENSE-2.0
    011
    012    Unless required by applicable law or agreed to in writing,
    013    software distributed under the License is distributed on an
    014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    015    KIND, either express or implied.  See the License for the
    016    specific language governing permissions and limitations
    017    under the License.
    018 */
    019package org.apache.wiki.tags;
    020
    021import java.io.IOException;
    022
    023import javax.servlet.jsp.jstl.fmt.LocaleSupport;
    024
    025import org.apache.wiki.util.TextUtil;
    026
    027
    028/**
    029 *  Calculate pagination string. Used for page-info and search results
    030 *
    031 *  <P><B>Attributes</B></P>
    032 *  <UL>
    033 *    <LI> start - start item of the page to be highlighted
    034 *    <LI> total - total number of items
    035 *    <LI> pagesize - total number of items per page
    036 *    <LI> maxlinks - number of page links to be generated
    037 *    <LI> fmtkey - pagination prefix of the i18n resource keys. Following keys are used:
    038 *    <br>fmtkey="info.pagination"
    039 *      <UL>
    040 *        <LI> info.pagination.first=<span class="first">First</span>
    041 *        <LI> info.pagination.last=<span class="last">Last</span>
    042 *        <LI> info.pagination.previous=<span class="prev">Previous</span>
    043 *        <LI> info.pagination.next=<span class="next">Next</span>
    044 *        <LI> info.pagination.all=<span class="all">all</span>
    045 *        <LI> info.pagination.total=&nbsp;(Total items: {0} )
    046 *        <LI> info.pagination.show.title=Show items from {0} to {1}
    047 *        <LI> info.pagination.showall.title=Show all items
    048 *      </UL>
    049 *  </UL>
    050 *  <P>Following optional attributes can be parameterized with '%s' (item count)</P>
    051 *  <UL>
    052 *    <LI> href - href of each page link. (optional)
    053 *    <LI> onclick - onclick of each page link. (optional)
    054 *  </UL>
    055 *
    056 *  @since 2.5.109
    057 */
    058public class SetPaginationTag
    059    extends WikiTagBase
    060{
    061    private static final long serialVersionUID = 0L;
    062    private static final int ALLITEMS = -1;
    063
    064    private int m_start;
    065    private int m_total;
    066    private int m_pagesize;
    067    private int m_maxlinks;
    068    private String m_fmtkey;
    069    private String m_href;
    070    private String m_onclick;
    071
    072    @Override
    073    public void initTag()
    074    {
    075        super.initTag();
    076        m_start = 0;
    077        m_total = 0;
    078        m_pagesize = 20;
    079        m_maxlinks = 9;
    080        m_fmtkey = null;
    081        m_href = null;
    082        m_onclick = null;
    083    }
    084
    085    public void setStart(final int arg)
    086    {
    087        m_start = arg;
    088    }
    089
    090    public void setTotal(final int arg)
    091    {
    092        m_total = arg;
    093    }
    094
    095    public void setPagesize(final int arg)
    096    {
    097        m_pagesize = arg;
    098    }
    099
    100    public void setMaxlinks(final int arg)
    101    {
    102        m_maxlinks = arg;
    103        if( m_maxlinks % 2 == 0 ) m_maxlinks--; /* must be odd */
    104    }
    105
    106    public void setFmtkey(final String arg)
    107    {
    108        m_fmtkey = arg;
    109    }
    110
    111    public void setHref(final String arg)
    112    {
    113        m_href = arg;
    114    }
    115
    116    public void setOnclick(final String arg)
    117    {
    118        m_onclick = arg;
    119    }
    120
    121
    122    // 0 20 40 60
    123    // 0 20 40 60 80 next last
    124    // first previous 20 40 *60* 80 100 next last
    125    // fist previous 40 60 80 100 120
    126    @Override
    127    public int doWikiStartTag()
    128        throws IOException
    129    {
    130        if( m_total <= m_pagesize ) return SKIP_BODY;
    131
    132        final StringBuilder pagination = new StringBuilder();
    133
    134        if( m_start > m_total ) m_start = m_total;
    135        if( m_start < ALLITEMS ) m_start = 0;
    136
    137        final int maxs = m_pagesize * m_maxlinks;
    138        final int mids = m_pagesize * ( m_maxlinks / 2 );
    139
    140        pagination.append( "<div class='pagination'>");
    141
    142        pagination.append( LocaleSupport.getLocalizedMessage( pageContext, m_fmtkey ) ).append( " " );
    143
    144        int cursor = 0;
    145        int cursormax = m_total;
    146
    147        if( m_total > maxs )   //need to calculate real window ends
    148        {
    149          if( m_start > mids ) cursor = m_start - mids;
    150          if( (cursor + maxs) > m_total )
    151            cursor = ( ( 1 + m_total/m_pagesize ) * m_pagesize ) - maxs ;
    152
    153          cursormax = cursor + maxs;
    154        }
    155
    156
    157        if( ( m_start == ALLITEMS ) || (cursor > 0) )
    158        {
    159            appendLink ( pagination, 0, m_fmtkey + ".first" );
    160        }
    161
    162
    163        if( (m_start != ALLITEMS ) && (m_start-m_pagesize >= 0) )
    164        {
    165            appendLink( pagination, m_start-m_pagesize, m_fmtkey + ".previous" );
    166        }
    167
    168        if( m_start != ALLITEMS )
    169        {
    170          while( cursor < cursormax )
    171          {
    172            if( cursor == m_start )
    173            {
    174              pagination.append( "<span class='cursor'>" );
    175              pagination.append( 1 + cursor/m_pagesize );
    176              pagination.append( "</span>" );
    177            }
    178            else
    179            {
    180              appendLink( pagination, cursor, 1+cursor/m_pagesize );
    181            }
    182            cursor += m_pagesize;
    183          }
    184        }
    185
    186
    187        if( (m_start != ALLITEMS ) && (m_start + m_pagesize < m_total) )
    188        {
    189            appendLink( pagination, m_start+m_pagesize, m_fmtkey + ".next" );
    190
    191        if( (m_start == ALLITEMS ) || (cursormax < m_total) )
    192          appendLink ( pagination, ( (m_total/m_pagesize) * m_pagesize ), m_fmtkey + ".last" );
    193        }
    194
    195        if( m_start == ALLITEMS )
    196        {
    197          pagination.append( "<span class='cursor'>" );
    198          pagination.append( LocaleSupport.getLocalizedMessage(pageContext, m_fmtkey + ".all" ) );
    199          pagination.append( "</span>&nbsp;&nbsp;" );
    200        }
    201        else
    202        {
    203          appendLink ( pagination, ALLITEMS, m_fmtkey + ".all" );
    204        }
    205
    206        //(Total items: " + m_total + ")" );
    207        pagination.append( LocaleSupport.getLocalizedMessage(pageContext, m_fmtkey + ".total",
    208                           new Object[]{ m_total } ) );
    209
    210        pagination.append( "</div>" );
    211
    212
    213        /* +++ processing done +++ */
    214
    215        final String p = pagination.toString();
    216
    217        pageContext.getOut().println( p );
    218
    219        pageContext.setAttribute( "pagination", p ); /* and cache for later use in page context */
    220
    221        return SKIP_BODY;
    222    }
    223
    224
    225    /**
    226     * Generate pagination links <a href='' title='' onclick=''>text</a>
    227     * for pagination blocks starting a page.
    228     * Uses m_href and m_onclick as attribute patterns
    229     * '%s' in the patterns are replaced with page offset
    230     *
    231     * @param sb  : stringbuilder to write output to
    232     * @param page : start of page block
    233     *
    234     **/
    235    private void appendLink(final StringBuilder sb, final int page, final String fmttextkey )
    236    {
    237        appendLink2( sb, page, LocaleSupport.getLocalizedMessage( pageContext, fmttextkey ) );
    238    }
    239    private void appendLink(final StringBuilder sb, final int page, final int paginationblock )
    240    {
    241        appendLink2( sb, page, Integer.toString( paginationblock ) );
    242    }
    243    private void appendLink2(final StringBuilder sb, final int page, final String text )
    244    {
    245        sb.append( "<a title=\"" );
    246        if( page == ALLITEMS )
    247        {
    248            sb.append( LocaleSupport.getLocalizedMessage( pageContext, m_fmtkey + ".showall.title" ) );
    249        }
    250        else
    251        {
    252            sb.append( LocaleSupport.getLocalizedMessage( pageContext, m_fmtkey + ".show.title",
    253                       new Object[]{ page + 1, page + m_pagesize } ) );
    254        }
    255        sb.append( "\" " );
    256
    257        if( m_href != null )
    258        {
    259            sb.append( "href=\"" );
    260            sb.append( TextUtil.replaceString( m_href, "%s", Integer.toString( page ) ) );
    261            sb.append( "\" " );
    262        }
    263
    264        if( m_onclick != null )
    265        {
    266            sb.append( "onclick=\"" );
    267            sb.append( TextUtil.replaceString( m_onclick, "%s", Integer.toString( page ) ) );
    268            sb.append( "\" " );
    269        }
    270
    271        sb.append( ">" );
    272        sb.append( text );
    273        sb.append( "</a>" );
    274    }
    275
    276}