diff --git a/history.js/history-tests.ts b/history.js/history-tests.ts new file mode 100644 index 0000000000..46c848d1b7 --- /dev/null +++ b/history.js/history-tests.ts @@ -0,0 +1,25 @@ + + +// Since History is defined in lib.d.ts as well +// the name for our interfaces was chosen to be Historyjs +// However at runtime you would need to do +// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/277 +var Historyjs: Historyjs = History; + +function tests() { + if (!Historyjs.enabled) { + return false; + } + + Historyjs.Adapter.bind(window, 'statechange', () => { + var State = Historyjs.getState(); + Historyjs.log(State.data, State.title, State.url); + }); + + Historyjs.pushState({ state: 1 }, "State 1", "?state=1"); + Historyjs.pushState({ state: 2 }, "State 2", "?state=2"); + Historyjs.replaceState({ state: 3 }, "State 3", "?state=3"); + Historyjs.pushState(null, null, "?state=4"); + Historyjs.back(); + Historyjs.go(2); +} \ No newline at end of file diff --git a/history.js/index.d.ts b/history.js/index.d.ts new file mode 100644 index 0000000000..5a24bd5d73 --- /dev/null +++ b/history.js/index.d.ts @@ -0,0 +1,61 @@ +// Type definitions for History.js 1.8.0 +// Project: https://github.com/browserstate/history.js +// Definitions by: Boris Yankov , Gidon Junge +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + + +interface HistoryAdapter { + bind(element: any, event: string, callback: () => void): void; + trigger(element: any, event: string): void; + onDomLoad(callback: () => void): void; +} + +// Since History is defined in lib.d.ts as well +// the name for our interfaces was chosen to be Historyjs +// However at runtime you would need to do +// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/277 +// var Historyjs: Historyjs = History; + +interface Historyjs { + + enabled: boolean; + + pushState(data: any, title: string, url: string): void; + replaceState(data: any, title: string, url: string): void; + getState(): HistoryState; + getStateByIndex(index: number): HistoryState; + getCurrentIndex(): number; + getHash(): string; + + Adapter: HistoryAdapter; + + back(): void; + forward(): void; + go(x: Number): void; + + log(...messages: any[]): void; + debug(...messages: any[]): void; + + options: HistoryOptions; +} + +interface HistoryState { + data?: any; + title?: string; + url: string; +} + +interface HistoryOptions { + hashChangeInterval?: number; + safariPollInterval?: number; + doubleCheckInterval?: number; + disableSuid?: boolean; + storeInterval?: number; + busyDelay?: number; + debug?: boolean; + initialTitle?: string; + html4Mode?: boolean; + delayInit?: number; + + +} diff --git a/history.js/tsconfig.json b/history.js/tsconfig.json new file mode 100644 index 0000000000..fc317ff3fe --- /dev/null +++ b/history.js/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "noImplicitAny": true, + "strictNullChecks": false, + "baseUrl": "../", + "typesSearchPaths": [ + "../" + ], + "noEmit": true + }, + "files": [ + "index.d.ts", + "history-tests.ts" + ] +} \ No newline at end of file diff --git a/history/history-tests.ts b/history/history-tests.ts index 46c848d1b7..fb4ae10cfd 100644 --- a/history/history-tests.ts +++ b/history/history-tests.ts @@ -1,25 +1,132 @@ -// Since History is defined in lib.d.ts as well -// the name for our interfaces was chosen to be Historyjs -// However at runtime you would need to do -// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/277 -var Historyjs: Historyjs = History; +import { createHistory, createLocation, useBeforeUnload, useQueries, useBasename } from 'history' +import { getUserConfirmation } from 'history/lib/DOMUtils' -function tests() { - if (!Historyjs.enabled) { - return false; - } +interface Promise { + then(onfulfilled?: (value: T) => TResult): Promise; +} - Historyjs.Adapter.bind(window, 'statechange', () => { - var State = Historyjs.getState(); - Historyjs.log(State.data, State.title, State.url); +let doSomethingAsync: () => Promise; +let input = { value: "" }; + +{ + let history = createHistory() + + // Listen for changes to the current location. The + // listener is called once immediately. + let unlisten = history.listen(function(location) { + console.log(location.pathname) + }) + + // When you're finished, stop the listener. + unlisten() + + // Push a new entry onto the history stack. + history.push('/home') + + // Replace the current entry on the history stack. + history.replace('/profile') + + // Push a new entry with state onto the history stack. + history.push({ + pathname: '/about', + search: '?the=search', + state: { some: 'state' } }); - Historyjs.pushState({ state: 1 }, "State 1", "?state=1"); - Historyjs.pushState({ state: 2 }, "State 2", "?state=2"); - Historyjs.replaceState({ state: 3 }, "State 3", "?state=3"); - Historyjs.pushState(null, null, "?state=4"); - Historyjs.back(); - Historyjs.go(2); + // Change just the search on an existing location. + //history.push({ ...location, search: '?the=other+search' }) + + // Go back to the previous history entry. The following + // two lines are synonymous. + history.go(-1) + history.goBack() + + let href = history.createHref('/the/path') +} + +{ + let history = createHistory() + + // Pushing a path string. + history.push('/the/path') + + // Omitting location state when pushing a location descriptor. + history.push({ pathname: '/the/path', search: '?the=search' }) + + // Extending an existing location object. + //history.push({ ...location, search: '?other=search' }) + + let location = createLocation('/a/path?a=query', { the: 'state' }) + + location = history.createLocation('/a/path?a=query', { the: 'state' }) +} + +{ + let history = createHistory() + history.listenBefore(function(location) { + if (input.value !== '') + return 'Are you sure you want to leave this page?' + }) + + history.listenBefore(function(location, callback) { + doSomethingAsync().then(callback) + }) +} + +{ + let history = createHistory({ + getUserConfirmation(message, callback) { + callback(window.confirm(message)) // The default behavior + } + }) +} + +{ + let history = useBeforeUnload(createHistory)() + + history.listenBeforeUnload(function() { + return 'Are you sure you want to leave this page?' + }) +} + +{ + let history = useQueries(createHistory)() + + history.listen(function(location) { + console.log(location.query) + }) +} + +{ + let history = useQueries(createHistory)({ + parseQueryString: function(queryString) { + // TODO: return a parsed version of queryString + return {}; + }, + stringifyQuery: function(query) { + // TODO: return a query string created from query + return ""; + } + }) + + history.createPath({ pathname: '/the/path', query: { the: 'query' } }) + history.push({ pathname: '/the/path', query: { the: 'query' } }) +} + +{ + // Run our app under the /base URL. + let history = useBasename(createHistory)({ + basename: '/base' + }) + + // At the /base/hello/world URL: + history.listen(function(location) { + console.log(location.pathname) // /hello/world + console.log(location.basename) // /base + }) + + history.createPath('/the/path') // /base/the/path + history.push('/the/path') // push /base/the/path } \ No newline at end of file diff --git a/history/index.d.ts b/history/index.d.ts index 5a24bd5d73..24d30e12af 100644 --- a/history/index.d.ts +++ b/history/index.d.ts @@ -1,61 +1,126 @@ -// Type definitions for History.js 1.8.0 -// Project: https://github.com/browserstate/history.js -// Definitions by: Boris Yankov , Gidon Junge +// Type definitions for history v2.0.0 +// Project: https://github.com/rackt/history +// Definitions by: Sergey Buturlakin , Nathan Brown // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// types based on https://github.com/rackt/history/blob/master/docs/Terms.md -interface HistoryAdapter { - bind(element: any, event: string, callback: () => void): void; - trigger(element: any, event: string): void; - onDomLoad(callback: () => void): void; +export type Action = string; +export type BeforeUnloadHook = () => string | boolean; +export type CreateHistory = (options?: HistoryOptions) => T; +export type CreateHistoryEnhancer = (createHistory: CreateHistory) => CreateHistory; + +export interface History { + listenBefore(hook: TransitionHook): () => void; + listen(listener: LocationListener): () => void; + transitionTo(location: Location): void; + push(path: LocationDescriptor): void; + replace(path: LocationDescriptor): void; + go(n: number): void; + goBack(): void; + goForward(): void; + createKey(): LocationKey; + createPath(path: LocationDescriptor): Path; + createHref(path: LocationDescriptor): Href; + createLocation(path?: LocationDescriptor, action?: Action, key?: LocationKey): Location; + + /** @deprecated use a location descriptor instead */ + createLocation(path?: Path, state?: LocationState, action?: Action, key?: LocationKey): Location; + /** @deprecated use location.key to save state instead */ + pushState(state: LocationState, path: Path): void; + /** @deprecated use location.key to save state instead */ + replaceState(state: LocationState, path: Path): void; + /** @deprecated use location.key to save state instead */ + setState(state: LocationState): void; + /** @deprecated use listenBefore instead */ + registerTransitionHook(hook: TransitionHook): void; + /** @deprecated use the callback returned from listenBefore instead */ + unregisterTransitionHook(hook: TransitionHook): void; } -// Since History is defined in lib.d.ts as well -// the name for our interfaces was chosen to be Historyjs -// However at runtime you would need to do -// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/277 -// var Historyjs: Historyjs = History; - -interface Historyjs { - - enabled: boolean; - - pushState(data: any, title: string, url: string): void; - replaceState(data: any, title: string, url: string): void; - getState(): HistoryState; - getStateByIndex(index: number): HistoryState; - getCurrentIndex(): number; - getHash(): string; - - Adapter: HistoryAdapter; - - back(): void; - forward(): void; - go(x: Number): void; - - log(...messages: any[]): void; - debug(...messages: any[]): void; - - options: HistoryOptions; +export type HistoryOptions = { + getCurrentLocation?: () => Location; + finishTransition?: (nextLocation: Location) => boolean; + saveState?: (key: LocationKey, state: LocationState) => void; + go?: (n: number) => void; + getUserConfirmation?: (message: string, callback: (result: boolean) => void) => void; + keyLength?: number; + queryKey?: string | boolean; + stringifyQuery?: (obj: any) => string; + parseQueryString?: (str: string) => any; + basename?: string; + entries?: string | [any]; + current?: number; } -interface HistoryState { - data?: any; - title?: string; - url: string; +export type Href = string + +export type Location = { + pathname: Pathname; + search: Search; + query: Query; + state: LocationState; + action: Action; + key: LocationKey; + basename?: string; +}; + +export type LocationDescriptorObject = { + pathname?: Pathname; + search?: Search; + query?: Query; + state?: LocationState; +}; + +export type LocationDescriptor = LocationDescriptorObject | Path; +export type LocationKey = string; +export type LocationListener = (location: Location) => void; +export type LocationState = Object; +export type Path = string // Pathname + QueryString; +export type Pathname = string; +export type Query = Object; +export type QueryString = string; +export type Search = string; + +export type TransitionHook = (location: Location, callback: (result: any) => void) => any + + +export interface HistoryBeforeUnload { + listenBeforeUnload(hook: BeforeUnloadHook): () => void; } -interface HistoryOptions { - hashChangeInterval?: number; - safariPollInterval?: number; - doubleCheckInterval?: number; - disableSuid?: boolean; - storeInterval?: number; - busyDelay?: number; - debug?: boolean; - initialTitle?: string; - html4Mode?: boolean; - delayInit?: number; - - +export interface HistoryQueries { + pushState(state: LocationState, pathname: Pathname | Path, query?: Query): void; + replaceState(state: LocationState, pathname: Pathname | Path, query?: Query): void; + createPath(path: Path, query?: Query): Path; + createHref(path: Path, query?: Query): Href; } + + +// Global usage, without modules, needs the small trick, because lib.d.ts +// already has `history` and `History` global definitions: +// var createHistory = ((window as any).History as HistoryModule.Module).createHistory; +export interface Module { + createHistory: CreateHistory; + createHashHistory: CreateHistory; + createMemoryHistory: CreateHistory; + createLocation(path?: Path, state?: LocationState, action?: Action, key?: LocationKey): Location; + useBasename(createHistory: CreateHistory): CreateHistory; + useBeforeUnload(createHistory: CreateHistory): CreateHistory; + useQueries(createHistory: CreateHistory): CreateHistory; + actions: { + PUSH: string; + REPLACE: string; + POP: string; + }; +} + +export { default as createHistory } from "history/lib/createBrowserHistory"; +export { default as createHashHistory } from "history/lib/createHashHistory"; +export { default as createMemoryHistory } from "history/lib/createMemoryHistory"; +export { default as createLocation } from "history/lib/createLocation"; +export { default as useBasename } from "history/lib/useBasename"; +export { default as useBeforeUnload } from "history/lib/useBeforeUnload"; +export { default as useQueries } from "history/lib/useQueries"; +import * as Actions from "history/lib/actions"; +export { Actions }; diff --git a/history/lib/DOMUtils.d.ts b/history/lib/DOMUtils.d.ts new file mode 100644 index 0000000000..f70a5993f9 --- /dev/null +++ b/history/lib/DOMUtils.d.ts @@ -0,0 +1,9 @@ +export function addEventListener(node: EventTarget, event: string, listener: EventListenerOrEventListenerObject): void; +export function removeEventListener(node: EventTarget, event: string, listener: EventListenerOrEventListenerObject): void; +export function getHashPath(): string; +export function replaceHashPath(path: string): void; +export function getWindowPath(): string; +export function go(n: number): void; +export function getUserConfirmation(message: string, callback: (result: boolean) => void): void; +export function supportsHistory(): boolean; +export function supportsGoWithoutReloadUsingHash(): boolean; diff --git a/history/lib/actions.d.ts b/history/lib/actions.d.ts new file mode 100644 index 0000000000..9eba9d4653 --- /dev/null +++ b/history/lib/actions.d.ts @@ -0,0 +1,9 @@ +export const PUSH: string; +export const REPLACE: string; +export const POP: string; + +export default { + PUSH, + REPLACE, + POP +} diff --git a/history/lib/createBrowserHistory.d.ts b/history/lib/createBrowserHistory.d.ts new file mode 100644 index 0000000000..a82b17e788 --- /dev/null +++ b/history/lib/createBrowserHistory.d.ts @@ -0,0 +1,2 @@ +import { HistoryOptions, History } from 'history'; +export default function createBrowserHistory(options?: HistoryOptions): History; \ No newline at end of file diff --git a/history/lib/createHashHistory.d.ts b/history/lib/createHashHistory.d.ts new file mode 100644 index 0000000000..57c0e8c1bb --- /dev/null +++ b/history/lib/createHashHistory.d.ts @@ -0,0 +1,2 @@ +import { HistoryOptions, History } from 'history'; +export default function createHashHistory(options?: HistoryOptions): History; \ No newline at end of file diff --git a/history/lib/createLocation.d.ts b/history/lib/createLocation.d.ts new file mode 100644 index 0000000000..c78f9fed80 --- /dev/null +++ b/history/lib/createLocation.d.ts @@ -0,0 +1,2 @@ +import { Path, LocationState, Action, LocationKey, Location } from 'history'; +export default function createLocation(path?: Path, state?: LocationState, action?: Action, key?: LocationKey): Location; diff --git a/history/lib/createMemoryHistory.d.ts b/history/lib/createMemoryHistory.d.ts new file mode 100644 index 0000000000..30d0180961 --- /dev/null +++ b/history/lib/createMemoryHistory.d.ts @@ -0,0 +1,2 @@ +import { HistoryOptions, History } from 'history'; +export default function createMemoryHistory(options?: HistoryOptions): History; diff --git a/history/lib/useBasename.d.ts b/history/lib/useBasename.d.ts new file mode 100644 index 0000000000..b9cfafff20 --- /dev/null +++ b/history/lib/useBasename.d.ts @@ -0,0 +1,2 @@ +import { CreateHistory } from 'history'; +export default function useBasename(createHistory: CreateHistory): CreateHistory; diff --git a/history/lib/useBeforeUnload.d.ts b/history/lib/useBeforeUnload.d.ts new file mode 100644 index 0000000000..87d0370a2b --- /dev/null +++ b/history/lib/useBeforeUnload.d.ts @@ -0,0 +1,2 @@ +import { CreateHistory, HistoryBeforeUnload } from 'history'; +export default function useBeforeUnload(createHistory: CreateHistory): CreateHistory; diff --git a/history/lib/useQueries.d.ts b/history/lib/useQueries.d.ts new file mode 100644 index 0000000000..2bb2a6697a --- /dev/null +++ b/history/lib/useQueries.d.ts @@ -0,0 +1,2 @@ +import { CreateHistory, HistoryQueries } from 'history'; +export default function useQueries(createHistory: CreateHistory): CreateHistory; \ No newline at end of file