Skip to content
This repository was archived by the owner on Mar 13, 2018. It is now read-only.

Commit 76bde89

Browse files
committed
Add progress and loading attributes; includes docs, demo, and test.
1 parent 5e0d9f8 commit 76bde89

File tree

4 files changed

+217
-4
lines changed

4 files changed

+217
-4
lines changed

core-ajax.html

+53-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
@homepage github.io
3333
-->
3434
<link rel="import" href="core-xhr.html">
35-
<polymer-element name="core-ajax" hidden attributes="url handleAs auto params response error method headers body contentType withCredentials">
35+
<polymer-element name="core-ajax" hidden attributes="url handleAs auto params response error method headers body contentType withCredentials progress loading">
3636
<script>
3737

3838
Polymer('core-ajax', {
@@ -106,7 +106,7 @@
106106
params: '',
107107

108108
/**
109-
* The response for the most recently made request, or null if it hasn't
109+
* The response for the current request, or null if it hasn't
110110
* completed yet or the request resulted in error.
111111
*
112112
* @attribute response
@@ -116,7 +116,7 @@
116116
response: null,
117117

118118
/**
119-
* The error for the most recently made request, or null if it hasn't
119+
* The error for the current request, or null if it hasn't
120120
* completed yet or the request resulted in success.
121121
*
122122
* @attribute error
@@ -125,6 +125,24 @@
125125
*/
126126
error: null,
127127

128+
/**
129+
* Whether the current request is currently loading.
130+
*
131+
* @attribute loading
132+
* @type boolean
133+
* @default false
134+
*/
135+
loading: false,
136+
137+
/**
138+
* The progress of the current request.
139+
*
140+
* @attribute progress
141+
* @type {loaded: number, total: number, lengthComputable: boolean}
142+
* @default {}
143+
*/
144+
progress: {},
145+
128146
/**
129147
* The HTTP method to use such as 'GET', 'POST', 'PUT', or 'DELETE'.
130148
* Default is 'GET'.
@@ -233,7 +251,22 @@
233251
this.fire('core-error', {response: response, xhr: xhr});
234252
},
235253

254+
processProgress: function(progress, xhr) {
255+
if (xhr !== this.activeRequest) {
256+
return;
257+
}
258+
var progressProxy = {
259+
lengthComputable: progress.lengthComputable,
260+
loaded: progress.loaded,
261+
total: progress.total
262+
}
263+
this.progress = progressProxy;
264+
},
265+
236266
complete: function(xhr) {
267+
if (xhr === this.activeRequest) {
268+
this.loading = false;
269+
}
237270
this.fire('core-complete', {response: xhr.status, xhr: xhr});
238271
},
239272

@@ -334,8 +367,24 @@
334367
args.url = this.url;
335368
args.method = this.method;
336369

337-
this.response = this.error = null;
370+
this.response = this.error = this.progress = null;
338371
this.activeRequest = args.url && this.xhr.request(args);
372+
if (this.activeRequest) {
373+
this.loading = true;
374+
var activeRequest = this.activeRequest;
375+
// IE < 10 doesn't support progress events.
376+
if ('onprogress' in activeRequest) {
377+
this.activeRequest.addEventListener(
378+
'progress',
379+
function(progress) {
380+
this.processProgress(progress, activeRequest);
381+
}.bind(this), false);
382+
} else {
383+
this.progress = {
384+
lengthComputable: false,
385+
}
386+
}
387+
}
339388
return this.activeRequest;
340389
}
341390

demo-progress.html

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="../platform/platform.js" debug></script>
5+
<meta charset="utf-8">
6+
<title>Race condition</title>
7+
</head>
8+
<body>
9+
<link rel="import" href="core-ajax.html">
10+
<link rel="import" href="../paper-progress/paper-progress.html">
11+
<polymer-element name="progress-test">
12+
<template>
13+
<core-ajax
14+
id='ajax' auto
15+
url="http://httpbin.org/drip"
16+
params="{{ {numbytes: numbytes, duration:5} }}"
17+
response="{{response}}"
18+
progress="{{progress}}"
19+
loading="{{loading}}"
20+
></core-ajax>
21+
22+
<!--
23+
Ordinarily you'd gate on progress.lengthComputable, but we know the
24+
length in this case (and httpbin sadly doesn't return a
25+
Content-Length header for this requesthere).
26+
-->
27+
<div>
28+
<button on-click='{{restart}}'>Restart</button>
29+
<template if='{{loading}}'>
30+
Loading...
31+
</template>
32+
<template if='{{!loading}}'>
33+
Loaded!
34+
</template>
35+
</div>
36+
<template if='{{loading && progress.loaded}}'>
37+
<paper-progress
38+
value="{{progress.loaded}}"
39+
min="0"
40+
max="{{numbytes}}">
41+
</paper-progress><br>
42+
</template>
43+
</template>
44+
<script>
45+
Polymer('progress-test', {
46+
loading: true,
47+
i: 0,
48+
numbytes: 1000,
49+
pretty: function(i) {
50+
return JSON.stringify(i, null, 2);
51+
},
52+
restart: function() {
53+
this.$.ajax.abort();
54+
this.$.ajax.go();
55+
}
56+
});
57+
</script>
58+
59+
</polymer-element>
60+
61+
<progress-test></progress-test>
62+
</body>
63+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<!doctype html>
2+
<!--
3+
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5+
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6+
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7+
Code distributed by Google as part of the polymer project is also
8+
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9+
-->
10+
<html>
11+
<head>
12+
<title>core-ajax-response-and-error</title>
13+
14+
<script src="../../../platform/platform.js"></script>
15+
<script src="../../../polymer-test-tools/chai/chai.js"></script>
16+
<script src="../../../polymer-test-tools/htmltest.js"></script>
17+
18+
<link rel="import" href="../../core-ajax.html">
19+
20+
</head>
21+
<body>
22+
23+
<polymer-element name="race-condition">
24+
<template>
25+
<!-- TODO: change this from /headers to /drip if we can get httpbin to
26+
send a Content-Length with their /drip response. -->
27+
<core-ajax
28+
auto url="http://httpbin.org/headers"
29+
params="{{ {numbytes: numbytes, duration:1} }}"
30+
loading="{{loading}}" progress="{{progress}}"
31+
on-core-response='{{responseReceived}}'></core-ajax>
32+
</template>
33+
<script>
34+
Polymer({
35+
numbytes: 1000,
36+
loading: null,
37+
loadingWasTrue: false,
38+
loadingFinished: false,
39+
previousLoaded: null,
40+
domReady: function() {
41+
// This will fail the test if it neither passes nor fails in time.
42+
this.finalTimeout = setTimeout(function() {
43+
chai.assert.fail('', '', 'Test timed out.');
44+
}, 3000);
45+
},
46+
loadingChanged: function() {
47+
this.assertConsistent();
48+
},
49+
progressChanged: function() {
50+
this.assertConsistent();
51+
},
52+
responseReceived: function() {
53+
// Shortly after the response is received we should settle into
54+
// the final consistent state for the element.
55+
setTimeout(function() {
56+
chai.assert.equal(this.loading, false);
57+
chai.assert.equal(this.loadingWasTrue, true);
58+
if (this.progress && this.progress.lengthComputable) {
59+
chai.assert.equal(this.progress.total, this.progress.loaded);
60+
}
61+
this.assertConsistent();
62+
clearTimeout(this.finalTimeout);
63+
done();
64+
}.bind(this), 100);
65+
},
66+
assertConsistent: function() {
67+
debugger;
68+
if (this.progress && this.progress.lengthComputable) {
69+
chai.assert.isNumber(this.progress.total);
70+
chai.assert.isNumber(this.progress.loaded);
71+
chai.assert(this.progress.loaded >= 0,
72+
'Bytes loaded should not be negative.');
73+
chai.assert(this.progress.loaded <= this.progress.total,
74+
'Bytes loaded should be less than or equal the total.');
75+
if (this.previousLoaded !== null) {
76+
chai.assert(this.progress.loaded >= this.previousLoaded,
77+
'Bytes loaded should increase monotonically.');
78+
}
79+
this.previousLoaded = this.progress.loaded;
80+
console.log(this.progress.loaded + ' of ' + this.progress.total);
81+
}
82+
if (this.loading === true) {
83+
this.loadingWasTrue = true;
84+
}
85+
if (this.loadingWasTrue && this.loading === false) {
86+
this.loadingFinished = true;
87+
}
88+
if (this.loadingFinished) {
89+
chai.assert.equal(
90+
this.loading, false,
91+
'Once loaded, the request should stay that way');
92+
}
93+
}
94+
});
95+
</script>
96+
</polymer-element>
97+
98+
<race-condition></race-condition>
99+
</body>
100+
</html>

tests/js/htmltests.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
htmlSuite('core-ajax', function() {
22
htmlTest('html/core-ajax.html');
33
htmlTest('html/core-ajax-response-and-error.html');
4+
htmlTest('html/core-ajax-progress-and-loading.html');
45
});

0 commit comments

Comments
 (0)