Patch example
This commit is contained in:
parent
d844a6fc16
commit
c7bad38a62
6 changed files with 105 additions and 39 deletions
48
example/main.dart
Normal file
48
example/main.dart
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
15
web/index.html
Normal 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>
|
|
@ -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>
|
Loading…
Reference in a new issue