diff --git a/docs/change-log.md b/docs/change-log.md index 3a281aa0..273cd0b1 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -1,5 +1,22 @@ ## 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) +- set promise's default value to initialValue if coming from m.request [#454](https://github.com/lhorie/mithril.js/issues/454) + +--- + [v0.1.30](/mithril/archive/v0.1.30) - maintenance ### Bug Fixes: @@ -8,6 +25,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..2b474861 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"}) @@ -432,8 +433,8 @@ where: [Object data,] [Boolean background,] [any initialValue,] - [any unwrapSuccess(any data),] - [any unwrapError(any data),] + [any unwrapSuccess(any data, XMLHttpRequest xhr),] + [any unwrapError(any data, XMLHttpRequest xhr),] [String serialize(any dataToSerialize),] [any deserialize(String dataToDeserialize),] [any extract(XMLHttpRequest xhr, XHROptions options),] @@ -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/tools.md b/docs/tools.md index 4cd78210..a0c0ae76 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -57,7 +57,7 @@ You can use it by adding a reference to your Typescript files. This will allow t ### Internet Explorer Compatibility -Mithril relies on some Ecmascript 5 features, namely: `Array::indexOf`, `Array::map` and `Object::keys`, as well as the `JSON` object. +Mithril relies on some ECMAScript 5 features, namely: `Array::indexOf`, `Array::map` and `Object::keys`, as well as the `JSON` object. Internet Explorer 8 lacks native support for some of these features. The easiest way to polyfill these features is to include this script: @@ -68,7 +68,7 @@ The easiest way to polyfill these features is to include this script: This will provide all the polyfills required for the browser. You can alternatively include only specific polyfills: ```markup - + ``` You can also use other polyfills to support these features in IE7. @@ -79,4 +79,4 @@ You can also use other polyfills to support these features in IE7. Mithril also has a dependency on XMLHttpRequest. If you wish to support IE6, you'll need [a shim for it](https://gist.github.com/Contra/2709462). IE7 and lower do not support cross-domain AJAX requests. -In addition, note that most `m.route` modes rely on `history.pushState` in order to allow moving from one page to another without a browser refresh. [IE9 and lower](http://caniuse.com/#search=pushstate) do not support this feature and will gracefully degrade to page refreshes instead. \ No newline at end of file +In addition, note that most `m.route` modes rely on `history.pushState` in order to allow moving from one page to another without a browser refresh. [IE9 and lower](http://caniuse.com/#search=pushstate) do not support this feature and will gracefully degrade to page refreshes instead. diff --git a/mithril.d.ts b/mithril.d.ts index 3279b8cc..06264c71 100644 --- a/mithril.d.ts +++ b/mithril.d.ts @@ -2,161 +2,164 @@ interface MithrilStatic { - (selector: string, attributes: MithrilAttributes, ...children: Array): MithrilVirtualElement; - (selector: string, ...children: Array): MithrilVirtualElement; + (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 + 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; + withAttr(property: string, callback: (value: any) => void): (e: MithrilEvent) => any; - module(rootElement: Node, module: MithrilModule): T; - module(rootElement: Node): T; + module(rootElement: Node, module: MithrilModule): T; + module(rootElement: Node): T; - trust(html: string): string; + 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; + 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; - } + redraw: { + (force?: boolean): void; + strategy: MithrilProperty; + } - route: { - (rootElement: HTMLDocument, defaultRoute: string, routes: MithrilRoutes): void; - (rootElement: Element, defaultRoute: string, routes: MithrilRoutes): void; + 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; + (element: Element, isInitialized: boolean): void; + (path: string, params?: any, shouldReplaceHistory?: boolean): void; + (): string; - param(key: string): string; - mode: string; - } + param(key: string): string; + mode: string; + } - request(options: MithrilXHROptions): MithrilPromise; + request(options: MithrilXHROptions): MithrilPromise; - deferred: { - onerror(e: Error): void; - (): MithrilDeferred; - } + deferred: { + onerror(e: Error): void; + (): MithrilDeferred; + } - sync(promises: MithrilPromise[]): MithrilPromise; + sync(promises: MithrilPromise[]): MithrilPromise; - startComputation(): void; - endComputation(): void; + startComputation(): void; + endComputation(): void; - // For test suite - deps: { - (mockWindow: Window): Window; - factory: Object; - } + // For test suite + deps: { + (mockWindow: Window): Window; + factory: Object; + } } interface MithrilVirtualElement { - key?: number; - tag?: string; - attrs?: MithrilAttributes; - children?: any[]; + key?: number; + tag?: string; + attrs?: MithrilAttributes; + children?: any[]; } // Configuration function for an element interface MithrilElementConfig { - (element: Element, isInitialized: boolean, context?: any): void; + (element: Element, isInitialized: boolean, context?: any): void; } // Attributes on a virtual element interface MithrilAttributes { - title?: string; - className?: string; - class?: string; - config?: MithrilElementConfig; + title?: string; + className?: string; + class?: string; + config?: MithrilElementConfig; } // Defines the subset of Event that Mithril needs interface MithrilEvent { - currentTarget: Element; + currentTarget: Element; } interface MithrilController { - (): any; - onunload?(evt: Event): any; + onunload?(evt: Event): any; +} + +interface MithrilControllerFunction extends MithrilController { + (): any; } interface MithrilView { - (ctrl: T): string|MithrilVirtualElement; + (ctrl: T): string|MithrilVirtualElement; } interface MithrilModule { - controller: T; - view: MithrilView; + controller: MithrilControllerFunction|{ new(): T }; + view: MithrilView; } interface MithrilProperty { - (): T; - (value: T): T; - toJSON(): T; + (): T; + (value: T): T; + toJSON(): T; } interface MithrilPromiseProperty extends MithrilPromise { - (): T; - (value: T): T; - toJSON(): T; + (): T; + (value: T): T; + toJSON(): T; } interface MithrilRoutes { - [key: string]: MithrilModule; + [key: string]: MithrilModule; } interface MithrilDeferred { - resolve(value?: T): void; - reject(value?: any): void; - promise: MithrilPromise; + resolve(value?: T): void; + reject(value?: any): void; + promise: MithrilPromise; } interface MithrilSuccessCallback { - (value: T): U; - (value: T): MithrilPromise; + (value: T): U; + (value: T): MithrilPromise; } interface MithrilErrorCallback { - (value: Error): U; - (value: string): U; + (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; + (): 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; - dataType?: string; + 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 = m; + export = m; } diff --git a/mithril.js b/mithril.js index 9c49da7b..2c2cf7ce 100644 --- a/mithril.js +++ b/mithril.js @@ -607,13 +607,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) { @@ -636,7 +642,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) { @@ -689,8 +698,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() { @@ -735,7 +745,8 @@ var m = (function app(window, undefined) { var prop = m.prop(); promise.then(prop); prop.then = function(resolve, reject) { - return propify(promise.then(resolve, reject)) + promise = promise.then(resolve, reject).then(prop); + return prop; }; return prop } diff --git a/tests/mithril-tests.js b/tests/mithril-tests.js index 00b30e34..b451f0af 100644 --- a/tests/mithril-tests.js +++ b/tests/mithril-tests.js @@ -2246,6 +2246,13 @@ function testMithril(mock) { xhr.onreadystatechange() return xhr.$headers["Content-Type"] === undefined }) + test(function() { + var prop = m.request({method: "POST", url: "test", initialValue: "foo"}).then(function(data) { return data; }) + var initialValue = prop(); + mock.XMLHttpRequest.$instances.pop().onreadystatechange() + + return initialValue === "foo" + }) test(function() { var prop = m.request({method: "POST", url: "test", initialValue: "foo"}) var initialValue = prop();