Patch example

This commit is contained in:
Tobe O 2018-08-20 15:18:43 -04:00
parent d844a6fc16
commit c7bad38a62
6 changed files with 105 additions and 39 deletions

48
example/main.dart Normal file
View file

@ -0,0 +1,48 @@
import 'dart:math';
import 'package:angel_route/angel_route.dart';
main() {
final router = new Router();
router.get('/users', () {});
router.post('/users/:id/timeline', (String id) {});
router.get('/square_root/:id([0-9]+)', (String n) {
return {'result': pow(int.parse(n), 0.5)};
});
// You can also have parameters auto-parsed.
//
// Supports int, double, and num.
router.get('/square_root/int:id([0-9]+)', (int n) {
return {'result': pow(n, 0.5)};
});
router.group('/show/:id', (router) {
router.get('/reviews', (id) {
return someQuery(id).reviews;
});
// Optionally restrict params to a RegExp
router.get('/reviews/:reviewId([A-Za-z0-9_]+)', (id, reviewId) {
return someQuery(id).reviews.firstWhere((r) => r.id == reviewId);
});
});
}
SomeQuery someQuery(id) => new SomeQuery();
class SomeQuery {
List<SomeQueryReview> get reviews => [
SomeQueryReview('fake'),
SomeQueryReview('data'),
];
}
class SomeQueryReview {
final String id;
SomeQueryReview(this.id);
}

View file

@ -1,25 +1,27 @@
import 'dart:async' show Stream, StreamController;
import 'dart:html';
import 'angel_route.dart';
import 'package:path/path.dart' as p;
import 'angel_route.dart';
final RegExp _hash = new RegExp(r'^#/');
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
/// A variation of the [Router] support both hash routing and push state.
abstract class BrowserRouter extends Router {
abstract class BrowserRouter<T> extends Router<T> {
/// Fires whenever the active route changes. Fires `null` if none is selected (404).
Stream<RoutingResult> get onResolve;
Stream<RoutingResult<T>> get onResolve;
/// Fires whenever the active route changes. Fires `null` if none is selected (404).
Stream<Route> get onRoute;
Stream<Route<T>> get onRoute;
/// Set `hash` to true to use hash routing instead of push state.
/// `listen` as `true` will call `listen` after initialization.
factory BrowserRouter({bool hash: false, bool listen: false}) {
return hash
? new _HashRouter(listen: listen)
: new _PushStateRouter(listen: listen);
? new _HashRouter<T>(listen: listen)
: new _PushStateRouter<T>(listen: listen);
}
BrowserRouter._() : super();
@ -39,22 +41,24 @@ abstract class BrowserRouter extends Router {
void listen();
/// Identical to [all].
Route on(String path, handler, {List middleware});
Route on(String path, T handler, {Iterable<T> middleware});
}
abstract class _BrowserRouterImpl extends Router implements BrowserRouter {
abstract class _BrowserRouterImpl<T> extends Router<T>
implements BrowserRouter<T> {
bool _listening = false;
Route _current;
StreamController<RoutingResult> _onResolve =
new StreamController<RoutingResult>();
StreamController<Route> _onRoute = new StreamController<Route>();
StreamController<RoutingResult<T>> _onResolve =
new StreamController<RoutingResult<T>>();
StreamController<Route<T>> _onRoute = new StreamController<Route<T>>();
Route get currentRoute => _current;
@override
Stream<RoutingResult> get onResolve => _onResolve.stream;
Stream<RoutingResult<T>> get onResolve => _onResolve.stream;
@override
Stream<Route> get onRoute => _onRoute.stream;
Stream<Route<T>> get onRoute => _onRoute.stream;
_BrowserRouterImpl({bool listen}) : super() {
if (listen != false) this.listen();
@ -64,11 +68,11 @@ abstract class _BrowserRouterImpl extends Router implements BrowserRouter {
@override
void go(Iterable linkParams) => _goTo(navigate(linkParams));
Route on(String path, handler, {List middleware}) =>
Route on(String path, T handler, {Iterable<T> middleware}) =>
all(path, handler, middleware: middleware);
void prepareAnchors() {
final anchors = window.document.querySelectorAll('a:not([dynamic])');
final anchors = window.document.querySelectorAll('a'); //:not([dynamic])');
for (final AnchorElement $a in anchors) {
if ($a.attributes.containsKey('href') &&
@ -77,7 +81,8 @@ abstract class _BrowserRouterImpl extends Router implements BrowserRouter {
$a.attributes['rel'] != 'external') {
$a.onClick.listen((e) {
e.preventDefault();
go($a.attributes['href'].split('/').where((str) => str.isNotEmpty));
_goTo($a.attributes['href']);
//go($a.attributes['href'].split('/').where((str) => str.isNotEmpty));
});
}
@ -96,7 +101,7 @@ abstract class _BrowserRouterImpl extends Router implements BrowserRouter {
}
}
class _HashRouter extends _BrowserRouterImpl {
class _HashRouter<T> extends _BrowserRouterImpl<T> {
_HashRouter({bool listen}) : super(listen: listen) {
if (listen) this.listen();
}
@ -108,7 +113,9 @@ class _HashRouter extends _BrowserRouterImpl {
void handleHash([_]) {
final path = window.location.hash.replaceAll(_hash, '');
final resolved = resolveAbsolute(path).first;
var allResolved = resolveAbsolute(path);
final resolved = allResolved.isEmpty ? null : allResolved.first;
if (resolved == null) {
_onResolve.add(null);
@ -138,7 +145,7 @@ class _HashRouter extends _BrowserRouterImpl {
}
}
class _PushStateRouter extends _BrowserRouterImpl {
class _PushStateRouter<T> extends _BrowserRouterImpl<T> {
String _basePath;
_PushStateRouter({bool listen, Route root}) : super(listen: listen) {
@ -165,10 +172,8 @@ class _PushStateRouter extends _BrowserRouterImpl {
_onRoute.add(_current = null);
} else {
final route = resolved.route;
window.history.pushState(
{'path': route.path, 'params': {}},
route.name ?? route.path,
relativeUri);
window.history.pushState({'path': route.path, 'params': {}},
route.name ?? route.path, relativeUri);
_onResolve.add(resolved);
_onRoute.add(_current = route);
}

View file

@ -25,7 +25,7 @@ final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
/// An abstraction over complex [Route] trees. Use this instead of the raw API. :)
class Router<T> {
final Map<String, Iterable<RoutingResult>> _cache = {};
final Map<String, Iterable<RoutingResult<T>>> _cache = {};
//final List<_ChainedRouter> _chained = [];
final List<T> _middleware = [];
@ -142,7 +142,7 @@ class Router<T> {
if (route is! SymlinkRoute) buf.write('${route.method} ');
buf.write('${route.path.isNotEmpty ? route.path : '/'}');
if (route is SymlinkRoute) {
if (route is SymlinkRoute<T>) {
buf.writeln();
dumpRouter(route.router);
} else {
@ -212,7 +212,7 @@ class Router<T> {
segments.add(route.path.replaceAll(_straySlashes, ''));
lastRoute = route;
if (route is SymlinkRoute) {
if (route is SymlinkRoute<T>) {
search = route.router;
}
@ -230,7 +230,7 @@ class Router<T> {
segments.add(route.path.replaceAll(_straySlashes, ''));
lastRoute = route;
if (route is SymlinkRoute) {
if (route is SymlinkRoute<T>) {
search = route.router;
}
@ -279,7 +279,7 @@ class Router<T> {
for (Route route in r.routes) {
int pos = scanner.position;
if (route is SymlinkRoute) {
if (route is SymlinkRoute<T>) {
if (route.parser.parse(scanner).successful) {
var s = crawl(route.router);
if (s) success = true;
@ -311,13 +311,13 @@ class Router<T> {
/// Returns the result of [resolve] with [path] passed as
/// both `absolute` and `relative`.
Iterable<RoutingResult> resolveAbsolute(String path,
Iterable<RoutingResult<T>> resolveAbsolute(String path,
{String method: 'GET', bool strip: true}) =>
resolveAll(path, path, method: method, strip: strip);
/// Finds every possible [Route] that matches the given path,
/// with the given method.
Iterable<RoutingResult> resolveAll(String absolute, String relative,
Iterable<RoutingResult<T>> resolveAll(String absolute, String relative,
{String method: 'GET', bool strip: true}) {
if (_useCache == true) {
return _cache.putIfAbsent('$method$absolute',
@ -327,9 +327,9 @@ class Router<T> {
return _resolveAll(absolute, relative, method: method, strip: strip);
}
Iterable<RoutingResult> _resolveAll(String absolute, String relative,
Iterable<RoutingResult<T>> _resolveAll(String absolute, String relative,
{String method: 'GET', bool strip: true}) {
final List<RoutingResult> results = [];
var results = <RoutingResult<T>>[];
resolve(absolute, relative, results, method: method, strip: strip);
// _printDebug(
@ -435,11 +435,11 @@ class _ChainedRouter<T> extends Router<T> {
}
/// Optimizes a router by condensing all its routes into one level.
Router flatten(Router router) {
var flattened = new Router();
Router<T> flatten<T>(Router<T> router) {
var flattened = new Router<T>();
for (var route in router.routes) {
if (route is SymlinkRoute) {
if (route is SymlinkRoute<T>) {
var base = route.path.replaceAll(_straySlashes, '');
var child = flatten(route.router);

View file

@ -25,7 +25,6 @@
<ul id="handlers">
<li>(empty)</li>
</ul>
<script src="basic.dart" type="application/dart"></script>
<script src="packages/browser/dart.js"></script>
<script src="basic.dart.js"></script>
</body>
</html>

15
web/index.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Angel Route Samples</title>
</head>
<body>
<h1>Angel Route Samples</h1>
<ul>
<li><a href="hash/basic.html">Hash-based</a></li>
<li><a href="push_state/basic.html">Push-state</a></li>
</ul>
</body>
</html>

View file

@ -26,7 +26,6 @@
<ul id="handlers">
<li>(empty)</li>
</ul>
<script src="/push_state/basic.dart" type="application/dart"></script>
<script src="packages/browser/dart.js"></script>
<script src="basic.dart.js"></script>
</body>
</html>