diff --git a/docs/change-log.md b/docs/change-log.md index 3a281aa0..8fb182f8 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -1,5 +1,21 @@ ## Change Log +[v0.1.31](/mithril/archive/v0.1.31) - maintenance + +### News: + +- Typescript definitions are more strongly typed +- m.request's `unwrapSuccess` and `unwrapError` callbacks now receive the XMLHttpRequest instance as a second parameter +- 3rd parameter for `m.route(route, params, shouldReplaceHistory)` is now public +- exact routes now have higher precedence than routes w/ variables [#452](https://github.com/lhorie/mithril.js/issues/452) + +### Bug Fixes: + +- fix routing bug in IE9 [#320](https://github.com/lhorie/mithril.js/issues/320) +- fix ordering bug in m.trust when using HTML entities [#453](https://github.com/lhorie/mithril.js/issues/453) + +--- + [v0.1.30](/mithril/archive/v0.1.30) - maintenance ### Bug Fixes: @@ -8,6 +24,8 @@ - fix module.view's `this` association regression in Haxe environment [#434](https://github.com/lhorie/mithril.js/issues/434) - fix array serialization syntax in querystrings [#440](https://github.com/lhorie/mithril.js/issues/440) +--- + [v0.1.29](/mithril/archive/v0.1.29) - maintenance ### News: diff --git a/docs/mithril.request.md b/docs/mithril.request.md index 1f45ccdb..ad89a482 100644 --- a/docs/mithril.request.md +++ b/docs/mithril.request.md @@ -164,6 +164,7 @@ In the example below, we take advantage of queuing to debug the AJAX response da //a FP-friendly console.log var log = function(value) { console.log(value) + return value } var users = m.request({method: "GET", url: "/user"}) @@ -507,7 +508,7 @@ where: The value that populates the returned getter-setter before the request completes. This is useful when using the `background` option, in order to avoid the need for null checks in views that may be attempting to access the returned getter-setter before the asynchronous request resolves. - - **any unwrapSuccess(any data)** (optional) + - **any unwrapSuccess(any data, XMLHttpRequest xhr)** (optional) A preprocessor function to unwrap the data from a success response in case the response contains metadata wrapping the data. @@ -523,7 +524,7 @@ where: The unwrapped data - - **any unwrapError(any data)** (optional) + - **any unwrapError(any data, XMLHttpRequest xhr)** (optional) A preprocessor function to unwrap the data from an error response in case the response contains metadata wrapping the data. diff --git a/docs/mithril.route.md b/docs/mithril.route.md index b32abdf6..fb3b50ee 100644 --- a/docs/mithril.route.md +++ b/docs/mithril.route.md @@ -73,7 +73,7 @@ m.route(document.body, "/dashboard/johndoe", { This redirects to the URL `http://server/#/dashboard/johndoe` and yields: ```markup -johndoe +
johndoe
``` Above, `dashboard` is a module. It contains a `controller` and a `view` properties. When the URL matches a route, the respective module's controller is instantiated and passed as a parameter to the view. diff --git a/mithril.d.ts b/mithril.d.ts index 5bdcff5b..06264c71 100644 --- a/mithril.d.ts +++ b/mithril.d.ts @@ -1,76 +1,165 @@ //Mithril type definitions for Typescript interface MithrilStatic { - (selector: string, attributes: Object, children?: any): MithrilVirtualElement; - (selector: string, children?: any): MithrilVirtualElement; - prop(value?: any): (value?: any) => any; - withAttr(property: string, callback: (value: any) => void): (e: Event) => any; - module(rootElement: Node, module?: MithrilModule): Object; - trust(html: string): String; - render(rootElement: Element, children?: any): void; - render(rootElement: HTMLDocument, children?: any): void; - redraw: { - (): void; - strategy(key: string); - }; - route: { - (rootElement:Element, defaultRoute:string, routes:{ [key: string]: MithrilModule }): void - (element: Element, isInitialized: boolean): void; - (rootElement:HTMLDocument, defaultRoute:string, routes:{ [key: string]: MithrilModule }): void; - (path:string, params?:any, shouldReplaceHistory?:boolean): void; - (): string; - param(key:string): string; - mode: string; - }; - request(options: MithrilXHROptions): MithrilPromise; - deferred(): MithrilDeferred; - sync(promises: MithrilPromise[]): MithrilPromise; - startComputation(): void; - endComputation(): void; - deps(Object: any): Object; + + (selector: string, attributes: MithrilAttributes, ...children: Array): MithrilVirtualElement; + (selector: string, ...children: Array): MithrilVirtualElement; + + prop(promise: MithrilPromise) : MithrilPromiseProperty; + prop(value: T): MithrilProperty; + prop(): MithrilProperty; // might be that this should be Property + + withAttr(property: string, callback: (value: any) => void): (e: MithrilEvent) => any; + + module(rootElement: Node, module: MithrilModule): T; + module(rootElement: Node): T; + + trust(html: string): string; + + render(rootElement: Element|HTMLDocument): void; + render(rootElement: Element|HTMLDocument, children: MithrilVirtualElement, forceRecreation?: boolean): void; + render(rootElement: Element|HTMLDocument, children: MithrilVirtualElement[], forceRecreation?: boolean): void; + + redraw: { + (force?: boolean): void; + strategy: MithrilProperty; + } + + route: { + (rootElement: HTMLDocument, defaultRoute: string, routes: MithrilRoutes): void; + (rootElement: Element, defaultRoute: string, routes: MithrilRoutes): void; + + (element: Element, isInitialized: boolean): void; + (path: string, params?: any, shouldReplaceHistory?: boolean): void; + (): string; + + param(key: string): string; + mode: string; + } + + request(options: MithrilXHROptions): MithrilPromise; + + deferred: { + onerror(e: Error): void; + (): MithrilDeferred; + } + + sync(promises: MithrilPromise[]): MithrilPromise; + + startComputation(): void; + endComputation(): void; + + // For test suite + deps: { + (mockWindow: Window): Window; + factory: Object; + } + } interface MithrilVirtualElement { - tag: string; - attrs: Object; - children: any; + key?: number; + tag?: string; + attrs?: MithrilAttributes; + children?: any[]; } -interface MithrilModule { - controller: Function; - view: Function; +// Configuration function for an element +interface MithrilElementConfig { + (element: Element, isInitialized: boolean, context?: any): void; } -interface MithrilDeferred { - resolve(value?: any): void; - reject(value?: any): void; - promise: MithrilPromise; +// Attributes on a virtual element +interface MithrilAttributes { + title?: string; + className?: string; + class?: string; + config?: MithrilElementConfig; } -interface MithrilPromise { - (value?: any): any; - then(successCallback?: (value: any) => any, errorCallback?: (value: any) => any): MithrilPromise; +// Defines the subset of Event that Mithril needs +interface MithrilEvent { + currentTarget: Element; } +interface MithrilController { + onunload?(evt: Event): any; +} + +interface MithrilControllerFunction extends MithrilController { + (): any; +} + +interface MithrilView { + (ctrl: T): string|MithrilVirtualElement; +} + +interface MithrilModule { + controller: MithrilControllerFunction|{ new(): T }; + view: MithrilView; +} + +interface MithrilProperty { + (): T; + (value: T): T; + toJSON(): T; +} + +interface MithrilPromiseProperty extends MithrilPromise { + (): T; + (value: T): T; + toJSON(): T; +} + +interface MithrilRoutes { + [key: string]: MithrilModule; +} + + +interface MithrilDeferred { + resolve(value?: T): void; + reject(value?: any): void; + promise: MithrilPromise; +} + +interface MithrilSuccessCallback { + (value: T): U; + (value: T): MithrilPromise; +} + +interface MithrilErrorCallback { + (value: Error): U; + (value: string): U; +} + +interface MithrilPromise { + (): T; + (value: T): T; + then(success: (value: T) => U): MithrilPromise; + then(success: (value: T) => MithrilPromise): MithrilPromise; + then(success: (value: T) => U, error: (value: Error) => V): MithrilPromise|MithrilPromise; + then(success: (value: T) => MithrilPromise, error: (value: Error) => V): MithrilPromise|MithrilPromise; +} interface MithrilXHROptions { - method: string; - url: string; - user?: string; - password?: string; - data?: any; - background?: boolean; - unwrapSuccess?(data: any): any; - unwrapError?(data: any): any; - serialize?(dataToSerialize: any): string; - deserialize?(dataToDeserialize: string): any; - extract?(xhr: XMLHttpRequest, options: MithrilXHROptions): string; - type?(data: Object): void; - config?(xhr: XMLHttpRequest, options: MithrilXHROptions): XMLHttpRequest; + method?: string; + url: string; + user?: string; + password?: string; + data?: any; + background?: boolean; + unwrapSuccess?(data: any): any; + unwrapError?(data: any): any; + serialize?(dataToSerialize: any): string; + deserialize?(dataToDeserialize: string): any; + extract?(xhr: XMLHttpRequest, options: MithrilXHROptions): string; + type?(data: Object): void; + config?(xhr: XMLHttpRequest, options: MithrilXHROptions): XMLHttpRequest; + dataType?: string; } declare var Mithril: MithrilStatic; declare var m: MithrilStatic; declare module 'mithril' { - export = MithrilStatic; + export = m; } diff --git a/mithril.js b/mithril.js index 2dead416..1c8f7e5e 100644 --- a/mithril.js +++ b/mithril.js @@ -648,13 +648,19 @@ var m = (function app(window, undefined) { window[listener]() } //config: m.route - else if (arguments[0].addEventListener) { + else if (arguments[0].addEventListener || arguments[0].attachEvent) { var element = arguments[0]; var isInitialized = arguments[1]; var context = arguments[2]; element.href = (m.route.mode !== 'pathname' ? $location.pathname : '') + modes[m.route.mode] + this.attrs.href; - element.removeEventListener("click", routeUnobtrusive); - element.addEventListener("click", routeUnobtrusive) + if (element.addEventListener) { + element.removeEventListener("click", routeUnobtrusive); + element.addEventListener("click", routeUnobtrusive) + } + else { + element.detachEvent("onclick", routeUnobtrusive); + element.attachEvent("onclick", routeUnobtrusive) + } } //m.route(route, params) else if (type.call(arguments[0]) === STRING) { @@ -677,7 +683,10 @@ var m = (function app(window, undefined) { }; redirect(modes[m.route.mode] + currentRoute) } - else $location[m.route.mode] = currentRoute + else { + $location[m.route.mode] = currentRoute + redirect(modes[m.route.mode] + currentRoute) + } } }; m.route.param = function(key) { @@ -730,8 +739,9 @@ var m = (function app(window, undefined) { if (e.ctrlKey || e.metaKey || e.which === 2) return; if (e.preventDefault) e.preventDefault(); else e.returnValue = false; - var currentTarget = e.currentTarget || this; + var currentTarget = e.currentTarget || e.srcElement; var args = m.route.mode === "pathname" && currentTarget.search ? parseQueryString(currentTarget.search.slice(1)) : {}; + while (currentTarget && currentTarget.nodeName.toUpperCase() != "A") currentTarget = currentTarget.parentNode m.route(currentTarget[m.route.mode].slice(modes[m.route.mode].length), args) } function setScroll() {