Add 'packages/paginate/' from commit 'a2daba88abb3c4c73b67922d3f93f2032b14e1da'
git-subtree-dir: packages/paginate git-subtree-mainline:12aa791a8e
git-subtree-split:a2daba88ab
This commit is contained in:
commit
c6d7d5f416
16 changed files with 594 additions and 0 deletions
2
packages/paginate/.analysis-options
Normal file
2
packages/paginate/.analysis-options
Normal file
|
@ -0,0 +1,2 @@
|
|||
analyzer:
|
||||
strong-mode: true
|
58
packages/paginate/.gitignore
vendored
Normal file
58
packages/paginate/.gitignore
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
.packages
|
||||
.pub/
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
pubspec.lock
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
.dart_tool
|
8
packages/paginate/.idea/modules.xml
Normal file
8
packages/paginate/.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/paginate.iml" filepath="$PROJECT_DIR$/.idea/paginate.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
18
packages/paginate/.idea/paginate.iml
Normal file
18
packages/paginate/.idea/paginate.iml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/test/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
7
packages/paginate/.idea/runConfigurations/All_Tests.xml
Normal file
7
packages/paginate/.idea/runConfigurations/All_Tests.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All Tests" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true">
|
||||
<option name="checkedMode" value="false" />
|
||||
<option name="filePath" value="$PROJECT_DIR$/test/all_test.dart" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
6
packages/paginate/.idea/vcs.xml
Normal file
6
packages/paginate/.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
1
packages/paginate/.travis.yml
Normal file
1
packages/paginate/.travis.yml
Normal file
|
@ -0,0 +1 @@
|
|||
language: dart
|
2
packages/paginate/CHANGELOG.md
Normal file
2
packages/paginate/CHANGELOG.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# 2.0.0
|
||||
* Dart2 + Angel2 update.
|
21
packages/paginate/LICENSE
Normal file
21
packages/paginate/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 The Angel Framework
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
60
packages/paginate/README.md
Normal file
60
packages/paginate/README.md
Normal file
|
@ -0,0 +1,60 @@
|
|||
# paginate
|
||||
[![Pub](https://img.shields.io/pub/v/angel_paginate.svg)](https://pub.dartlang.org/packages/angel_paginate)
|
||||
[![build status](https://travis-ci.org/angel-dart/paginate.svg)](https://travis-ci.org/angel-dart/paginate)
|
||||
|
||||
Platform-agnostic pagination library, with custom support for the
|
||||
[Angel framework](https://github.com/angel-dart/angel).
|
||||
|
||||
# Installation
|
||||
In your `pubspec.yaml` file:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
angel_paginate: ^2.0.0
|
||||
```
|
||||
|
||||
# Usage
|
||||
This library exports a `Paginator<T>`, which can be used to efficiently produce
|
||||
instances of `PaginationResult<T>`. Pagination results, when serialized to JSON, look like
|
||||
this:
|
||||
|
||||
```json
|
||||
{
|
||||
"total" : 75,
|
||||
"items_per_page" : 10,
|
||||
"previous_page" : 3,
|
||||
"current_page" : 4,
|
||||
"next_page" : 5,
|
||||
"start_index" : 30,
|
||||
"end_index" : 39,
|
||||
"data" : ["<items...>"]
|
||||
}
|
||||
```
|
||||
|
||||
Results can be parsed from Maps using the `PaginationResult<T>.fromMap` constructor, and
|
||||
serialized via their `toJson()` method.
|
||||
|
||||
To create a paginator:
|
||||
|
||||
```dart
|
||||
import 'package:angel_paginate/angel_paginate.dart';
|
||||
|
||||
main() {
|
||||
var p = new Paginator(iterable);
|
||||
|
||||
// Get the current page (default: page 1)
|
||||
var page = p.current;
|
||||
print(page.total);
|
||||
print(page.startIndex);
|
||||
print(page.data); // The actual items on this page.
|
||||
p.next(); // Advance a page
|
||||
p.back(); // Back one page
|
||||
p.goToPage(10); // Go to page number (1-based, not a 0-based index)
|
||||
}
|
||||
```
|
||||
|
||||
The entire Paginator API is documented, so check out the DartDocs.
|
||||
|
||||
Paginators by default cache paginations, to improve performance as you shift through pages.
|
||||
This can be especially helpful in a client-side application where your UX involves a fast
|
||||
response time, i.e. a search page.
|
15
packages/paginate/example/main.dart
Normal file
15
packages/paginate/example/main.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
import 'package:angel_paginate/angel_paginate.dart';
|
||||
|
||||
main() {
|
||||
var iterable = [1, 2, 3, 4];
|
||||
var p = new Paginator(iterable);
|
||||
|
||||
// Get the current page (default: page 1)
|
||||
var page = p.current;
|
||||
print(page.total);
|
||||
print(page.startIndex);
|
||||
print(page.data); // The actual items on this page.
|
||||
p.next(); // Advance a page
|
||||
p.back(); // Back one page
|
||||
p.goToPage(10); // Go to page number (1-based, not a 0-based index)
|
||||
}
|
191
packages/paginate/lib/angel_paginate.dart
Normal file
191
packages/paginate/lib/angel_paginate.dart
Normal file
|
@ -0,0 +1,191 @@
|
|||
/// Efficiently paginates collections of items in an object-oriented manner.
|
||||
class Paginator<T> {
|
||||
final Map<int, PaginationResult<T>> _cache = {};
|
||||
PaginationResult<T> _current;
|
||||
int _page = 0;
|
||||
|
||||
/// The collection of items to be paginated.
|
||||
final Iterable<T> _items;
|
||||
|
||||
/// The maximum number of items to be shown per page.
|
||||
final int itemsPerPage;
|
||||
|
||||
/// If `true` (default), then the results of paginations will be saved by page number.
|
||||
///
|
||||
/// For example, you would only have to paginate page 1 once. Future calls would return a cached version.
|
||||
final bool useCache;
|
||||
|
||||
Paginator(this._items, {this.itemsPerPage: 5, this.useCache: true});
|
||||
|
||||
/// Returns `true` if there are more items at lesser page indices than the current one.
|
||||
bool get canGoBack => _page > 0;
|
||||
|
||||
/// Returns `true` if there are more items at greater page indices than the current one.
|
||||
bool get canGoForward => _page < _lastPage();
|
||||
|
||||
/// The current page index.
|
||||
int get index => _page;
|
||||
|
||||
/// Returns the greatest possible page number for this collection, given the number of [itemsPerPage].
|
||||
int get lastPageNumber => _lastPage();
|
||||
|
||||
/// The current page number. This is not the same as [index].
|
||||
///
|
||||
/// This getter will return user-friendly numbers. The lowest value it will ever return is `1`.
|
||||
int get pageNumber => _page < 1 ? 1 : (_page + 1);
|
||||
|
||||
/// Fetches the current page. This will be cached until [back] or [next] is called.
|
||||
///
|
||||
/// If [useCache] is `true` (default), then computations will be cached even after the page changes.
|
||||
PaginationResult<T> get current {
|
||||
if (_current != null)
|
||||
return _current;
|
||||
else
|
||||
return _current = _getPage();
|
||||
}
|
||||
|
||||
PaginationResult<T> _computePage() {
|
||||
var len = _items.length;
|
||||
var it = _items.skip(_page * (itemsPerPage ?? 5));
|
||||
var offset = len - it.length;
|
||||
it = it.take(itemsPerPage);
|
||||
var last = _lastPage();
|
||||
// print('cur: $_page, last: $last');
|
||||
return new _PaginationResultImpl(it,
|
||||
currentPage: _page + 1,
|
||||
previousPage: _page <= 0 ? -1 : _page,
|
||||
nextPage: _page >= last - 1 ? -1 : _page + 2,
|
||||
startIndex: it.isEmpty ? -1 : offset,
|
||||
endIndex: offset + it.length - 1,
|
||||
itemsPerPage:
|
||||
itemsPerPage < _items.length ? itemsPerPage : _items.length,
|
||||
total: len);
|
||||
}
|
||||
|
||||
PaginationResult<T> _getPage() {
|
||||
if (useCache != false)
|
||||
return _cache.putIfAbsent(_page, () => _computePage());
|
||||
else
|
||||
return _computePage();
|
||||
}
|
||||
|
||||
int _lastPage() {
|
||||
var n = (_items.length / itemsPerPage).round();
|
||||
// print('items: ${_items.length}');
|
||||
// print('per page: $itemsPerPage');
|
||||
// print('quotient: $n');
|
||||
var remainder = _items.length - (n * itemsPerPage);
|
||||
// print('remainder: $remainder');
|
||||
return (remainder <= 0) ? n : n + 1;
|
||||
}
|
||||
|
||||
/// Attempts to go the specified page. If it fails, then it will remain on the current page.
|
||||
///
|
||||
/// Keep in mind - this just not be a zero-based index, but a one-based page number. The lowest
|
||||
/// allowed value is `1`.
|
||||
void goToPage(int page) {
|
||||
if (page > 0 && page <= _lastPage()) {
|
||||
_page = page - 1;
|
||||
_current = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the paginator back one page, if possible.
|
||||
void back() {
|
||||
if (_page > 0) {
|
||||
_page--;
|
||||
_current = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Advances the paginator one page, if possible.
|
||||
void next() {
|
||||
if (_page < _lastPage()) {
|
||||
_page++;
|
||||
_current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores the result of a pagination.
|
||||
abstract class PaginationResult<T> {
|
||||
factory PaginationResult.fromMap(Map<String, dynamic> map) =>
|
||||
new _PaginationResultImpl((map['data'] as Iterable).cast<T>(),
|
||||
currentPage: map['current_page'],
|
||||
endIndex: map['end_index'],
|
||||
itemsPerPage: map['items_per_page'],
|
||||
nextPage: map['next_page'],
|
||||
previousPage: map['previous_page'],
|
||||
startIndex: map['start_index'],
|
||||
total: map['total']);
|
||||
|
||||
List<T> get data;
|
||||
|
||||
int get currentPage;
|
||||
|
||||
int get previousPage;
|
||||
|
||||
int get nextPage;
|
||||
|
||||
int get itemsPerPage;
|
||||
|
||||
int get total;
|
||||
|
||||
int get startIndex;
|
||||
|
||||
int get endIndex;
|
||||
|
||||
Map<String, dynamic> toJson();
|
||||
}
|
||||
|
||||
class _PaginationResultImpl<T> implements PaginationResult<T> {
|
||||
final Iterable<T> _data;
|
||||
Iterable<T> _cachedData;
|
||||
|
||||
@override
|
||||
final int currentPage;
|
||||
|
||||
_PaginationResultImpl(this._data,
|
||||
{this.currentPage,
|
||||
this.endIndex,
|
||||
this.itemsPerPage,
|
||||
this.nextPage,
|
||||
this.previousPage,
|
||||
this.startIndex,
|
||||
this.total});
|
||||
|
||||
@override
|
||||
List<T> get data => _cachedData ?? (_cachedData = new List<T>.from(_data));
|
||||
|
||||
@override
|
||||
final int endIndex;
|
||||
|
||||
@override
|
||||
final int itemsPerPage;
|
||||
|
||||
@override
|
||||
final int nextPage;
|
||||
|
||||
@override
|
||||
final int previousPage;
|
||||
|
||||
@override
|
||||
final int startIndex;
|
||||
|
||||
@override
|
||||
final int total;
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'total': total,
|
||||
'items_per_page': itemsPerPage,
|
||||
'previous_page': previousPage,
|
||||
'current_page': currentPage,
|
||||
'next_page': nextPage,
|
||||
'start_index': startIndex,
|
||||
'end_index': endIndex,
|
||||
'data': data
|
||||
};
|
||||
}
|
||||
}
|
13
packages/paginate/pubspec.yaml
Normal file
13
packages/paginate/pubspec.yaml
Normal file
|
@ -0,0 +1,13 @@
|
|||
name: angel_paginate
|
||||
version: 2.0.0
|
||||
description: Platform-agnostic pagination library, with custom support for the Angel framework.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/paginate
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
dev_dependencies:
|
||||
angel_test: ^2.0.0
|
||||
logging: ^0.11.0
|
||||
test: ^1.0.0
|
8
packages/paginate/test/all_test.dart
Normal file
8
packages/paginate/test/all_test.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
import 'package:test/test.dart';
|
||||
import 'bounds_test.dart' as bounds;
|
||||
import 'paginate_test.dart' as paginate;
|
||||
|
||||
main() {
|
||||
group('bounds', bounds.main);
|
||||
group('paginate', paginate.main);
|
||||
}
|
57
packages/paginate/test/bounds_test.dart
Normal file
57
packages/paginate/test/bounds_test.dart
Normal file
|
@ -0,0 +1,57 @@
|
|||
import 'dart:convert';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_paginate/angel_paginate.dart';
|
||||
import 'package:angel_test/angel_test.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
final List<Map<String, String>> mjAlbums = [
|
||||
{'billie': 'jean'},
|
||||
{'off': 'the_wall'},
|
||||
{'michael': 'jackson'}
|
||||
];
|
||||
|
||||
main() {
|
||||
TestClient client;
|
||||
|
||||
setUp(() async {
|
||||
var app = new Angel();
|
||||
|
||||
app.get('/api/songs', (req, res) {
|
||||
var p = Paginator(mjAlbums, itemsPerPage: mjAlbums.length);
|
||||
p.goToPage(int.parse(req.queryParameters['page'] ?? '1'));
|
||||
return p.current;
|
||||
});
|
||||
|
||||
client = await connectTo(app);
|
||||
|
||||
app.logger = Logger('angel_paginate')
|
||||
..onRecord.listen((rec) {
|
||||
print(rec);
|
||||
if (rec.error != null) print(rec.error);
|
||||
if (rec.stackTrace != null) print(rec.stackTrace);
|
||||
});
|
||||
});
|
||||
|
||||
tearDown(() => client.close());
|
||||
|
||||
test('limit exceeds size of collection', () async {
|
||||
var response = await client.get(Uri(
|
||||
path: '/api/songs',
|
||||
queryParameters: {r'$limit': (mjAlbums.length + 1).toString()}));
|
||||
|
||||
var page = new PaginationResult<Map<String, dynamic>>.fromMap(
|
||||
json.decode(response.body));
|
||||
|
||||
print('page: ${page.toJson()}');
|
||||
|
||||
expect(page.total, mjAlbums.length);
|
||||
expect(page.itemsPerPage, mjAlbums.length);
|
||||
expect(page.previousPage, -1);
|
||||
expect(page.currentPage, 1);
|
||||
expect(page.nextPage, -1);
|
||||
expect(page.startIndex, 0);
|
||||
expect(page.endIndex, mjAlbums.length - 1);
|
||||
expect(page.data, mjAlbums);
|
||||
});
|
||||
}
|
127
packages/paginate/test/paginate_test.dart
Normal file
127
packages/paginate/test/paginate_test.dart
Normal file
|
@ -0,0 +1,127 @@
|
|||
import 'package:angel_paginate/angel_paginate.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
// Count-down from 100, then 101 at the end...
|
||||
final List<int> DATA = new List<int>.generate(100, (i) => 100 - i)..add(101);
|
||||
|
||||
main() {
|
||||
group('cache', () {
|
||||
var cached = new Paginator<int>(DATA),
|
||||
uncached = new Paginator<int>(DATA, useCache: false);
|
||||
|
||||
test('always cache current', () {
|
||||
expect(cached.current, cached.current);
|
||||
expect(uncached.current, uncached.current);
|
||||
});
|
||||
|
||||
test('only cache prev/next if useCache != false', () {
|
||||
var cached1 = cached.current;
|
||||
cached.goToPage(4);
|
||||
var cached4 = cached.current;
|
||||
cached.goToPage(1);
|
||||
expect(cached.current, cached1);
|
||||
cached.goToPage(4);
|
||||
expect(cached.current, cached4);
|
||||
|
||||
var uncached1 = uncached.current;
|
||||
uncached.goToPage(4);
|
||||
var uncached4 = uncached.current;
|
||||
uncached.goToPage(1);
|
||||
expect(uncached.current, isNot(uncached1));
|
||||
uncached.goToPage(4);
|
||||
expect(uncached.current, isNot(uncached4));
|
||||
});
|
||||
});
|
||||
|
||||
test('default state', () {
|
||||
var paginator = new Paginator<int>(DATA);
|
||||
expect(paginator.index, 0);
|
||||
expect(paginator.pageNumber, 1);
|
||||
expect(paginator.itemsPerPage, 5);
|
||||
expect(paginator.useCache, true);
|
||||
expect(paginator.canGoBack, false);
|
||||
expect(paginator.canGoForward, true);
|
||||
expect(paginator.lastPageNumber, 21);
|
||||
|
||||
// Going back should do nothing
|
||||
var p = paginator.pageNumber;
|
||||
paginator.back();
|
||||
expect(paginator.pageNumber, p);
|
||||
});
|
||||
|
||||
group('paginate', () {
|
||||
test('first page', () {
|
||||
var paginator = new Paginator<int>(DATA);
|
||||
expect(paginator.pageNumber, 1);
|
||||
var r = paginator.current;
|
||||
print(r.toJson());
|
||||
expect(r.total, DATA.length);
|
||||
expect(r.itemsPerPage, 5);
|
||||
expect(r.previousPage, -1);
|
||||
expect(r.currentPage, 1);
|
||||
expect(r.nextPage, 2);
|
||||
expect(r.startIndex, 0);
|
||||
expect(r.endIndex, 4);
|
||||
expect(r.data, DATA.skip(r.startIndex).take(r.itemsPerPage).toList());
|
||||
});
|
||||
});
|
||||
|
||||
test('third page', () {
|
||||
var paginator = new Paginator<int>(DATA)..goToPage(3);
|
||||
expect(paginator.pageNumber, 3);
|
||||
var r = paginator.current;
|
||||
print(r.toJson());
|
||||
expect(r.total, DATA.length);
|
||||
expect(r.itemsPerPage, 5);
|
||||
expect(r.previousPage, 2);
|
||||
expect(r.currentPage, 3);
|
||||
expect(r.nextPage, 4);
|
||||
expect(r.startIndex, 10);
|
||||
expect(r.endIndex, 14);
|
||||
expect(r.data, DATA.skip(r.startIndex).take(r.itemsPerPage).toList());
|
||||
|
||||
paginator.back();
|
||||
expect(paginator.pageNumber, 2);
|
||||
});
|
||||
|
||||
test('last page', () {
|
||||
var paginator = new Paginator<int>(DATA);
|
||||
paginator.goToPage(paginator.lastPageNumber);
|
||||
var r = paginator.current;
|
||||
expect(r.total, DATA.length);
|
||||
expect(r.itemsPerPage, 5);
|
||||
expect(r.previousPage, paginator.lastPageNumber - 1);
|
||||
expect(r.currentPage, paginator.lastPageNumber);
|
||||
expect(r.nextPage, -1);
|
||||
expect(r.startIndex, (paginator.lastPageNumber - 1) * 5);
|
||||
expect(r.endIndex, r.startIndex);
|
||||
expect(r.data, [DATA.last]);
|
||||
expect(r.data, DATA.skip(r.startIndex).take(r.itemsPerPage).toList());
|
||||
});
|
||||
|
||||
test('dump pages', () {
|
||||
var paginator = new Paginator<int>(DATA);
|
||||
print('${paginator.lastPageNumber} page(s) of data:');
|
||||
|
||||
do {
|
||||
print(' * Page #${paginator.pageNumber}: ${paginator.current.data}');
|
||||
paginator.next();
|
||||
} while (paginator.canGoForward);
|
||||
});
|
||||
|
||||
test('empty collection', () {
|
||||
var paginator = new Paginator([]);
|
||||
var page = paginator.current;
|
||||
print(page.toJson());
|
||||
|
||||
expect(page.total, 0);
|
||||
expect(page.previousPage, -1);
|
||||
expect(page.nextPage, -1);
|
||||
expect(page.currentPage, 1);
|
||||
expect(page.startIndex, -1);
|
||||
expect(page.endIndex, -1);
|
||||
expect(page.data, isEmpty);
|
||||
expect(paginator.canGoBack, isFalse);
|
||||
expect(paginator.canGoForward, isFalse);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue