| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library route.url_pattern; | 5 library route.url_pattern; |
| 6 | 6 |
| 7 import 'url_matcher.dart'; | 7 import 'url_matcher.dart'; |
| 8 | 8 |
| 9 // From the PatternCharacter rule here: | 9 // From the PatternCharacter rule here: |
| 10 // http://ecma-international.org/ecma-262/5.1/#sec-15.10 | 10 // http://ecma-international.org/ecma-262/5.1/#sec-15.10 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 46 * server.dart: | 46 * server.dart: |
| 47 * | 47 * |
| 48 * import 'urls.dart'; | 48 * import 'urls.dart'; |
| 49 * import 'package:route/server.dart'; | 49 * import 'package:route/server.dart'; |
| 50 * | 50 * |
| 51 * main() { | 51 * main() { |
| 52 * var server = new HttpServer(); | 52 * var server = new HttpServer(); |
| 53 * server.addRequestHandler(matchesUrl(articleUrl), serveArticle); | 53 * server.addRequestHandler(matchesUrl(articleUrl), serveArticle); |
| 54 * } | 54 * } |
| 55 * | 55 * |
| 56 * serveArticle(req, res) { | 56 * serveArcticle(req, res) { |
| 57 * var articleId = articleUrl.parse(req.path)[0]; | 57 * var articleId = articleUrl.parse(req.path)[0]; |
| 58 * // ... | 58 * // ... |
| 59 * } | 59 * } |
| 60 * | 60 * |
| 61 * Use with older browsers | 61 * Use with older browsers |
| 62 * ----------------------- | 62 * ----------------------- |
| 63 * | 63 * |
| 64 * Since '#' matches both '#' and '/' it can be used in as a path separator | 64 * Since '#' matches both '#' and '/' it can be used in as a path separator |
| 65 * between the "static" portion of your URL and the "dynamic" portion. The | 65 * between the "static" portion of your URL and the "dynamic" portion. The |
| 66 * dynamic portion would be the part that change when a user navigates to new | 66 * dynamic portion would be the part that change when a user navigates to new |
| (...skipping 20 matching lines...) Expand all Loading... |
| 87 RegExp _baseRegex; | 87 RegExp _baseRegex; |
| 88 | 88 |
| 89 UrlPattern(this.pattern) { | 89 UrlPattern(this.pattern) { |
| 90 _parse(pattern); | 90 _parse(pattern); |
| 91 } | 91 } |
| 92 | 92 |
| 93 RegExp get regex => _regex; | 93 RegExp get regex => _regex; |
| 94 | 94 |
| 95 String reverse(Iterable args, {bool useFragment: false}) { | 95 String reverse(Iterable args, {bool useFragment: false}) { |
| 96 var sb = new StringBuffer(); | 96 var sb = new StringBuffer(); |
| 97 var chars = pattern.split(''); |
| 97 var argsIter = args.iterator; | 98 var argsIter = args.iterator; |
| 98 | 99 |
| 99 int depth = 0; | 100 int depth = 0; |
| 100 int groupCount = 0; | 101 int groupCount = 0; |
| 101 bool escaped = false; | 102 bool escaped = false; |
| 102 | 103 |
| 103 for (int i = 0; i < pattern.length; i++) { | 104 for (int i = 0; i < chars.length; i++) { |
| 104 var c = pattern[i]; | 105 var c = chars[i]; |
| 105 if (c == '\\' && escaped == false) { | 106 if (c == '\\' && escaped == false) { |
| 106 escaped = true; | 107 escaped = true; |
| 107 } else { | 108 } else { |
| 108 if (c == '(') { | 109 if (c == '(') { |
| 109 if (escaped && depth == 0) { | 110 if (escaped && depth == 0) { |
| 110 sb.write(c); | 111 sb.write(c); |
| 111 } | 112 } |
| 112 if (!escaped) depth++; | 113 if (!escaped) depth++; |
| 113 } else if (c == ')') { | 114 } else if (c == ')') { |
| 114 if (escaped && depth == 0) { | 115 if (escaped && depth == 0) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 /** | 191 /** |
| 191 * Returns true if the path portion of the pattern, the part before the | 192 * Returns true if the path portion of the pattern, the part before the |
| 192 * fragment, matches [str]. If there is no fragment in the pattern, this is | 193 * fragment, matches [str]. If there is no fragment in the pattern, this is |
| 193 * equivalent to calling [matches]. | 194 * equivalent to calling [matches]. |
| 194 * | 195 * |
| 195 * This method is most useful on a server that is serving the HTML of a | 196 * This method is most useful on a server that is serving the HTML of a |
| 196 * single page app. Clients that don't support pushState will not send the | 197 * single page app. Clients that don't support pushState will not send the |
| 197 * fragment to the server, so the server will have to handle just the path | 198 * fragment to the server, so the server will have to handle just the path |
| 198 * part. | 199 * part. |
| 199 */ | 200 */ |
| 200 bool matchesNonFragment(String str) => | 201 bool matchesNonFragment(String str) { |
| 201 _hasFragment ? _matches(_baseRegex, str) : matches(str); | 202 if (!_hasFragment) { |
| 203 return matches(str); |
| 204 } else { |
| 205 return _matches(_baseRegex, str); |
| 206 } |
| 207 } |
| 202 | 208 |
| 203 Iterable<Match> allMatches(String str) => regex.allMatches(str); | 209 Iterable<Match> allMatches(String str) { |
| 210 return regex.allMatches(str); |
| 211 } |
| 204 | 212 |
| 205 bool operator ==(other) => | 213 bool operator ==(other) => |
| 206 (other is UrlPattern) && (other.pattern == pattern); | 214 (other is UrlPattern) && (other.pattern == pattern); |
| 207 | 215 |
| 208 int get hashCode => pattern.hashCode; | 216 int get hashCode => pattern.hashCode; |
| 209 | 217 |
| 210 String toString() => pattern.toString(); | 218 String toString() => pattern.toString(); |
| 211 | 219 |
| 212 _parse(String pattern) { | 220 _parse(String pattern) { |
| 213 var sb = new StringBuffer(); | 221 var sb = new StringBuffer(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 lastGroupEnd = i; | 273 lastGroupEnd = i; |
| 266 } | 274 } |
| 267 } else if (c == '#') { | 275 } else if (c == '#') { |
| 268 // TODO(justinfagnani): what else should be banned in groups? '/'? | 276 // TODO(justinfagnani): what else should be banned in groups? '/'? |
| 269 throw new ArgumentError('illegal # inside group'); | 277 throw new ArgumentError('illegal # inside group'); |
| 270 } | 278 } |
| 271 escaped = (c == r'\' && !escaped); | 279 escaped = (c == r'\' && !escaped); |
| 272 sb.write(c); | 280 sb.write(c); |
| 273 } | 281 } |
| 274 } | 282 } |
| 283 // sb.write(r'$'); |
| 275 _regex = new RegExp(sb.toString()); | 284 _regex = new RegExp(sb.toString()); |
| 276 } | 285 } |
| 277 | 286 |
| 278 void _setBasePattern(String basePattern) { | 287 void _setBasePattern(String basePattern) { |
| 279 if (_hasFragment == true) { | 288 if (_hasFragment == true) { |
| 280 throw new ArgumentError('multiple # characters'); | 289 throw new ArgumentError('multiple # characters'); |
| 281 } | 290 } |
| 282 _hasFragment = true; | 291 _hasFragment = true; |
| 283 _baseRegex = new RegExp('$basePattern\$'); | 292 _baseRegex = new RegExp('$basePattern\$'); |
| 284 } | 293 } |
| 285 | 294 |
| 286 Match matchAsPrefix(String string, [int start = 0]) { | 295 Match matchAsPrefix(String string, [int start = 0]) { |
| 287 throw new UnimplementedError('matchAsPrefix is not implemented'); | 296 throw new UnimplementedError('matchAsPrefix is not implemented'); |
| 288 } | 297 } |
| 289 | 298 |
| 290 List<String> urlParameterNames() { | 299 List<String> urlParameterNames() { |
| 291 throw new UnimplementedError('urlParameterNames is not implemented'); | 300 throw new UnimplementedError('urlParameterNames is not implemented'); |
| 292 } | 301 } |
| 293 | 302 |
| 294 int compareTo(UrlMatcher another) { | 303 int compareTo(UrlMatcher another) { |
| 295 throw new UnimplementedError('compareTo is not implemented'); | 304 throw new UnimplementedError('compareTo is not implemented'); |
| 296 } | 305 } |
| 297 } | 306 } |
| OLD | NEW |