Skip to content

Commit

Permalink
Feature/paginator (#94)
Browse files Browse the repository at this point in the history
* fixes #86

* comment unused variables

* fix codeclimate

* Initial implementation of Label class

* Apply fixes from StyleCI

* prevent multi-render, resolve #85

* prevent multi-render, resolve #85

* rename .jade to .pug

* Implement Grid - added bar, actions, checkboxes

* Apply fixes from StyleCI

* various improvements

* finally a good logic

* Fixed bugs with variable names

* Implement paginator

* Apply fixes from StyleCI

* Mostly adding docs to paginator and missing template

* more tests for paginator

* Apply fixes from StyleCI

* Update misc.rst

* typo

* Update Paginator.php
  • Loading branch information
romaninsh authored and DarkSide666 committed Mar 31, 2017
1 parent 36eeae7 commit dea8769
Show file tree
Hide file tree
Showing 13 changed files with 404 additions and 9 deletions.
3 changes: 2 additions & 1 deletion demos/init.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
$basic->addItem('Button', ['button']);
$basic->addItem('Header', ['header']);
$basic->addItem('Labels', ['label']);
$basic->addItem('Columns', ['columns']);
$basic->addItem('Menu', ['menu']);
$basic->addItem('Paginator', ['paginator']);

$basic = $layout->leftMenu->addGroup(['Interactivity', 'icon'=>'talk']);
$basic->addItem('JavaScript Events', ['button2']);
Expand Down
14 changes: 14 additions & 0 deletions demos/paginator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

date_default_timezone_set('UTC');
include 'init.php';

$layout->add(['Header', 'Paginator tracks its own position']);
$layout->add(['Paginator', 'total'=>40]);

$layout->add(['Header', 'Dynamic reloading']);
$seg = $layout->add(['View', 'ui'=>'blue segment']);
$label = $seg->add(['Label']);
$bb = $seg->add(['Paginator', 'total'=>50, 'range'=>2, 'reload'=>$seg]);
$label->addClass('blue ribbon');
$label->set('Current page: '.$bb->page);
21 changes: 21 additions & 0 deletions docs/app.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ Execution state
Will be true if application is currently rendering recursively through the Render Tree.

Links
=====

.. php:method:: url(page)
Method to generate links between pages. Specified with associative array::

$url = $app->url(['contact', 'from'=>'John Smith']);

this method must respond with a properly formatted url such as::

contact.php?from=John+Smith

You may redefine this metod if you are using beautiful URLs and advanced
routing::

/app/contact/John+Smith

Rest of Agile UI code can rely on url() wrapper.


Hooks
=====

Expand Down
4 changes: 3 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ Contents:
layouts
building-components
lister
tree
table
paginator
grid
form
crud
tree
virtual-page
console

Expand Down
2 changes: 1 addition & 1 deletion docs/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ designer with knowledge of HTML/CSS we recommend you to create your own layouts
if you are not sure how to do that, then using "Columns" class might be a good alternative for some
basic content arrangements.

.. php:meth:: addColumn()
.. php:method:: addColumn()
When you add new component to the page it will typically consume 100% width of its container. Columns
will break down width into chunks that can be used by other elements::
Expand Down
92 changes: 92 additions & 0 deletions docs/paginator.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@

.. _paginator:

=========
Paginator
=========

.. php:namespace:: atk4\ui
.. php:class:: Paginator
Paginator displays a horizontal UI menu providing links to pages when all of the content does not fit
on a page. Paginator is a stand-alone component but you can use it in conjunction with other compononents.

Adding and Using
================

.. php:attr: $total
.. php:attr: $page
Place paginator in a designated spot on your page. You also should specify what's the total number of pages
paginator should have::

$paginator = $layout->add('Paginator');
$paginator->total = 20;

Paginator will not display links to all the 20 pages, instead it will show first, last, current page and few
pages around the current page. Paginator will automatically place links back to your current page through
:php:meth:`App::url()`.

After initializing paginator you can use it's properties to determine current page. Quite often you'll need
to display current page BEFORE the paginator on your page::

$h = $page->add('Header');
$page->add('LoremIpsum'); // some content here

$p = $page->add('Paginator');
$h->set('Page '.$p->page.' from '.$p->total);

Remember that values of 'page' and 'total' are integers, so you may need to do type-casting::

$label->set($p->page); // will not work
$label->set((string)$p->page); // works fine

Range and Logic
===============

You can configure Paginator through properties.

.. php:attr: $range
Reasonable values for $range would be 2 to 5, depending on how big you want your paganiator to appear. Provided
that you have enough pages, user should see $range*2+1 bars.

.. php:meth: getPaginatorItems
You can override this method to implement a different logic for calculating which page links to display given
the current and total pages.

.. php:meth: getCurrentPage
Returns number of current page.

Template
========

Paginator uses Semantic UI `ui pagination menu` so if you are unhappy with the styling (e.g: active element is not
sufficiently highlighted), you should refer to Semantic UI or use alternative theme.

The template for Paginator uses custom logic:

- `rows` region will be populated with list of page items
- `Item` region will be cloned and used to represent a regular page
- `Spacer` region will be used to represent '...'
- `FirstItem` if present, will be used for link to page "1". Otherwise `Item` is used.
- `LastItem` if present, shows the link to last page. Otherwise `Item` is used.

Each of the above (except Spacer) may have `active`, `link` and `page` tags.


.. php:meth: renderItem($t, $page = null)
Dynamic Reloading
=================

.. php:attr: $reload
Specifying a view here will cause paginator to only reload this particular component and not all the page entirely.
Usually the View you specify here should also contain the paginator as well as possibly other components that
may be related to it. This technique is used by :php:class:`Grid` and some other components.


6 changes: 3 additions & 3 deletions docs/table.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@

.. _table:

====
=====
Table
====
=====

.. php:namespace:: atk4\ui
Table is the simplest way to output multiple records of structured data. Table only works along with the model,
however you can use :php:meth:`Lister::setSource` to inject static data (although it is slower than simply
however you can use :php:meth:`View::setSource` to inject static data (although it is slower than simply
using a model). :ref:`no_data`


Expand Down
6 changes: 3 additions & 3 deletions docs/view.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ Each of the views will automatically render all of the child views.



Initializing Tree
=================
Initializing Render Tree
========================

Views use a principle of ``delayed init``, which allow you to manipulate View objects
in any way you wish, before they will actuallized:.
in any way you wish, before they will actuallized.

.. php:method:: add($object, $region = 'Content')
Expand Down
192 changes: 192 additions & 0 deletions src/Paginator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?php

namespace atk4\ui;

class Paginator extends View
{
/**
* Specify how many pages this paginator has total.
*
* @var int
*/
public $total = null;

/**
* Override what is the current page. If not set, Paginator will look inside
* $_GET[$this->name]. If page > total, then page = total.
*
* @var int
*/
public $page = null;

/**
* Specifies how many items per page must be shown.
*
* @var int
*/
public $ipp = 50;

/**
* When there are more than $range*2+1 items, then current page will be surrounded by $range pages
* followed by spacer ..., for example if range=2, then.
*
* 1, ..., 5, 6, *7*, 8, 9, ..., 34
*
* @var int
*/
public $range = 4;

/**
* If specified, must be instance of a view which will be reloaded on selection.
*/
public $reload = null;

public $ui = 'pagination menu';
public $defaultTemplate = 'paginator.html';

/**
* Initialization.
*/
public function init()
{
parent::init();

if (!$this->page) {
$this->page = $this->getCurrentPage();
}
}

/**
* Determine and return the current page. You can extend this method for
* the advanced logic.
*
* @return int
*/
public function getCurrentPage()
{
return isset($_GET[$this->name]) ? (int) $_GET[$this->name] : 1;
}

/**
* Calculate logical sequence of items in a paginator. Responds with array
* containing recipe for HTML augmenting:.
*
* [ '[', '...', 10, 11, 12 ]
*
* Array will contain '[', ']', denoting "first" , "last" items, '...' for the spacer and any
* other integer value for a regular page link.
*
* @return array
*/
public function getPaginatorItems()
{
if ($this->page < 1) {
$this->page = 1;
} elseif ($this->page > $this->total) {
$this->page = $this->total;
}

$start = $this->page - $this->range;
$end = $this->page + $this->range;

// see if we are close to the edge
if ($start < 1) {
// shift by ($start-1);
$end += (1 - $start);
$start = 1;
}
if ($end > $this->total) {
$start -= ($end - $this->total);
$end = $this->total;
}

if ($start < 1) {
$start = 1; // shifted twice
}

$p = [];

if ($start > 1) {
$p[] = '[';
}

if ($start > 2) {
$p[] = '...';
}

for ($i = $start; $i <= $end; $i++) {
$p[] = $i;
}

if ($end < $this->total - 1) {
$p[] = '...';
}

if ($end < $this->total) {
$p[] = ']';
}

return $p;
}

/**
* TODO: Remove after https://github.com/atk4/ui/issues/69 is fixed.
*
* @param int|string $page
*
* @return string
*/
public function url($page)
{
return $this->app->url(['paginator', $this->name=>$page]);
}

/**
* Render page item using template $t for the page number $page.
*
* @param Template $t
* @param int|string $page
*/
public function renderItem($t, $page = null)
{
if ($page) {
$t->trySet('page', (string) $page);
$t->trySet('link', $this->url($page));

$t->trySet('active', $page === $this->page ? 'active' : '');
}

$this->template->appendHTML('rows', $t->render());
}

/**
* Renders view.
*/
public function renderView()
{
$t_item = $this->template->cloneRegion('Item');
$t_first = $this->template->hasTag('FirstItem') ? $this->template->cloneRegion('FirstItem') : $t_item;
$t_last = $this->template->hasTag('LastItem') ? $this->template->cloneRegion('LastItem') : $t_item;
$t_spacer = $this->template->cloneRegion('Spacer');

$this->template->del('rows');

foreach ($this->getPaginatorItems() as $item) {
if ($item === '[') {
$this->renderItem($t_first, 1);
} elseif ($item === '...') {
$this->renderItem($t_spacer);
} elseif ($item === ']') {
$this->renderItem($t_last, $this->total);
} else {
$this->renderItem($t_item, $item);
}
}

if ($this->reload) {
$this->on('click', '.item', new jsReload($this->reload, [$this->name => new jsExpression('$(this).data("page")')]));
}

parent::renderView();
}
}
Loading

0 comments on commit dea8769

Please sign in to comment.