Merge remote-tracking branch 'origin/next' into ctx-reuse-flag

This commit is contained in:
Leo Horie 2015-02-26 22:54:13 -05:00
commit 1a57bcc403
6 changed files with 142 additions and 101 deletions

View file

@ -1,5 +1,22 @@
## Change Log ## 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 [v0.1.30](/mithril/archive/v0.1.30) - maintenance
### Bug Fixes: ### 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 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) - fix array serialization syntax in querystrings [#440](https://github.com/lhorie/mithril.js/issues/440)
---
[v0.1.29](/mithril/archive/v0.1.29) - maintenance [v0.1.29](/mithril/archive/v0.1.29) - maintenance
### News: ### News:

View file

@ -164,6 +164,7 @@ In the example below, we take advantage of queuing to debug the AJAX response da
//a FP-friendly console.log //a FP-friendly console.log
var log = function(value) { var log = function(value) {
console.log(value) console.log(value)
return value
} }
var users = m.request({method: "GET", url: "/user"}) var users = m.request({method: "GET", url: "/user"})
@ -432,8 +433,8 @@ where:
[Object<any> data,] [Object<any> data,]
[Boolean background,] [Boolean background,]
[any initialValue,] [any initialValue,]
[any unwrapSuccess(any data),] [any unwrapSuccess(any data, XMLHttpRequest xhr),]
[any unwrapError(any data),] [any unwrapError(any data, XMLHttpRequest xhr),]
[String serialize(any dataToSerialize),] [String serialize(any dataToSerialize),]
[any deserialize(String dataToDeserialize),] [any deserialize(String dataToDeserialize),]
[any extract(XMLHttpRequest xhr, XHROptions options),] [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. 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. 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 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. A preprocessor function to unwrap the data from an error response in case the response contains metadata wrapping the data.

View file

@ -57,7 +57,7 @@ You can use it by adding a reference to your Typescript files. This will allow t
### Internet Explorer Compatibility ### 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: 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: This will provide all the polyfills required for the browser. You can alternatively include only specific polyfills:
```markup ```markup
<script src="https://polyfill.io/readable/gimme(array.prototype.indexof,object.keys,function.prototype.bind,array.prototype.foreach,JSON)"></script> <script src="http://cdn.polyfill.io/v1/polyfill.min.js?features=Array.prototype.indexOf,Object.keys,Function.prototype.bind,Array.prototype.forEach,JSON"></script>
``` ```
You can also use other polyfills to support these features in IE7. You can also use other polyfills to support these features in IE7.

179
mithril.d.ts vendored
View file

@ -2,161 +2,164 @@
interface MithrilStatic { interface MithrilStatic {
(selector: string, attributes: MithrilAttributes, ...children: Array<string|MithrilVirtualElement>): MithrilVirtualElement; (selector: string, attributes: MithrilAttributes, ...children: Array<string|MithrilVirtualElement>): MithrilVirtualElement;
(selector: string, ...children: Array<string|MithrilVirtualElement>): MithrilVirtualElement; (selector: string, ...children: Array<string|MithrilVirtualElement>): MithrilVirtualElement;
prop<T>(promise: MithrilPromise<T>) : MithrilPromiseProperty<T>; prop<T>(promise: MithrilPromise<T>) : MithrilPromiseProperty<T>;
prop<T>(value: T): MithrilProperty<T>; prop<T>(value: T): MithrilProperty<T>;
prop(): MithrilProperty<Object>; // might be that this should be Property<any> prop(): MithrilProperty<Object>; // might be that this should be Property<any>
withAttr(property: string, callback: (value: any) => void): (e: MithrilEvent) => any; withAttr(property: string, callback: (value: any) => void): (e: MithrilEvent) => any;
module<T extends MithrilController>(rootElement: Node, module: MithrilModule<T>): T; module<T extends MithrilController>(rootElement: Node, module: MithrilModule<T>): T;
module<T extends MithrilController>(rootElement: Node): T; module<T extends MithrilController>(rootElement: Node): T;
trust(html: string): string; trust(html: string): string;
render(rootElement: Element|HTMLDocument): void; 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, children: MithrilVirtualElement[], forceRecreation?: boolean): void; render(rootElement: Element|HTMLDocument, children: MithrilVirtualElement[], forceRecreation?: boolean): void;
redraw: { redraw: {
(force?: boolean): void; (force?: boolean): void;
strategy: MithrilProperty<string>; strategy: MithrilProperty<string>;
} }
route: { route: {
<T extends MithrilController>(rootElement: HTMLDocument, defaultRoute: string, routes: MithrilRoutes<T>): void; <T extends MithrilController>(rootElement: HTMLDocument, defaultRoute: string, routes: MithrilRoutes<T>): void;
<T extends MithrilController>(rootElement: Element, defaultRoute: string, routes: MithrilRoutes<T>): void; <T extends MithrilController>(rootElement: Element, defaultRoute: string, routes: MithrilRoutes<T>): void;
(element: Element, isInitialized: boolean): void; (element: Element, isInitialized: boolean): void;
(path: string, params?: any, shouldReplaceHistory?: boolean): void; (path: string, params?: any, shouldReplaceHistory?: boolean): void;
(): string; (): string;
param(key: string): string; param(key: string): string;
mode: string; mode: string;
} }
request<T>(options: MithrilXHROptions): MithrilPromise<T>; request<T>(options: MithrilXHROptions): MithrilPromise<T>;
deferred: { deferred: {
onerror(e: Error): void; onerror(e: Error): void;
<T>(): MithrilDeferred<T>; <T>(): MithrilDeferred<T>;
} }
sync<T>(promises: MithrilPromise<T>[]): MithrilPromise<T[]>; sync<T>(promises: MithrilPromise<T>[]): MithrilPromise<T[]>;
startComputation(): void; startComputation(): void;
endComputation(): void; endComputation(): void;
// For test suite // For test suite
deps: { deps: {
(mockWindow: Window): Window; (mockWindow: Window): Window;
factory: Object; factory: Object;
} }
} }
interface MithrilVirtualElement { interface MithrilVirtualElement {
key?: number; key?: number;
tag?: string; tag?: string;
attrs?: MithrilAttributes; attrs?: MithrilAttributes;
children?: any[]; children?: any[];
} }
// Configuration function for an element // Configuration function for an element
interface MithrilElementConfig { interface MithrilElementConfig {
(element: Element, isInitialized: boolean, context?: any): void; (element: Element, isInitialized: boolean, context?: any): void;
} }
// Attributes on a virtual element // Attributes on a virtual element
interface MithrilAttributes { interface MithrilAttributes {
title?: string; title?: string;
className?: string; className?: string;
class?: string; class?: string;
config?: MithrilElementConfig; config?: MithrilElementConfig;
} }
// Defines the subset of Event that Mithril needs // Defines the subset of Event that Mithril needs
interface MithrilEvent { interface MithrilEvent {
currentTarget: Element; currentTarget: Element;
} }
interface MithrilController { interface MithrilController {
(): any; onunload?(evt: Event): any;
onunload?(evt: Event): any; }
interface MithrilControllerFunction extends MithrilController {
(): any;
} }
interface MithrilView<T extends MithrilController> { interface MithrilView<T extends MithrilController> {
(ctrl: T): string|MithrilVirtualElement; (ctrl: T): string|MithrilVirtualElement;
} }
interface MithrilModule<T extends MithrilController> { interface MithrilModule<T extends MithrilController> {
controller: T; controller: MithrilControllerFunction|{ new(): T };
view: MithrilView<T>; view: MithrilView<T>;
} }
interface MithrilProperty<T> { interface MithrilProperty<T> {
(): T; (): T;
(value: T): T; (value: T): T;
toJSON(): T; toJSON(): T;
} }
interface MithrilPromiseProperty<T> extends MithrilPromise<T> { interface MithrilPromiseProperty<T> extends MithrilPromise<T> {
(): T; (): T;
(value: T): T; (value: T): T;
toJSON(): T; toJSON(): T;
} }
interface MithrilRoutes<T extends MithrilController> { interface MithrilRoutes<T extends MithrilController> {
[key: string]: MithrilModule<T>; [key: string]: MithrilModule<T>;
} }
interface MithrilDeferred<T> { interface MithrilDeferred<T> {
resolve(value?: T): void; resolve(value?: T): void;
reject(value?: any): void; reject(value?: any): void;
promise: MithrilPromise<T>; promise: MithrilPromise<T>;
} }
interface MithrilSuccessCallback<T, U> { interface MithrilSuccessCallback<T, U> {
(value: T): U; (value: T): U;
(value: T): MithrilPromise<U>; (value: T): MithrilPromise<U>;
} }
interface MithrilErrorCallback<U> { interface MithrilErrorCallback<U> {
(value: Error): U; (value: Error): U;
(value: string): U; (value: string): U;
} }
interface MithrilPromise<T> { interface MithrilPromise<T> {
(): T; (): T;
(value: T): T; (value: T): T;
then<U>(success: (value: T) => U): MithrilPromise<U>; then<U>(success: (value: T) => U): MithrilPromise<U>;
then<U>(success: (value: T) => MithrilPromise<U>): MithrilPromise<U>; then<U>(success: (value: T) => MithrilPromise<U>): MithrilPromise<U>;
then<U,V>(success: (value: T) => U, error: (value: Error) => V): MithrilPromise<U>|MithrilPromise<V>; then<U,V>(success: (value: T) => U, error: (value: Error) => V): MithrilPromise<U>|MithrilPromise<V>;
then<U,V>(success: (value: T) => MithrilPromise<U>, error: (value: Error) => V): MithrilPromise<U>|MithrilPromise<V>; then<U,V>(success: (value: T) => MithrilPromise<U>, error: (value: Error) => V): MithrilPromise<U>|MithrilPromise<V>;
} }
interface MithrilXHROptions { interface MithrilXHROptions {
method?: string; method?: string;
url: string; url: string;
user?: string; user?: string;
password?: string; password?: string;
data?: any; data?: any;
background?: boolean; background?: boolean;
unwrapSuccess?(data: any): any; unwrapSuccess?(data: any): any;
unwrapError?(data: any): any; unwrapError?(data: any): any;
serialize?(dataToSerialize: any): string; serialize?(dataToSerialize: any): string;
deserialize?(dataToDeserialize: string): any; deserialize?(dataToDeserialize: string): any;
extract?(xhr: XMLHttpRequest, options: MithrilXHROptions): string; extract?(xhr: XMLHttpRequest, options: MithrilXHROptions): string;
type?(data: Object): void; type?(data: Object): void;
config?(xhr: XMLHttpRequest, options: MithrilXHROptions): XMLHttpRequest; config?(xhr: XMLHttpRequest, options: MithrilXHROptions): XMLHttpRequest;
dataType?: string; dataType?: string;
} }
declare var Mithril: MithrilStatic; declare var Mithril: MithrilStatic;
declare var m: MithrilStatic; declare var m: MithrilStatic;
declare module 'mithril' { declare module 'mithril' {
export = m; export = m;
} }

View file

@ -607,13 +607,19 @@ var m = (function app(window, undefined) {
window[listener]() window[listener]()
} }
//config: m.route //config: m.route
else if (arguments[0].addEventListener) { else if (arguments[0].addEventListener || arguments[0].attachEvent) {
var element = arguments[0]; var element = arguments[0];
var isInitialized = arguments[1]; var isInitialized = arguments[1];
var context = arguments[2]; var context = arguments[2];
element.href = (m.route.mode !== 'pathname' ? $location.pathname : '') + modes[m.route.mode] + this.attrs.href; element.href = (m.route.mode !== 'pathname' ? $location.pathname : '') + modes[m.route.mode] + this.attrs.href;
element.removeEventListener("click", routeUnobtrusive); if (element.addEventListener) {
element.addEventListener("click", routeUnobtrusive) element.removeEventListener("click", routeUnobtrusive);
element.addEventListener("click", routeUnobtrusive)
}
else {
element.detachEvent("onclick", routeUnobtrusive);
element.attachEvent("onclick", routeUnobtrusive)
}
} }
//m.route(route, params) //m.route(route, params)
else if (type.call(arguments[0]) === STRING) { else if (type.call(arguments[0]) === STRING) {
@ -636,7 +642,10 @@ var m = (function app(window, undefined) {
}; };
redirect(modes[m.route.mode] + currentRoute) 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) { 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.ctrlKey || e.metaKey || e.which === 2) return;
if (e.preventDefault) e.preventDefault(); if (e.preventDefault) e.preventDefault();
else e.returnValue = false; 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)) : {}; 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) m.route(currentTarget[m.route.mode].slice(modes[m.route.mode].length), args)
} }
function setScroll() { function setScroll() {
@ -735,7 +745,8 @@ var m = (function app(window, undefined) {
var prop = m.prop(); var prop = m.prop();
promise.then(prop); promise.then(prop);
prop.then = function(resolve, reject) { prop.then = function(resolve, reject) {
return propify(promise.then(resolve, reject)) promise = promise.then(resolve, reject).then(prop);
return prop;
}; };
return prop return prop
} }

View file

@ -2246,6 +2246,13 @@ function testMithril(mock) {
xhr.onreadystatechange() xhr.onreadystatechange()
return xhr.$headers["Content-Type"] === undefined 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() { test(function() {
var prop = m.request({method: "POST", url: "test", initialValue: "foo"}) var prop = m.request({method: "POST", url: "test", initialValue: "foo"})
var initialValue = prop(); var initialValue = prop();