Merge branch 'master' into tsc-1.5.0-alpha

This commit is contained in:
vvakame
2015-07-20 20:42:49 +09:00
18 changed files with 3545 additions and 160 deletions
+386
View File
@@ -0,0 +1,386 @@
/// <reference path="./baconjs.d.ts" />
function CreatingStreams() {
$("#my-div").asEventStream("click");
$("#my-div").asEventStream("click", ".more-specific-selector");
$("#my-div").asEventStream("click", (event, args) => args[0]);
$("#my-div").asEventStream("click", ".more-specific-selector", (event, args) => args[0]);
Bacon.fromPromise($.ajax("https://baconjs.github.io/"));
Bacon.fromPromise(Promise.resolve(1));
Bacon.fromPromise($.ajax("https://baconjs.github.io/"), true);
Bacon.fromPromise(Promise.resolve(1), false);
Bacon.fromPromise($.ajax("https://baconjs.github.io/"), true, (n:string) => {
return [new Bacon.Next(n), new Bacon.Next(() => n), new Bacon.End()];
});
Bacon.fromPromise(Promise.resolve(1), false, n => {
return [new Bacon.Next(n), new Bacon.Next(() => n), new Bacon.End()];
});
Bacon.fromEvent(document.body, "click").onValue(() => {
alert("Bacon!");
});
Bacon.fromEvent(document.body, "click", (event:MouseEvent) => event.clientX).onValue(clientX => {
alert("Bacon!");
});
Bacon.fromEvent(process.stdin, "readable", () => {
alert("Bacon!");
});
// This would create a stream that outputs a single value "Bacon!" and ends after that. The use of setTimeout causes the value to be delayed by 1 second.
Bacon.fromCallback(callback => {
setTimeout(() => {
callback("Bacon!");
}, 1000);
});
// You can also give any number of arguments to `fromCallback`, which will be passed to the function. These arguments can be simple variables, Bacon EventStreams or Properties. For example the following will output "Bacon rules":
Bacon.fromCallback((a, b, callback) => {
callback(a + " " + b);
}, Bacon.constant("bacon"), "rules").log();
{
var fs = require("fs"),
read = Bacon.fromNodeCallback(fs.readFile, "input.txt");
read.onError(error => {
console.log("Reading failed: " + error);
});
read.onValue(value => {
console.log("Read contents: " + value);
});
}
Bacon.once(new Bacon.Error("fail"));
// The following would lead to `1,2,3,1,2,3...` to be repeated indefinitely:
Bacon.fromArray([1, new Bacon.Error("")]);
Bacon.repeatedly(10, [1, 2, 3]);
// The following will produce values `0,1,2`.
Bacon.repeat(i => {
if (i < 3) {
return Bacon.once(i);
} else {
return false;
}
}).log();
{
var stream = Bacon.fromBinder(sink => {
sink("first value");
sink([new Bacon.Next("2nd"), new Bacon.Next("3rd")]);
sink(new Bacon.Next(() => {
return "This one will be evaluated lazily"
}));
sink(new Bacon.Error("oops, an error"));
sink(new Bacon.End());
return () => {
// unsub functionality here, this one's a no-op
};
});
stream.log();
}
new Bacon.Next("value");
new Bacon.Next(() => "value");
}
function CommonMethodsInEventStreamsAndProperties() {
// Converting strings to integers, skipping empty values:
Bacon.once("").flatMap(text => {
return text != "" ? parseInt(text) : Bacon.never();
});
Bacon.sequentially(1, [1, 2, 3]).scan(0, (a, b) => a + b);
Bacon.sequentially(1, [1, 2, 3]).diff(0, (a, b) => Math.abs(b - a));
// If you have a EventStream `s` with a value sequence `1,2,3,4,5`, the respective values in `s.slidingWindow(2)` would be `[],[1],[1,2],[2,3],[3,4],[4,5]`:
Bacon.fromArray([1, 2, 3, 4, 5]).slidingWindow(2);
// The values of `s.slidingWindow(2,2)`would be `[1,2],[2,3],[3,4],[4,5]`:
Bacon.fromArray([1, 2, 3, 4, 5]).slidingWindow(2, 2);
{
var x = Bacon.fromArray([1, 2]), y = Bacon.fromArray([3, 4]);
x.zip(y, (x, y) => x + y);
}
{
var stream = Bacon.fromArray([1, 2]);
stream.log("New event in myStream");
stream.log();
}
Bacon.fromArray([1, 2, 3]).withStateMachine(0, (sum, event) => {
if (event.hasValue()) {
// had to cast to `number` because event:Bacon.Next<number>|Bacon.Error<{}>
return [sum + <number>event.value(), []];
}
else if (event.isEnd()) {
return [undefined, [new Bacon.Next(sum), event]];
}
else {
return [sum, [event]];
}
});
{
var property = Bacon.fromArray([1, 2, 3]).toProperty(),
who = Bacon.fromArray(["A", "B", "C"]).toProperty();
property.decode({1: "mike", 2: who});
property.decode({1: {type: "mike"}, 2: {type: "other", whoThen: who}});
}
{
// This is handy for keeping track whether we are currently awaiting an AJAX response:
var ajaxRequest = <Bacon.Observable<Error, JQueryXHR>>{},
ajaxResponse = <Bacon.Observable<Error, JQueryXHR>>{},
showAjaxIndicator = ajaxRequest.awaiting(ajaxResponse);
}
Bacon.fromArray([1, 2, -3, 3]).withHandler(function (event) {
if (event.hasValue() && event.value() < 0) {
this.push(new Bacon.Error("Value below zero"));
return this.push(new Bacon.End());
} else {
return this.push(event);
}
});
{
var src = Bacon.once(1),
obs = src.map(x => -x);
console.log(obs.toString()); // > "Bacon.once(1).map(function)"
obs.withDescription(src, "times", -1);
console.log(obs.toString()); // > "Bacon.once(1).times(-1)"
}
{
// Calculator for grouped consecutive values until group is cancelled:
var events = [
{id: 1, type: "add", val: 3},
{id: 2, type: "add", val: -1},
{id: 1, type: "add", val: 2},
{id: 2, type: "cancel"},
{id: 3, type: "add", val: 2},
{id: 3, type: "cancel"},
{id: 1, type: "add", val: 1},
{id: 1, type: "add", val: 2},
{id: 1, type: "cancel"}
],
keyF = (event:{id:number}) => event.id,
limitF = (groupedStream:Bacon.EventStream<string, {id:number; type:string; val?:number}>) => {
var cancel = groupedStream.filter(x => x.type === "cancel").take(1),
adds = groupedStream.filter(x => x.type === "add");
return adds.takeUntil(cancel).map(x => x.val);
};
Bacon.sequentially(2, events)
.groupBy(keyF, limitF)
.flatMap(groupedStream => groupedStream.fold(0, (acc, x) => acc + x))
.onValue(sum => {
console.log(sum); // returns [-1, 2, 8] in an order
});
}
}
function EventStream() {
// This creates the stream which doesn't produce any events and never ends:
Bacon.interval(1e1, 0).last();
Bacon.fromArray([1, 2, 2, 1])
.skipDuplicates().log(); // > returns [1, 2, 1] in an order
// You might get two events containing [1,2,3,4] and [5,6,7] respectively, given that the flush occurs between numbers 4 and 5:
Bacon.fromArray([1, 2, 3, 4, 5, 6, 7]).bufferWithTime(0);
// Here's an equivalent to `stream.bufferWithTime(10)`:
{
var stream = Bacon.fromArray([1, 2, 3, 4, 5, 6, 7]);
stream.bufferWithTime(f => {
setTimeout(f, 10);
});
}
// You will get output events with values `[1, 2]`, `[3, 4]` and `[5]`.
Bacon.fromArray([1, 2, 3, 4, 5]).bufferWithCount(2);
}
function Property() {
// This creates the property which doesn't produce any events and never ends:
Bacon.interval(1e1, 0).toProperty().last();
{
var property = Bacon.fromArray([1, 2, 3, 4, 5]).toProperty();
// If you want to assign your Property to the "disabled" attribute of a JQuery object, you can do this:
property.assign($("#my-button"), "attr", "disabled");
// A simpler example would be to toggle the visibility of an element based on a Property:
property.assign($("#my-button"), "toggle");
}
Bacon.fromArray([1, 2, 2, 1]).toProperty()
.skipDuplicates().log(); // > returns [1, 2, 1] in an order
}
function CombiningMultipleStreamsAndProperties() {
{
var property = Bacon.constant(1),
stream = Bacon.once(2),
constant = 3;
Bacon.combineAsArray(property, stream, constant)
.log(); // > returns [1, 2, 3]
}
{
// To calculate the current sum of three numeric Properties, you can do:
var property = Bacon.constant(1),
stream = Bacon.once(2),
constant = 3;
// NOTE: had to explicitly specify the typing for `x:number, y:number, z:number`
Bacon.combineWith((x:number, y:number, z:number) => x + y + z, property, stream, constant);
}
{
// Assuming you've got streams or properties named `password`, `username`, `firstname` and `lastname`, you can do:
var password = Bacon.constant("easy"),
username = Bacon.constant("juha"),
firstname = Bacon.constant("juha"),
lastname = Bacon.constant("paananen"),
// NOTE: you should provide `combineTemplate` typing explicitly!
loginInfo = Bacon.combineTemplate<string, {
magicNumber:number; userid:string; passwd:string;
name:{first:string; last:string}
}>({
magicNumber: 3,
userid: username,
passwd: password,
name: {first: firstname, last: lastname}
}).onValue(loginInfo => {
// and your new `loginInfo` property will combine values from all these streams using that template, whenever any of the streams/properties get a new value. It would yield a value:
console.log("`loginInfo` expected", {
magicNumber: 3,
userid: "juha",
passwd: "easy",
name: {first: "juha", last: "paananen"}
});
console.log("`loginInfo` actual", loginInfo);
});
// Note that all Bacon.combine* methods produce a `Property` instead of an `EventStream`. If you need the result as an `EventStream` you might want to use `property.changes()`:
Bacon.combineWith((firstname, lastname) => `${firstname} ${lastname}`, firstname, lastname).changes();
}
{
var x = Bacon.fromArray([1, 2, 3]),
y = Bacon.fromArray([10, 20, 30]),
z = Bacon.fromArray([100, 200, 300]);
Bacon.zipAsArray(x, y, z)
.log(); // > returns values `[1, 10, 100]`, `[2, 20, 200]` and `[3, 30, 300]`
}
// The following example would log the number 3.
// NOTE: had to explicitly specify the typing for `a:number, b:number`
Bacon.onValues(Bacon.constant(1), Bacon.constant(2), (a:number, b:number) => {
console.log(a + b);
});
}
function $Event() {
new Bacon.Next("value");
new Bacon.Next(() => "value");
}
function Errors() {
// In case you want to convert (some) value events into Error events, you may use `flatMap` like this:
// NOTE: had to explicitly specify the typing for `flatMap`
Bacon.fromArray([1, 2, 3, 4]).flatMap<number>(x => {
return x > 2 ? new Bacon.Error("too big") : x;
});
// Conversely, if you want to convert some Error events into value events, you may use `flatMapError`:
Bacon.fromArray<string, number>([1, 2, 3, 4]).flatMapError<number>(error => {
var isNonCriticalError = (error:string) => Math.random() < .5,
handleNonCriticalError = (error:string) => 42;
return isNonCriticalError(error) ? handleNonCriticalError(error) : new Bacon.Error(error);
});
// Note also that Bacon.js combinators do not catch errors that are thrown. Especially `map` doesn't do so. If you want to map things and wrap caught errors into Error events, you can do the following:
Bacon.fromArray([1, 2, 3, 4]).flatMap(x => {
var dangerousFunction = (x:number) => {
throw new Error("dangerous function!");
};
try {
return dangerousFunction(x);
} catch (e) {
return new Bacon.Error(e);
}
});
Bacon.once("https://baconjs.github.io/").flatMap(url => {
// `ajaxCall` gives `Error`s on network or server `Error`s.
var ajaxCall = (url:string) => {
return Bacon.fromPromise<JQueryXHR, JQueryXHR>($.ajax(url));
};
return Bacon.retry({
source: () => ajaxCall(url),
retries: 5,
isRetryable: (error:JQueryXHR) => error.status !== 404,
delay: context => 100 // Just use the same delay always
});
});
}
function JoinPatterns() {
{
// Consider implementing a game with discrete time ticks. We want to handle key-events synchronized on tick-events, with at most one key event handled per tick. If there are no key events, we want to just process a tick:
var tick = Bacon.interval(1e2, 0),
keyEvent = Bacon.fromEvent(document.body, "click", _ => Date.now()),
handleTick = (_:number) => `timestamp: NONE`,
handleKeyEvent = (timestamp:number) => `timestamp: ${timestamp}`;
Bacon.when(
[tick, keyEvent], (_:number, timestamp:number) => handleKeyEvent(timestamp),
[tick], handleTick
);
// Order is important here. If the [tick] patterns had been written first, this would have been tried first, and preferred at each tick.
}
{
// Join patterns are indeed a generalization of `zip`, and `zip` is equivalent to a single-rule join pattern. The following `Observable`s have the same output:
var a = Bacon.once("a"),
b = Bacon.once("b"),
c = Bacon.once("c"),
f = (a:string, b:string, c:string) => `a = ${a}; b = ${b}; c = ${c}.`;
Bacon.zipWith(f, a, b, c);
Bacon.when([a, b, c], f);
}
{
// The inputs to `Bacon.update` are defined like this:
var initial = 0,
x = Bacon.interval(1e3, 1),
y = Bacon.interval(2e3, 1),
z = Bacon.interval(1.5e3, 1);
// NOTE: had to explicitly specify the typing for `previous:number`
Bacon.update(initial,
[x, y, z], (previous:number, x:number, y:number, z:number) => previous + x + y + z,
[x, y], (previous:number, x:number, y:number) => previous + x + y
);
// As input, each function above will get the previous value of the `result` Property, along with values from the listed Observables. The value returned by the function will be used as the next value of `result`. Just like in `Bacon.when`, only EventStreams will trigger an update, while Properties will be just sampled. So, if you list a single EventStream and several Properties, the value will be updated only when an event occurs in the EventStream.
}
{
// Here's a simple gaming example:
var scoreMultiplier = Bacon.constant(1),
hitUfo = new Bacon.Bus(),
hitMotherShip = new Bacon.Bus(),
score = Bacon.update(0,
[hitUfo, scoreMultiplier], (score:number, _:number, multiplier:number) => score + 100 * multiplier,
[hitMotherShip], (score:number, _:number) => score + 2000
);
// In the example, the `score` property is updated when either `hitUfo` or `hitMotherShip` occur. The `scoreMultiplier` Property is sampled to take multiplier into account when `hitUfo` occurs.
}
}
+2746
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
/// <reference path="camel-case.d.ts" />
import camelCase = require('camel-case');
console.log(camelCase('string')); // => "string"
console.log(camelCase('dot.case')); // => "dotCase"
console.log(camelCase('PascalCase')); // => "pascalCase"
console.log(camelCase('version 1.2.10')); // => "version1_2_10"
console.log(camelCase('STRING 1.2', 'tr')); // => "strıng1_2"
+9
View File
@@ -0,0 +1,9 @@
// Type definitions for camel-case
// Project: https://github.com/blakeembrey/camel-case
// Definitions by: Sam Saint-Pettersen <https://github.com/stpettersens>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare module "camel-case" {
function camelCase(string: string, locale?: string): string;
export = camelCase;
}
+1
View File
@@ -44,6 +44,7 @@ interface Cheerio {
// Traversing
find(selector: string): Cheerio;
find(element: Cheerio): Cheerio;
parent(selector?: string): Cheerio;
parents(selector?: string): Cheerio;
@@ -0,0 +1,13 @@
/// <reference path='./connect-modrewrite.d.ts' />
/// <reference path='../express/express.d.ts' />
import modRewrite = require('connect-modrewrite');
import express = require('express');
var app = express();
app.use(modRewrite([
'^/test$ /index.html',
'^/test/\\d*$ /index.html [L]',
'^/test/\\d*/\\d*$ /flag.html [L]',
]));
+12
View File
@@ -0,0 +1,12 @@
// Type definitions for connect-modrewrite
// Project: https://github.com/tinganho/connect-modrewrite
// Definitions by: Tingan Ho <https://github.com/tinganho/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../express/express.d.ts" />
declare module 'connect-modrewrite' {
import express = require('express');
function modrewrite(rewrites: string[]): express.RequestHandler;
export = modrewrite;
}
+9
View File
@@ -0,0 +1,9 @@
/// <reference path="git-config.d.ts" />
import gitConfig = require('git-config');
var config: Object = gitConfig.sync();
console.log(JSON.stringify(config));
config = gitConfig.sync('gitconfig');
console.log(JSON.stringify(config));
+8
View File
@@ -0,0 +1,8 @@
// Type definitions for git-config
// Project: https://github.com/eugeneware/git-config
// Definitions by: Sam Saint-Pettersen <https://github.com/stpettersens>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare module "git-config" {
export function sync(gitFile?: string): Object; // Synchronous version.
}
+5
View File
@@ -0,0 +1,5 @@
[user]
name = A Git User
email = git.user@domain.xyz
[push]
default = simple
+11 -1
View File
@@ -1092,7 +1092,17 @@ result = <{ a: number; b: number; c: number; }>_.transform(<{ [index: string]: n
r[key] = num * 3;
});
result = <number[]>_.values({ 'one': 1, 'two': 2, 'three': 3 });
// _.values
class TestValues {
public a = 1;
public b = 2;
public c: string;
}
TestValues.prototype.c = 'a';
result = <number[]>_.values<number>(new TestValues());
// → [1, 2] (iteration order is not guaranteed)
result = <number[]>_(new TestValues()).values<number>().value();
// → [1, 2] (iteration order is not guaranteed)
// _.valueIn
class TestValueIn {
+10 -3
View File
@@ -6301,11 +6301,18 @@ declare module _ {
//_.values
interface LoDashStatic {
/**
* Creates an array composed of the own enumerable property values of object.
* @param object The object to inspect.
* Creates an array of the own enumerable property values of object.
* @param object The object to query.
* @return Returns an array of property values.
**/
values(object?: any): any[];
values<T>(object?: any): T[];
}
interface LoDashObjectWrapper<T> {
/**
* @see _.values
**/
values<TResult>(): LoDashObjectWrapper<TResult[]>;
}
//_.valuesIn
+2 -1
View File
@@ -75,7 +75,8 @@ function test() {
];
}
function testPath() {
function testPath() {
makerjs.path.breakAtPoint(paths.arc, [0,0]).type;
makerjs.path.intersection(paths.circle, paths.arc).intersectionPoints;
makerjs.path.mirror(paths.arc, true, true);
makerjs.path.moveRelative(paths.circle, [0,0]);
+13 -5
View File
@@ -94,10 +94,6 @@ declare module MakerJs {
* The main point of reference for this path.
*/
origin: IPoint;
/**
* Optional CSS style properties to be emitted into SVG. Useful for creating guidelines and debugging your model.
*/
cssStyle?: string;
}
/**
* Test to see if an object implements the required properties of a path.
@@ -425,6 +421,18 @@ declare module MakerJs.path {
*/
function scale(pathToScale: IPath, scaleValue: number): IPath;
}
declare module MakerJs.path {
/**
* Breaks a path in two. The supplied path will end at the supplied pointOfBreak,
* a new path is returned which begins at the pointOfBreak and ends at the supplied path's initial end point.
* For Circle, the original path will be converted in place to an Arc, and null is returned.
*
* @param pathToBreak The path to break.
* @param pointOfBreak The point at which to break the path.
* @returns A new path of the same type, when path type is line or arc. Returns null for circle.
*/
function breakAtPoint(pathToBreak: IPath, pointOfBreak: IPoint): IPath;
}
declare module MakerJs.paths {
/**
* Class for arc path.
@@ -661,7 +669,7 @@ declare module MakerJs.path {
*
* @param path1 First path to find intersection.
* @param path2 Second path to find intersection.
* @result IPathIntersection object, with points(s) of intersection (and angles, when a path is an arc or circle); or null if the paths did not intersect.
* @returns IPathIntersection object, with points(s) of intersection (and angles, when a path is an arc or circle); or null if the paths did not intersect.
*/
function intersection(path1: IPath, path2: IPath): IPathIntersection;
}
+30 -26
View File
@@ -5,31 +5,34 @@
/// <reference path="../express/express.d.ts" />
declare module Express {
export interface Request {
files: {
[fieldname: string]: {
/** Field name specified in the form */
fieldname: string;
/** Name of the file on the user's computer */
originalname: string;
/** Renamed file name */
name: string;
/** Encoding type of the file */
encoding: string;
/** Mime type of the file */
mimetype: string;
/** Location of the uploaded file */
path: string;
/** Extension of the file */
extension: string;
/** Size of the file in bytes */
size: number;
/** If the file was truncated due to size limitation */
truncated: boolean;
/** Raw data (is null unless the inMemory option is true) */
buffer: Buffer;
}
[fieldname: string]: Multer.File
}
}
module Multer {
export interface File {
/** Field name specified in the form */
fieldname: string;
/** Name of the file on the user's computer */
originalname: string;
/** Encoding type of the file */
encoding: string;
/** Mime type of the file */
mimetype: string;
/** Size of the file in bytes */
size: number;
/** The folder to which the file has been saved (DiskStorage) */
destination: string;
/** The name of the file within the destination (DiskStorage) */
filename: string;
/** Location of the uploaded file (DiskStorage) */
path: string;
/** A Buffer of the entire file (MemoryStorage) */
buffer: Buffer;
}
}
}
@@ -40,6 +43,7 @@ declare module "multer" {
function multer(options?: multer.Options): express.RequestHandler;
module multer {
type Options = {
/** The destination directory for the uploaded files. */
dest?: string;
@@ -69,11 +73,11 @@ declare module "multer" {
/** Function to rename the directory in which to place uploaded files. The dest parameter is the default value originally assigned or passed into multer. The req and res parameters are also passed into the function because they may contain information (eg session data) needed to create the path (eg get userid from the session). */
changeDest?: (dest: string, req: Express.Request, res: Express.Response) => string;
/** Event handler triggered when a file starts to be uploaded. A file object, with the following properties, is available to this function: fieldname, originalname, name, encoding, mimetype, path, and extension. */
onFileUploadStart?: (file: string, req: Express.Request, res: Express.Response) => void;
onFileUploadStart?: (file: Express.Multer.File, req: Express.Request, res: Express.Response) => void;
/** Event handler triggered when a chunk of buffer is received. A buffer object along with a file object is available to the function. */
onFileUploadData?: (file: string, data: Buffer, req: Express.Request, res: Express.Response) => void;
onFileUploadData?: (file: Express.Multer.File, data: Buffer, req: Express.Request, res: Express.Response) => void;
/** Event handler trigger when a file is completely uploaded. A file object is available to the function. */
onFileUploadComplete?: (file: string, req: Express.Request, res: Express.Response) => void;
onFileUploadComplete?: (file: Express.Multer.File, req: Express.Request, res: Express.Response) => void;
/** Event handler triggered when the form parsing starts. */
onParseStart?: () => void;
/** Event handler triggered when the form parsing completes. The request object and the next objects are are passed to the function. */
@@ -81,7 +85,7 @@ declare module "multer" {
/** Event handler for any errors encountering while processing the form. The error object and the next object is available to the function. If you are handling errors yourself, make sure to terminate the request or call the next() function, else the request will be left hanging. */
onError?: () => void;
/** Event handler triggered when a file size exceeds the specification in the limit object. No more files will be parsed after the limit is reached. */
onFileSizeLimit?: (file: string) => void;
onFileSizeLimit?: (file: Express.Multer.File) => void;
/** Event handler triggered when the number of files exceed the specification in the limit object. No more files will be parsed after the limit is reached. */
onFilesLimit?: () => void;
/** Event handler triggered when the number of fields exceed the specification in the limit object. No more fields will be parsed after the limit is reached. */
+136 -115
View File
@@ -1,117 +1,138 @@
/// <reference path="navigation.d.ts" />
// History Manager
class LogHistoryManager extends Navigation.HashHistoryManager {
addHistory(state: Navigation.State, url: string) {
console.log('add history');
super.addHistory(state, url);
}
}
// State Router
class LogStateRouter extends Navigation.StateRouter {
getData(route: string): { state: Navigation.State; data: any } {
console.log('get data');
return super.getData(route);
}
}
// Settings
Navigation.settings.router = new LogStateRouter();
Navigation.settings.historyManager = new LogHistoryManager();
Navigation.settings.stateIdKey = 'state';
// Configuration
Navigation.StateInfoConfig.build([
{ key: 'home', initial: 'page', states: [
{ key: 'page', route: '' }
]},
{ key: 'person', initial: 'list', states: [
{ key: 'list', route: 'people/{page}', transitions: [
{ key: 'select', to: 'details' }
], defaults: { page: 1 }, trackCrumbTrail: false },
{ key: 'details', route: 'person/{id}', defaultTypes: { id: 'number' } }
]}
]);
// StateInfo
var dialogs = Navigation.StateInfoConfig.dialogs;
var home = dialogs['home'];
var homePage = home.states['page'];
var homeKey = home.key;
var homePageKey = homePage.key;
homePage = home.initial;
var person = dialogs['person'];
var personList = person.states['list'];
var personDetails = person.states['details'];
var personListSelect = personList.transitions['select'];
personList = personListSelect.parent;
personDetails = personListSelect.to;
var pageDefault = personList.defaults.page;
var idDefaultType = personDetails.defaultTypes.id;
// StateNavigator
personList.dispose = () => {};
personList.navigating = (data, url, navigate) => {
navigate();
};
personList.navigated = (data) => {};
// State Handler
class LogStateHandler extends Navigation.StateHandler {
getNavigationData(state: Navigation.State, url: string): any {
console.log('get navigation data');
super.getNavigationData(state, url);
}
}
homePage.stateHandler = new LogStateHandler();
personList.stateHandler = new LogStateHandler();
personDetails.stateHandler = new LogStateHandler();
// Navigation Event
var navigationListener =
(oldState: Navigation.State, state: Navigation.State, data: any) => {
Navigation.StateController.offNavigate(navigationListener);
};
Navigation.StateController.onNavigate(navigationListener);
// Navigation
Navigation.start('home');
Navigation.StateController.navigate('person');
Navigation.StateController.refresh();
Navigation.StateController.refresh({ page: 2 });
Navigation.StateController.navigate('select', { id: 10 });
var canGoBack: boolean = Navigation.StateController.canNavigateBack(1);
Navigation.StateController.navigateBack(1);
// Navigation Link
var link = Navigation.StateController.getNavigationLink('person');
link = Navigation.StateController.getRefreshLink();
link = Navigation.StateController.getRefreshLink({ page: 2 });
link = Navigation.StateController.getNavigationLink('select', { id: 10 });
var nextDialog = Navigation.StateController.getNextState('select').parent;
person = nextDialog;
Navigation.StateController.navigateLink(link);
link = Navigation.StateController.getNavigationBackLink(1);
var crumb = Navigation.StateController.crumbs[0];
link = crumb.navigationLink;
// StateContext
Navigation.StateController.navigate('home');
Navigation.StateController.navigate('person');
home = Navigation.StateContext.previousDialog;
homePage = Navigation.StateContext.previousState;
person === Navigation.StateContext.dialog;
personList === Navigation.StateContext.state;
var url: string = Navigation.StateContext.url;
var page: number = Navigation.StateContext.data.page;
// Navigation Data
Navigation.StateController.refresh({ page: 2 });
var data = Navigation.StateContext.includeCurrentData({ sort: 'name' }, ['page']);
Navigation.StateController.refresh(data);
Navigation.StateContext.clear('sort');
var data = Navigation.StateContext.includeCurrentData({ pageSize: 10 });
Navigation.StateController.refresh(data);
Navigation.StateContext.clear();
Navigation.StateController.refresh();
module NavigationTests {
// History Manager
class LogHistoryManager extends Navigation.HashHistoryManager {
addHistory(state: Navigation.State, url: string) {
console.log('add history');
super.addHistory(state, url);
}
}
// Crumb Trail Persister
class LogCrumbTrailPersister extends Navigation.CrumbTrailPersister {
load(crumbTrail: string): string {
console.log('load');
return crumbTrail;
}
save(crumbTrail: string): string {
console.log('save');
return crumbTrail;
}
}
// State Router
class LogStateRouter extends Navigation.StateRouter {
getData(route: string): { state: Navigation.State; data: any } {
console.log('get data');
return super.getData(route);
}
}
// Settings
Navigation.settings.router = new LogStateRouter();
Navigation.settings.historyManager = new LogHistoryManager();
Navigation.settings.crumbTrailPersister = new LogCrumbTrailPersister();
Navigation.settings.stateIdKey = 'state';
// Configuration
Navigation.StateInfoConfig.build([
{ key: 'home', initial: 'page', states: [
{ key: 'page', route: '' }
]},
{ key: 'person', initial: 'list', states: [
{ key: 'list', route: ['people/{page}', 'people/{page}/sort/{sort}'], transitions: [
{ key: 'select', to: 'details' }
], defaults: { page: 1 }, trackCrumbTrail: false },
{ key: 'details', route: 'person/{id}', trackTypes: false, defaultTypes: { id: 'number' } }
]}
]);
// StateInfo
var dialogs = Navigation.StateInfoConfig.dialogs;
var home = dialogs['home'];
var homePage = home.states['page'];
var homeKey = home.key;
var homePageKey = homePage.key;
homePage = home.initial;
var person = dialogs['person'];
var personList = person.states['list'];
var personDetails = person.states['details'];
var personListSelect = personList.transitions['select'];
personList = personListSelect.parent;
personDetails = personListSelect.to;
var pageDefault = personList.defaults.page;
var idDefaultType = personDetails.defaultTypes.id;
// StateNavigator
personList.dispose = () => {};
personList.navigating = (data, url, navigate) => {
navigate([]);
};
personList.navigated = (data, asyncData) => {};
personDetails.navigating = (data, url, navigate) => {
navigate();
};
personDetails.navigated = (data) => {};
// State Handler
class LogStateHandler extends Navigation.StateHandler {
getNavigationData(state: Navigation.State, url: string): any {
console.log('get navigation data');
super.getNavigationData(state, url);
}
}
homePage.stateHandler = new LogStateHandler();
personList.stateHandler = new LogStateHandler();
personDetails.stateHandler = new LogStateHandler();
// Navigation Event
var navigationListener =
(oldState: Navigation.State, state: Navigation.State, data: any) => {
Navigation.StateController.offNavigate(navigationListener);
};
Navigation.StateController.onNavigate(navigationListener);
// Navigation
Navigation.start('home');
Navigation.StateController.navigate('person');
Navigation.StateController.refresh();
Navigation.StateController.refresh({ page: 2 });
Navigation.StateController.navigate('select', { id: 10 });
var canGoBack: boolean = Navigation.StateController.canNavigateBack(1);
Navigation.StateController.navigateBack(1);
// Navigation Link
var link = Navigation.StateController.getNavigationLink('person');
link = Navigation.StateController.getRefreshLink();
link = Navigation.StateController.getRefreshLink({ page: 2 });
link = Navigation.StateController.getNavigationLink('select', { id: 10 });
var nextDialog = Navigation.StateController.getNextState('select').parent;
person = nextDialog;
Navigation.StateController.navigateLink(link);
link = Navigation.StateController.getNavigationBackLink(1);
var crumb = Navigation.StateController.crumbs[0];
link = crumb.navigationLink;
Navigation.StateController.navigateLink(link, true);
// StateContext
Navigation.StateController.navigate('home');
Navigation.StateController.navigate('person');
home = Navigation.StateContext.previousDialog;
homePage = Navigation.StateContext.previousState;
person === Navigation.StateContext.dialog;
personList === Navigation.StateContext.state;
var url: string = Navigation.StateContext.url;
var page: number = Navigation.StateContext.data.page;
// Navigation Data
Navigation.StateController.refresh({ page: 2 });
var data = Navigation.StateContext.includeCurrentData({ sort: 'name' }, ['page']);
Navigation.StateController.refresh(data);
Navigation.StateContext.clear('sort');
var data = Navigation.StateContext.includeCurrentData({ pageSize: 10 });
Navigation.StateController.refresh(data);
Navigation.StateContext.clear();
Navigation.StateController.refresh();
}
+143 -9
View File
@@ -1,4 +1,4 @@
// Type definitions for Navigation 1.0
// Type definitions for Navigation 1.1.0
// Project: http://grahammendick.github.io/navigation/
// Definitions by: Graham Mendick <https://github.com/grahammendick>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
@@ -61,15 +61,20 @@ declare module Navigation {
*/
title?: string;
/**
* Gets the route Url pattern
* Gets the route Url patterns
*/
route: string;
route: string | string[];
/**
* Gets a value that indicates whether to maintain crumb trail
* information e.g PreviousState. This can be used together with Route
* to produce user friendly Urls
*/
trackCrumbTrail?: boolean;
/**
* Gets a value that indicates whether NavigationData Types are
* preserved when navigating
*/
trackTypes?: boolean;
}
/**
@@ -175,20 +180,35 @@ declare module Navigation {
*/
title: string;
/**
* Gets the route Url pattern
* Gets the route Url patterns
*/
route: string;
route: string | string[];
/**
* Gets a value that indicates whether to maintain crumb trail
* information e.g PreviousState. This can be used together with Route
* to produce user friendly Urls
*/
trackCrumbTrail: boolean;
/**
* Gets a value that indicates whether NavigationData Types are
* preserved when navigating
*/
trackTypes: boolean;
/**
* Gets or sets the IStateHandler responsible for building and parsing
* avigation links to this State
* navigation links to this State
*/
stateHandler: IStateHandler;
/**
* Called on the old State (this is not the same as the previous
* State) before navigating to a different State
* @param state The new State
* @param data The new NavigationData
* @param url The new target location
* @param unload The function to call to continue to navigate
* @param history A value indicating whether browser history was used
*/
unloading: (state: State, data: any, url: string, unload: () => void, history?: boolean) => void;
/**
* Called on the old State (this is not the same as the previous
* State) after navigating to a different State
@@ -197,15 +217,17 @@ declare module Navigation {
/**
* Called on the current State after navigating to it
* @param data The current NavigationData
* @param asyncData The data passed asynchronously while navigating
*/
navigated: (data: any) => void;
navigated: (data: any, asyncData?: any) => void;
/**
* Called on the new State before navigating to it
* @param data The new NavigationData
* @param url The new target location
* @param navigate The function to call to continue to navigate
* @param navigate The function to call to continue to navigate
* @param history A value indicating whether browser history was used
*/
navigating: (data: any, url: string, navigate: () => void) => void;
navigating: (data: any, url: string, navigate: (asyncData?: any) => void, history?: boolean) => void;
}
/**
@@ -366,6 +388,84 @@ declare module Navigation {
*/
getUrl(anchor: HTMLAnchorElement): string;
}
/**
* Provides the base functionality for crumb trail persistence mechanisms
*/
class CrumbTrailPersister {
/**
* Overridden by derived classes to return the persisted crumb trail
* @param crumbTrail The key, returned from the save function, to
* identify the persisted crumb trail
* @returns The crumb trail holding navigation and data information
*/
load(crumbTrail: string): string;
/**
* Overridden by derived classes to persist the crumb trail
* @param crumbTrail The crumb trail holding navigation and data
* information
* @returns The key to be passed to load function for crumb trail
* retrieval
*/
save(crumbTrail: string): string;
}
/**
* Persists crumb trails, over a specified length, in localStorage.
* Prevents the creation of unmanageably long Urls. If used in a browser
* without localStorage or outside of a browser environment, then in memory
* storage is used
*/
class StorageCrumbTrailPersister extends CrumbTrailPersister {
/**
* Initializes a new instance of the StorageCrumbTrailPersister class
* with a maxLength of 500, historySize of 100 and localStorage as the
* storage mechanism
*/
constructor();
/**
* Initializes a new instance of the StorageCrumbTrailPersister class
* with a historySize of 100 and localStorage as the storage mechanism
* @param maxLength The length above which any crumb trail will be
* stored in localStorage
*/
constructor(maxLength: number);
/**
* Initializes a new instance of the StorageCrumbTrailPersister class
* with localStorage as the storage mechanism
* @param maxLength The length above which any crumb trail will be
* stored in localStorage
* @param historySize The maximum number of crumb trails that will be
* held at any one time in localStorage
*/
constructor(maxLength: number, historySize: number);
/**
* Initializes a new instance of the StorageCrumbTrailPersister class
* @param maxLength The length above which any crumb trail will be
* stored in the storage
* @param historySize The maximum number of crumb trails that will be
* held at any one time in the storage
* @param storage The storage mechanism
*/
constructor(maxLength: number, historySize: number, storage: Storage);
/**
* Uses the crumbTrail parameter to determine whether to retrieve the
* crumb trail from storage. If retrieved from storage it may be null
* @param Key generated by the save function
* @returns Either the crumbTrail or the one retrieved value from
* storage; can be null if retrieved from storage
*/
load(crumbTrail: string): string;
/**
* If the crumbTrail is not over the maxLength it is returned.
* Otherwise the crumbTrail is stored in storage using a short key,
* unique within a given storage session. Also expunges old items from
* storage, if the historySize is breached when a new item is added
* @param crumbTrail The crumb trail to persist
* @returns crumbTrail or short, generated key pointing at crumbTrail
*/
save(crumbTrail: string): string;
}
/**
* Defines a contract a class must implement in order to build and parse
@@ -434,6 +534,14 @@ declare module Navigation {
navigationLink: string;
/**
* Initializes a new instance of the Crumb class
* @param data The Context Data held at the time of navigating away
* from this State
* @param state The configuration information associated with this
* navigation
* @param link The hyperlink navigation to return to the State and pass
* the associated Data
* @param last A value indicating whether the Crumb is the last in the
* crumb trail
*/
constructor(data: any, state: State, link: string, last: boolean);
}
@@ -442,8 +550,18 @@ declare module Navigation {
* Provides access to the Navigation Settings configuration
*/
class NavigationSettings {
/**
* Gets or sets the builder and parser of State routes
*/
router: IRouter;
/**
* Gets or sets the manager of the browser Url
*/
historyManager: IHistoryManager;
/**
* Gets or sets the crumb trail persistence mechanism
*/
crumbTrailPersister: CrumbTrailPersister;
/**
* Gets or sets the key that identifies the StateId
*/
@@ -464,6 +582,11 @@ declare module Navigation {
* Gets or sets the application path
*/
applicationPath: string;
/**
* Gets or sets a value indicating whether the PreviousStateId and
* ReturnData should be part of the CrumbTrail
*/
combineCrumbTrail: boolean;
}
/**
@@ -650,6 +773,12 @@ declare module Navigation {
* @param url The target location
*/
static navigateLink(url: string): void;
/**
* Navigates to the url
* @param url The target location
* @param history A value indicating whether browser history was used
*/
static navigateLink(url: string, history: boolean): void;
/**
* Gets the next State. Depending on the action will either return the
* 'to' State of a Transition or the 'initial' State of a Dialog
@@ -831,6 +960,11 @@ declare module Navigation {
* @returns The matched route and data
*/
match(path: string): { route: Route; data: any; };
/**
* Sorts the routes by the comparer
* @param compare The route comparer function
*/
sort(compare: (routeA: Route, routeB: Route) => number): void;
}
/**
+1
View File
@@ -150,6 +150,7 @@ declare module Rx {
immediate: IScheduler;
currentThread: ICurrentThreadScheduler;
default: IScheduler; // alias for Scheduler.timeout
timeout: IScheduler;
}