Hello all.

Not sure if this is really a bug, as the paged may have the correct behaviour in other circumstances, and break in those circumstances if the changes I suggest are applied. Still, I didn't know where to post this (mods, if it should be posted elsewhere, please let me know).

First of all, the issue:

I have a category page (template: products in grid) with 10+ pages of products in it. I wanted to have the following type of pager:

1... 4 5 6...10

so I issued the following in the markup:
       <nopCommerce:Pager 
      runat="server"
      ID="productsPager"
      ShowPagerItems="true"
      ShowFirst="true"
      ShowPrevious="false"
      ShowIndividualPages="true"
      ShowNext="false"
      ShowLast="true"
      IndividualPagesDisplayedCount="3"
      CurrentPageText="Pager.CurrentPage" />


and in the codebehind:

this.productsPagerTop.FirstButtonText = "1";
this.productsPagerTop.LastButtonText=this.productsPagerTop.TotalPages.ToString();



It didn't work, as when I clicked on page 3, the first page link would vanish. Same thing happened to the last page link, when I clicked on 8, so it would be something like:

2 3 4 ... 10

or

1 ... 7 8 9

It was clear that there was something going on in the pager data binding. I traced the erratic behaviour in the conditions used in the data binding methods. First, the bindFirst(). The original code is:

        protected virtual void BindFirst(Control control)
        {
            if ((this.PageIndex >= 3) && (this.TotalPages > this.IndividualPagesDisplayedCount))
            {
                 //display first page link, and possibly the ellipsis
             }
         }


this effectively says: start showing the first page link from the fourth page onwards, and only if all pages are more than the number of individual pages to show. So it makes sense that it didn't render the first page link on page 3. A bit of math reveals that the first page link should be displayed when all of the following are true:
a) if the individual pages shown do not include the first page. effectively, this means that the current page index (zero based) should be larger than
this.IndividualPagesDisplayedCount/2
(integer division: for
this.IndividualPagesDisplayedCount=3
, this means that current page index should be more than 1 (i.e. third page onwards), while for a value of, say, 5, the first page index that fires the rendering is 3 (i.e. fourth page, correctly).
b) all pages are more than the number of individual pages to show.

I'm not sure, but I think that (a) implies (b).

Anyway, I changed the code to

        protected virtual void BindFirst(Control control)
        {
            if ((this.PageIndex > this.IndividualPagesDisplayedCount/2) && (this.TotalPages > this.IndividualPagesDisplayedCount))
            {
                 //display first page link, and possibly the ellipsis
             }
         }


Now there was another issue: the ellipsis would show up from the third page onwards, showing something like this:

1 ... 2 3 4 ...10

which is also wrong.

The condition for this was
//...
                if ((this.ShowIndividualPages || (this.ShowPrevious && (this.PageIndex > 0))) || this.ShowLast)
                {
                    control.Controls.Add(new LiteralControl("&nbsp;...&nbsp;"));
                }
//...


this says that
a)if ShowIndividualPages is set to true, render the ellipsis whenever the first page link is rendered, no matter what - wrong.
b) if ShowLast is set to true, render the ellipsis whenever the first page link is rendered, no matter what - wrong (why would the ShowLast property affect whether the ellipsis between the first and the previous page link will show?)
c) if ShowPrevious is set to truw, and we're not in the first page,  render the ellipsis whenever the first page link is rendered, no matter what - wrong.

All it took, was an extra condition:

//...
                if (((this.ShowIndividualPages || (this.ShowPrevious && (this.PageIndex > 0))) || this.ShowLast) && this.PageIndex > ((this.IndividualPagesDisplayedCount/2)+1))
                {
                    control.Controls.Add(new LiteralControl("&nbsp;...&nbsp;"));
                }
//...


the extra condition effectively says that the ellipsis should be displayed only if there is at least one page between the first one, and the first of the individually rendered pages. So for
this.IndividualPagesDisplayedCount=3
, this condition is true from the fourth page onward, thus providing the correct result of:

1 2 3 ... 10
1 2 3 ... 10
1 2 3 4 ...10
1 ...3 4 5 ...10

etc.

Similar changes took place in the bindLast() method, to affect the behaviour of the last page link, though the math was a little bit more involved to get the effect right. All in all, the two changed methods are:

        protected virtual void BindFirst(Control control)
        {
      if ((this.PageIndex > this.IndividualPagesDisplayedCount / 2) && (this.TotalPages > this.IndividualPagesDisplayedCount))
            {
                HyperLink child = new HyperLink();
                child.Text = this.FirstButtonText;
                child.NavigateUrl = this.GetPageNavigateUrl(1);
                control.Controls.Add(child);

        if (((this.ShowIndividualPages || (this.ShowPrevious && (this.PageIndex > 0))) || this.ShowLast) && this.PageIndex > ((this.IndividualPagesDisplayedCount / 2) + 1))
                {
                    control.Controls.Add(new LiteralControl("&nbsp;...&nbsp;"));
                }
            }
        }

and
        protected virtual void BindLast(Control control)
        {
      if (((this.PageIndex + 1 + this.IndividualPagesDisplayedCount / 2) < this.TotalPages) && (this.TotalPages > this.IndividualPagesDisplayedCount))
            {
        if ((this.ShowIndividualPages || (this.ShowNext && ((this.PageIndex + 1) < this.TotalPages))) && ((this.PageIndex+1) < (this.TotalPages-(this.IndividualPagesDisplayedCount / 2) - 1)))
                {
                    control.Controls.Add(new LiteralControl("&nbsp;...&nbsp;"));
                }

                HyperLink child = new HyperLink();
                child.Text = this.LastButtonText;
                child.NavigateUrl = this.GetPageNavigateUrl(this.TotalPages);
                control.Controls.Add(child);
            }
        }


Any thoughts, critique, optimisation, and/or bug fixes on the fix are welcome.

Yiannis