Oh Baby, It's So Hot When You Paginate! (aka Paginating Results In ColdFusion)

<cfcomponent
	displayname="DataPager"
	output="no"
	hint="Handles data pagination mathematics.">
 
	<!--- Run the pseudo constructor to set up default data structures. --->
	<cfscript>
 
		// Set up an instance structure to hold instance data.
		VARIABLES.Instance = StructNew();
 
		// Set default instance data.
		VARIABLES.Instance.Page = 0;
		VARIABLES.Instance.Pages = 0;
		VARIABLES.Instance.PageSize = 15;
		VARIABLES.Instance.Bucket = 0;
		VARIABLES.Instance.Buckets = 0;
		VARIABLES.Instance.BucketSize = 10;
		VARIABLES.Instance.BucketStartPage = 0;
		VARIABLES.Instance.BucketEndPage = 0;
		VARIABLES.Instance.RecordCount = 0;
		VARIABLES.Instance.Offset = 0;
		VARIABLES.Instance.Prev = 0;
		VARIABLES.Instance.Next = 0;
		VARIABLES.Instance.End = 0;
		VARIABLES.Instance.Start = 0;
		VARIABLES.Instance.URL = "";
 
	</cfscript>
 
 
	<cffunction name="Init" access="public" returntype="DataPager" output="no"
		hint="Returns an initialized data pager instance.">
 
		<!--- REturn this reference. --->
		<cfreturn THIS />
	</cffunction>
 
 
	<cffunction name="Calculate" access="public" returntype="boolean" output="no"
		hint="Calculates the page instance data based on the parts that were manually set.">
 
		<cfscript>
 
			// Check properites for valid values and ranges. If any of the values is invalid,
			// set the default or most appropriate value.
 
			if (VARIABLES.Instance.PageSize LT 1){
				VARIABLES.Instance.PageSize = 15;
			}
 
			if (VARIABLES.Instance.BucketSize LT 1){
				VARIABLES.Instance.BucketSize = 5;
			}
 
			if (VARIABLES.Instance.Offset GT VARIABLES.Instance.RecordCount){
				VARIABLES.Instance.Offset = VARIABLES.Instance.RecordCount;
			}
 
			if (VARIABLES.Instance.Offset LT 1){
				VARIABLES.Instance.Offset = 1;
			}
 
 
			// Only update the list page if we have a record count to work with. Otherwise,
			// just return default values.
			if (VARIABLES.Instance.RecordCount GT 0){
 
				// Figure out how many total pages.
				VARIABLES.Instance.Pages = Ceiling(VARIABLES.Instance.RecordCount / VARIABLES.Instance.PageSize);
 
				// Figure out which page we are on.
				VARIABLES.Instance.Page = Ceiling(VARIABLES.Instance.Offset / VARIABLES.Instance.PageSize);
 
				// Figure out how many total buckets exist.
				VARIABLES.Instance.Buckets = Ceiling(VARIABLES.Instance.Pages / VARIABLES.Instance.BucketSize);
 
				// Figure out which bucket we are in.
				VARIABLES.Instance.Bucket = Ceiling(VARIABLES.Instance.Page / VARIABLES.Instance.BucketSize);
 
				// Get bucket start page.
				VARIABLES.Instance.BucketStartPage = (((VARIABLES.Instance.Bucket - 1) * VARIABLES.Instance.BucketSize) + 1);
 
				// Get bucket end page.
				VARIABLES.Instance.BucketEndPage = (VARIABLES.Instance.BucketStartPage + VARIABLES.Instance.BucketSize - 1);
 
				// Validate end bucket range.
				if (VARIABLES.Instance.BucketEndPage GT VARIABLES.Instance.Pages){
					VARIABLES.Instance.BucketEndPage = VARIABLES.Instance.Pages;
				}
 
 
				// Readjust the current offset by page. ie. Make the current offset the first item
				// on the current page.
				VARIABLES.Instance.Offset = (((VARIABLES.Instance.Page - 1) * VARIABLES.Instance.PageSize) + 1);
 
				// Calculate Prev Link.
				if (VARIABLES.Instance.Page GT 1){
					VARIABLES.Instance.Prev = (VARIABLES.Instance.Offset - VARIABLES.Instance.PageSize);
				}
 
				// Calculate Next Link.
				if (VARIABLES.Instance.Page LT VARIABLES.Instance.Pages){
					VARIABLES.Instance.Next = (VARIABLES.Instance.Offset + VARIABLES.Instance.PageSize);
				}
 
				// Set up start and end values.
				VARIABLES.Instance.Start = VARIABLES.Instance.Offset;
				VARIABLES.Instance.End = (VARIABLES.Instance.Offset + VARIABLES.Instance.PageSize - 1);
 
				// Validate the end row.
				if (VARIABLES.Instance.End GT VARIABLES.Instance.RecordCount){
					VARIABLES.Instance.End = VARIABLES.Instance.RecordCount;
				}
 
			}
 
			// Return out.
			return(true);
 
		</cfscript>
	</cffunction>
 
 
	<cffunction name="GetBucket" access="public" returntype="numeric" output="no"
		hint="Gets the current bucket.">
 
		<cfreturn VARIABLES.Instance.Bucket />
	</cffunction>
 
 
	<cffunction name="GetBucketEndPage" access="public" returntype="numeric" output="no"
		hint="Gets the last page in the current bucket.">
 
		<cfreturn VARIABLES.Instance.BucketEndPage />
	</cffunction>
 
 
	<cffunction name="GetBuckets" access="public" returntype="numeric" output="no"
		hint="Gets the number of buckets in the list pager.">
 
		<cfreturn VARIABLES.Instance.Buckets />
	</cffunction>
 
 
	<cffunction name="GetBucketSize" access="public" returntype="numeric" output="no"
		hint="Gets the bucket size.">
 
		<cfreturn VARIABLES.Instance.BucketSize />
	</cffunction>
 
 
	<cffunction name="GetBucketStartPage" access="public" returntype="numeric" output="no"
		hint="Gets the first page in the current bucket.">
 
		<cfreturn VARIABLES.Instance.BucketStartPage />
	</cffunction>
 
 
	<cffunction name="GetEnd" access="public" returntype="numeric" output="no"
		hint="Gets the last offset in the current page.">
 
		<cfreturn VARIABLES.Instance.End />
	</cffunction>
 
 
	<cffunction name="GetNext" access="public" returntype="numeric" output="no"
		hint="Gets the next page.">
 
		<cfreturn VARIABLES.Instance.Next />
	</cffunction>
 
 
	<cffunction name="GetOffset" access="public" returntype="numeric" output="no"
		hint="Gets the current offset">
 
		<cfreturn VARIABLES.Instance.Offset />
	</cffunction>
 
 
	<cffunction name="GetPage" access="public" returntype="numeric" output="no"
		hint="Gets the current page.">
 
		<cfreturn VARIABLES.Instance.Page />
	</cffunction>
 
 
	<cffunction name="GetPages" access="public" returntype="numeric" output="no"
		hint="Gets the number of pages in the list pager.">
 
		<cfreturn VARIABLES.Instance.Pages />
	</cffunction>
 
 
	<cffunction name="GetPageSize" access="public" returntype="numeric" output="no"
		hint="Gets the page size.">
 
		<cfreturn VARIABLES.Instance.PageSize />
	</cffunction>
 
 
	<cffunction name="GetPrev" access="public" returntype="numeric" output="no"
		hint="Gets the previous page.">
 
		<cfreturn VARIABLES.Instance.Prev />
	</cffunction>
 
 
	<cffunction name="GetRecordCount" access="public" returntype="numeric" output="no"
		hint="Gets the record count.">
 
		<cfreturn VARIABLES.Instance.RecordCount />
	</cffunction>
 
 
	<cffunction name="GetStart" access="public" returntype="numeric" output="no"
		hint="Gets the first offset in the current page.">
 
		<cfreturn VARIABLES.Instance.Start />
	</cffunction>
 
 
	<cffunction name="GetURL" access="public" returntype="numeric" output="no"
		hint="Gets the base url.">
 
		<cfreturn VARIABLES.Instance.URL />
	</cffunction>
 
 
	<cffunction name="HasMultiplePages" access="public" returntype="boolean" output="no"
		hint="Checks to see if the page had more than one page to display.">
 
		<cfreturn (VARIABLES.Instance.Pages GT 1) />
	</cffunction>
 
 
	<cffunction name="ReplaceOffset" access="public" returntype="string" output="no"
		hint="Replaces the [OFFSET] with the passed offset in the base url. This gives the user more flexibility as to how the offset is going to be used.">
 
		<!--- Define arguments. --->
		<cfargument name="Offset" type="numeric" required="yes" />
 
		<!--- Return the replaced url. --->
		<cfreturn ReplaceNoCase(VARIABLES.Instance.URL, "[OFFSET]", ARGUMENTS.Offset, "ALL") />
	</cffunction>
 
 
	<cffunction name="SetBucketSize" access="public" returntype="boolean" output="no"
		hint="Sets the bucket size (pages per bucket).">
 
		<!--- Define arguments. --->
		<cfargument name="BucketSize" type="numeric" required="yes" />
 
		<cfset VARIABLES.Instance.BucketSize = ARGUMENTS.BucketSize />
		<cfreturn true />
	</cffunction>
 
 
	<cffunction name="SetOffset" access="public" returntype="boolean" output="no"
		hint="Sets the page offset.">
 
		<!--- Define arguments. --->
		<cfargument name="Offset" type="numeric" required="yes" />
 
		<cfset VARIABLES.Instance.Offset = ARGUMENTS.Offset />
		<cfreturn true />
	</cffunction>
 
 
	<cffunction name="SetPageSize" access="public" returntype="boolean" output="no"
		hint="Sets the page size.">
 
		<!--- Define arguments. --->
		<cfargument name="PageSize" type="numeric" required="yes" />
 
		<cfset VARIABLES.Instance.PageSize = ARGUMENTS.PageSize />
		<cfreturn true />
	</cffunction>
 
 
	<cffunction name="SetRecordCount" access="public" returntype="boolean" output="no"
		hint="Sets the record count.">
 
		<!--- Define arguments. --->
		<cfargument name="RecordCount" type="numeric" required="yes" />
 
		<cfset VARIABLES.Instance.RecordCount = ARGUMENTS.RecordCount />
		<cfreturn true />
	</cffunction>
 
 
	<cffunction name="SetUrl" access="public" returntype="boolean" output="no"
		hint="Sets the base url.">
 
		<!--- Define arguments. --->
		<cfargument name="Url" type="string" required="yes" />
 
		<cfset VARIABLES.Instance.Url = ARGUMENTS.Url />
		<cfreturn true />
	</cffunction>
 
</cfcomponent>

For Cut-and-Paste