make xhr.abort reject promise chain

This commit is contained in:
Leo Horie 2014-04-29 22:19:07 -04:00
parent c1f6705a59
commit 38dba03f6d
11 changed files with 69 additions and 13 deletions

View file

@ -62,6 +62,12 @@
</div>
<div class="col(9,9,12)">
<h2 id="change-log">Change Log</h2>
<p><a href="/mithril/archive/v0.1.11">v0.1.11</a> - maintenance</p>
<h3 id="news-">News:</h3>
<ul>
<li>Added <code>m.route()</code> overload to allow reading of current route <a href="https://github.com/lhorie/mithril.js/issues/61">#61</a></li>
</ul>
<hr>
<p><a href="/mithril/archive/v0.1.10">v0.1.10</a> - maintenance</p>
<h3 id="news-">News:</h3>
<ul>

View file

@ -163,7 +163,6 @@ dashboard.controller = function() {
};
dashboard.view = function(ctrl) {
//assuming there&#39;s an element w/ id = &quot;example&quot; somewhere on the page
return m(&quot;#example&quot;, [
new autocompleter.view(ctrl.autocompleter, {onchange: m.withAttr(&quot;value&quot;, console.log)}),
]);

View file

@ -214,7 +214,7 @@ m.render(todo.view(ctrl)); // input now says &quot;Write code&quot;</code></pre>
<hr>
<p>In addition to bi-directional data binding, we can also bind parameterized functions to events:</p>
<pre><code class="lang-javascript">m(&quot;button&quot;, {onclick: ctrl.add.bind(ctrl, ctrl.description)}, &quot;Add&quot;)</code></pre>
<p>In the code above, we are simply using the native Javascript <code>Function::bind</code> method. This creates a new function with the parameter already set. In functional programming, this is called <a href="http://en.wikipedia.org/wiki/Currying"><em>currying</em></a>.</p>
<p>In the code above, we are simply using the native Javascript <code>Function::bind</code> method. This creates a new function with the parameter already set. In functional programming, this is called <a href="http://en.wikipedia.org/wiki/Partial_application"><em>partial application</em></a>.</p>
<p>The <code>ctrl.add.bind(ctrl, ctrl.description)</code> expression above returns a function that is equivalent to this code:</p>
<pre><code class="lang-javascript">onclick: function(e) {
ctrl.add(ctrl.description)
@ -262,7 +262,7 @@ m(&quot;table&quot;, [
<ul>
<li>The template is rendered as a child of the implicit <code>&lt;html&gt;</code> element of the document</li>
<li>The text input saves its value to the <code>ctrl.description</code> getter-setter we defined earlier</li>
<li><p>The button calls the <code>ctrl.add</code> method when clicked. The <code>.bind(ctrl, ctrl.description)</code> idiom is a <a href="http://en.wikipedia.org/wiki/Currying">functional curry</a>.</p>
<li><p>The button calls the <code>ctrl.add</code> method when clicked. The <code>.bind(ctrl, ctrl.description)</code> idiom is a <a href="http://en.wikipedia.org/wiki/Partial_application">partial application</a>.</p>
<p>In this example, it&#39;s only used to maintain the scope binding for the <code>this</code> parameter in the controller method, but typically it&#39;s also used to bind parameters to the function without the need to declare a wrapper anonymous function.</p>
</li>
<li>The table lists all the existing to-dos, if any.</li>
@ -409,7 +409,7 @@ this.description = function(value) {
<p>Another feature - the optional <code>m()</code> utility - allows writing terse templates in a declarative style using CSS shorthands, similar to popular HTML preprocessors from server-side MVC frameworks.</p>
<p>And because Mithril views are javascript, the developer has full freedom to abstract common patterns - from bidirectional binding helpers to full blown components - using standard javascript refactoring techniques.</p>
<p>Mithril templates are also more collision-proof than other component systems since there&#39;s no way to pollute the HTML tag namespace by defining ad-hoc tag names.</p>
<p>A more intellectually interesting aspect of the framework is that event handling is encouraged to be done via functional composition (i.e. by using tools like <a href="mithril.withAttr.html"><code>m.withAttr</code></a>, <a href="mithril.prop.html"><code>m.prop</code></a> and the native <code>.bind()</code> method for currying).</p>
<p>A more intellectually interesting aspect of the framework is that event handling is encouraged to be done via functional composition (i.e. by using tools like <a href="mithril.withAttr.html"><code>m.withAttr</code></a>, <a href="mithril.prop.html"><code>m.prop</code></a> and the native <code>.bind()</code> method for partial application).</p>
<p>If you&#39;ve been interested in learning or using Functional Programming in the real world, Mithril provides very pragmatic opportunities to get into it.</p>
<hr>
<h2 id="learn-more">Learn More</h2>

View file

@ -398,6 +398,9 @@ Mithril = m = new function app(window) {
xhr.open(options.method, options.url, true, options.user, options.password)
xhr.onload = typeof options.onload == "function" ? options.onload : function() {}
xhr.onerror = typeof options.onerror == "function" ? options.onerror : function() {}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 0) xhr.onerror({type: "error", target: xhr})
}
if (typeof options.config == "function") options.config(xhr, options)
xhr.send(options.data)
return xhr
@ -1012,6 +1015,24 @@ function testMithril(mock) {
var paramValueAfter = m.route.param("a1")
return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined
})
test(function() {
//https://github.com/lhorie/mithril.js/issues/61
mock.performance.$elapse(50)
mock.location.search = "?"
var module = {controller: function() {}, view: function() {return m.route.param("a1")}}
var root = mock.document.createElement("div")
m.route.mode = "search"
m.route(root, "/test7/foo", {
"/": module,
"/test7/:a1": module
})
var routeValueBefore = m.route()
m.route("/")
var routeValueAfter = m.route()
return routeValueBefore === "/test7/foo" && routeValueAfter === "/"
})
//m.prop
test(function() {

View file

@ -398,6 +398,9 @@ Mithril = m = new function app(window) {
xhr.open(options.method, options.url, true, options.user, options.password)
xhr.onload = typeof options.onload == "function" ? options.onload : function() {}
xhr.onerror = typeof options.onerror == "function" ? options.onerror : function() {}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 0) xhr.onerror({type: "error", target: xhr})
}
if (typeof options.config == "function") options.config(xhr, options)
xhr.send(options.data)
return xhr

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -233,6 +233,15 @@ m.request({method: &quot;POST&quot;, url: &quot;/foo&quot;, extract: extract});<
m.request({method: &quot;POST&quot;, url: &quot;/foo&quot;, config: xhrConfig});</code></pre>
<hr>
<h3 id="aborting-a-request">Aborting a request</h3>
<p>The <code>config</code> option can also be used to retrieve the <code>XMLHttpRequest</code> instance for aborting the request. This idiom can also be used to attach <code>onprogress</code> event handlers.</p>
<pre><code class="lang-javascript">var transport = m.prop();
m.request({method: &quot;POST&quot;, url: &quot;/foo&quot;, config: transport});
//the `transport` getter-setter contains an instance of XMLHttpRequest
transport().abort();</code></pre>
<hr>
<h3 id="signature">Signature</h3>
<p><a href="how-to-read-signatures.html">How to read signatures</a></p>
<pre><code class="lang-clike">Promise request(XHROptions options)
@ -277,7 +286,7 @@ where:
<p>Data to be sent. It&#39;s automatically placed in the appropriate section of the request with the appropriate serialization based on <code>method</code></p>
</li>
<li><p><strong>any unwrapSuccess(any data)</strong> (optional)</p>
<p>A preprocessor function to extract the data from a success response in case the response contains metadata wrapping the data.</p>
<p>A preprocessor function to unwrap the data from a success response in case the response contains metadata wrapping the data.</p>
<p>The default value (if this parameter is falsy) is the identity function <code>function(value) {return value}</code></p>
<p>For example, if the response is <code>{data: [{name: &quot;John&quot;}, {name: &quot;Mary&quot;}]}</code> and the unwrap function is <code>function(response) {return response.data}</code>, then the response will be considered to be <code>[{name: &quot;John&quot;}, {name: &quot;Mary&quot;}]</code> when processing the <code>type</code> parameter</p>
<ul>
@ -290,7 +299,7 @@ where:
</ul>
</li>
<li><p><strong>any unwrapError(any data)</strong> (optional)</p>
<p>A preprocessor function to extract the data from an error response in case the response contains metadata wrapping the data.</p>
<p>A preprocessor function to unwrap the data from an error response in case the response contains metadata wrapping the data.</p>
<p>The default value (if this parameter is falsy) is the identity function <code>function(value) {return value}</code></p>
<ul>
<li><p><strong>Object<any> | Array<any> data</strong></p>
@ -325,7 +334,7 @@ where:
</li>
<li><p><strong>any extract(XMLHttpRequest xhr, XHROptions options)</strong> (optional)</p>
<p>Method to use to extract the data from the raw XMLHttpRequest. This is useful when the relevant data is either in a response header or the status field.</p>
<p>If this parameter is falsy, the default value is <code>function(xhr, options) {return xhr.responseText}</code>.</p>
<p>If this parameter is falsy, the default value is a function that returns <code>xhr.responseText</code>.</p>
</li>
<li><p><strong>void type(Object<any> data)</strong> (optional)</p>
<p>The response object (or the child items if this object is an Array) will be passed as a parameter to the class constructor defined by <code>type</code></p>