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 */
019 package org.apache.wiki.tags;
020
021 import java.io.IOException;
022
023 import javax.servlet.jsp.jstl.fmt.LocaleSupport;
024
025 import 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= (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 */
058 public 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 public void initTag()
073 {
074 super.initTag();
075 m_start = 0;
076 m_total = 0;
077 m_pagesize = 20;
078 m_maxlinks = 9;
079 m_fmtkey = null;
080 m_href = null;
081 m_onclick = null;
082 }
083
084 public void setStart(int arg)
085 {
086 m_start = arg;
087 }
088
089 public void setTotal(int arg)
090 {
091 m_total = arg;
092 }
093
094 public void setPagesize(int arg)
095 {
096 m_pagesize = arg;
097 }
098
099 public void setMaxlinks(int arg)
100 {
101 m_maxlinks = arg;
102 if( m_maxlinks % 2 == 0 ) m_maxlinks--; /* must be odd */
103 }
104
105 public void setFmtkey(String arg)
106 {
107 m_fmtkey = arg;
108 }
109
110 public void setHref(String arg)
111 {
112 m_href = arg;
113 }
114
115 public void setOnclick(String arg)
116 {
117 m_onclick = arg;
118 }
119
120
121 // 0 20 40 60
122 // 0 20 40 60 80 next last
123 // first previous 20 40 *60* 80 100 next last
124 // fist previous 40 60 80 100 120
125 public int doWikiStartTag()
126 throws IOException
127 {
128 if( m_total <= m_pagesize ) return SKIP_BODY;
129
130 StringBuffer pagination = new StringBuffer();
131
132 if( m_start > m_total ) m_start = m_total;
133 if( m_start < ALLITEMS ) m_start = 0;
134
135 int maxs = m_pagesize * m_maxlinks;
136 int mids = m_pagesize * ( m_maxlinks / 2 );
137
138 pagination.append( "<div class='pagination'>");
139
140 pagination.append( LocaleSupport.getLocalizedMessage(pageContext, m_fmtkey )+ " " );
141
142 int cursor = 0;
143 int cursormax = m_total;
144
145 if( m_total > maxs ) //need to calculate real window ends
146 {
147 if( m_start > mids ) cursor = m_start - mids;
148 if( (cursor + maxs) > m_total )
149 cursor = ( ( 1 + m_total/m_pagesize ) * m_pagesize ) - maxs ;
150
151 cursormax = cursor + maxs;
152 }
153
154
155 if( ( m_start == ALLITEMS ) || (cursor > 0) )
156 {
157 appendLink ( pagination, 0, m_fmtkey + ".first" );
158 }
159
160
161 if( (m_start != ALLITEMS ) && (m_start-m_pagesize >= 0) )
162 {
163 appendLink( pagination, m_start-m_pagesize, m_fmtkey + ".previous" );
164 }
165
166 if( m_start != ALLITEMS )
167 {
168 while( cursor < cursormax )
169 {
170 if( cursor == m_start )
171 {
172 pagination.append( "<span class='cursor'>" );
173 pagination.append( 1 + cursor/m_pagesize );
174 pagination.append( "</span>" );
175 }
176 else
177 {
178 appendLink( pagination, cursor, 1+cursor/m_pagesize );
179 }
180 cursor += m_pagesize;
181 }
182 }
183
184
185 if( (m_start != ALLITEMS ) && (m_start + m_pagesize < m_total) )
186 {
187 appendLink( pagination, m_start+m_pagesize, m_fmtkey + ".next" );
188
189 if( (m_start == ALLITEMS ) || (cursormax < m_total) )
190 appendLink ( pagination, ( (m_total/m_pagesize) * m_pagesize ), m_fmtkey + ".last" );
191 }
192
193 if( m_start == ALLITEMS )
194 {
195 pagination.append( "<span class='cursor'>" );
196 pagination.append( LocaleSupport.getLocalizedMessage(pageContext, m_fmtkey + ".all" ) );
197 pagination.append( "</span> " );
198 }
199 else
200 {
201 appendLink ( pagination, ALLITEMS, m_fmtkey + ".all" );
202 }
203
204 //(Total items: " + m_total + ")" );
205 pagination.append( LocaleSupport.getLocalizedMessage(pageContext, m_fmtkey + ".total",
206 new Object[]{ m_total } ) );
207
208 pagination.append( "</div>" );
209
210
211 /* +++ processing done +++ */
212
213 String p = pagination.toString();
214
215 pageContext.getOut().println( p );
216
217 pageContext.setAttribute( "pagination", p ); /* and cache for later use in page context */
218
219 return SKIP_BODY;
220 }
221
222
223 /**
224 * Generate pagination links <a href='' title='' onclick=''>text</a>
225 * for pagination blocks starting a page.
226 * Uses m_href and m_onclick as attribute patterns
227 * '%s' in the patterns are replaced with page offset
228 *
229 * @param sb : stringbuffer to write output to
230 * @param page : start of page block
231 * @param onclick : link text
232 *
233 **/
234 private void appendLink( StringBuffer sb, int page, String fmttextkey )
235 {
236 appendLink2( sb, page, LocaleSupport.getLocalizedMessage( pageContext, fmttextkey ) );
237 }
238 private void appendLink( StringBuffer sb, int page, int paginationblock )
239 {
240 appendLink2( sb, page, Integer.toString( paginationblock ) );
241 }
242 private void appendLink2( StringBuffer sb, int page, String text )
243 {
244 sb.append( "<a title=\"" );
245 if( page == ALLITEMS )
246 {
247 sb.append( LocaleSupport.getLocalizedMessage( pageContext, m_fmtkey + ".showall.title" ) );
248 }
249 else
250 {
251 sb.append( LocaleSupport.getLocalizedMessage( pageContext, m_fmtkey + ".show.title",
252 new Object[]{ page + 1, page + m_pagesize } ) );
253 }
254 sb.append( "\" " );
255
256 if( m_href != null )
257 {
258 sb.append( "href=\"" );
259 sb.append( TextUtil.replaceString( m_href, "%s", Integer.toString( page ) ) );
260 sb.append( "\" " );
261 }
262
263 if( m_onclick != null )
264 {
265 sb.append( "onclick=\"" );
266 sb.append( TextUtil.replaceString( m_onclick, "%s", Integer.toString( page ) ) );
267 sb.append( "\" " );
268 }
269
270 sb.append( ">" );
271 sb.append( text );
272 sb.append( "</a>" );
273 }
274
275 }