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= (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> " ); 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}