Fossil SCM

Added fossil.fetch() responseHeaders option to pass on one or more response headers to the onload() callback.

stephan 2020-05-12 13:18 fileedit-ajaxify
Commit bbb738d07dfbecb9f3f5923765fb6c1cf66fb301bf36ec4bfc3ba69782a7b46c
1 file changed +54 -17
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -40,17 +40,30 @@
4040
4141
- responseType: optional string. One of ("text", "arraybuffer",
4242
"blob", or "document") (as specified by XHR2). Default = "text".
4343
As an extension, it supports "json", which tells it that the
4444
response is expected to be text and that it should be JSON.parse()d
45
- before passing it on to the onload() callback.
45
+ before passing it on to the onload() callback. If parsing of such
46
+ an object fails, the onload callback is not called, and the
47
+ onerror() callback is passed the exception from the parsing error.
4648
4749
- urlParams: string|object. If a string, it is assumed to be a
4850
URI-encoded list of params in the form "key1=val1&key2=val2...",
4951
with NO leading '?'. If it is an object, all of its properties get
5052
converted to that form. Either way, the parameters get appended to
5153
the URL before submitting the request.
54
+
55
+ - responseHeaders: If true, the onload() callback is passed an
56
+ additional argument: a map of all of the response headers. If it's
57
+ a string value, the 2nd argument passed to onload() is instead the
58
+ value of that single header. If it's an array, it's treated as a
59
+ list of headers to return, and the 2nd argument is a map of those
60
+ header values. When a map is passed on, all of its keys are
61
+ lower-cased. When a single header is requested and that header is
62
+ set multiple times, they are (per the XHR docs) concatenated
63
+ together with ", " between them.
64
+
5265
5366
When an options object does not provide onload() or onerror()
5467
handlers of its own, this function falls back to
5568
fossil.fetch.onload() and fossil.fetch.onerror() as defaults. The
5669
default implementations route the data through the dev console and
@@ -61,11 +74,11 @@
6174
Returns this object, noting that the XHR request is asynchronous,
6275
and still in transit (or has yet to be sent) when that happens.
6376
*/
6477
window.fossil.fetch = function f(uri,opt){
6578
const F = fossil;
66
- if(!f.onerror){
79
+ if(!f.onerror){/* "static" functions... */
6780
f.onerror = function(e/*event or exception*/){
6881
console.error("Ajax error:",e);
6982
if(e instanceof Error){
7083
F.error('Exception:',e);
7184
}
@@ -83,11 +96,23 @@
8396
F.error(txt)
8497
}
8598
}
8699
};
87100
f.onload = (r)=>console.debug('ajax response:',r);
88
- }
101
+ f.parseResponseHeaders = function(h){
102
+ const rc = {};
103
+ if(!h) return rc;
104
+ const ar = h.trim().split(/[\r\n]+/);
105
+ ar.forEach(function(line) {
106
+ const parts = line.split(': ');
107
+ const header = parts.shift();
108
+ const value = parts.join(': ');
109
+ rc[header.toLowerCase()] = value;
110
+ });
111
+ return rc;
112
+ };
113
+ }/*static init*/
89114
if('/'===uri[0]) uri = uri.substr(1);
90115
if(!opt) opt = {};
91116
else if('function'===typeof opt) opt={onload:opt};
92117
if(!opt.onload) opt.onload = f.onload;
93118
if(!opt.onerror) opt.onerror = f.onerror;
@@ -118,23 +143,35 @@
118143
jsonResponse = true;
119144
x.responseType = 'text';
120145
}else{
121146
x.responseType = opt.responseType||'text';
122147
}
123
- if(opt.onload){
124
- x.onload = function(e){
125
- if(200!==this.status){
126
- if(opt.onerror) opt.onerror(e);
127
- return;
128
- }
129
- try{
130
- opt.onload((jsonResponse && this.response)
131
- ? JSON.parse(this.response) : this.response);
132
- }catch(e){
133
- if(opt.onerror) opt.onerror(e);
134
- }
135
- }
136
- }
148
+ x.onload = function(e){
149
+ if(200!==this.status){
150
+ if(opt.onerror) opt.onerror(e);
151
+ return;
152
+ }
153
+ const orh = opt.responseHeaders;
154
+ let head;
155
+ if(true===orh){
156
+ head = f.parseResponseHeaders(this.getAllResponseHeaders());
157
+ }else if('string'===typeof orh){
158
+ head = this.getResponseHeader(orh);
159
+ }else if(orh instanceof Array){
160
+ head = {};
161
+ orh.forEach((s)=>{
162
+ if('string' === typeof s) head[s.toLowerCase()] = x.getResponseHeader(s);
163
+ });
164
+ }
165
+ try{
166
+ const args = [(jsonResponse && this.response)
167
+ ? JSON.parse(this.response) : this.response];
168
+ if(head) args.push(head);
169
+ opt.onload.apply(opt, args);
170
+ }catch(e){
171
+ if(opt.onerror) opt.onerror(e);
172
+ }
173
+ };
137174
if(undefined!==payload) x.send(payload);
138175
else x.send();
139176
return this;
140177
};
141178
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -40,17 +40,30 @@
40
41 - responseType: optional string. One of ("text", "arraybuffer",
42 "blob", or "document") (as specified by XHR2). Default = "text".
43 As an extension, it supports "json", which tells it that the
44 response is expected to be text and that it should be JSON.parse()d
45 before passing it on to the onload() callback.
 
 
46
47 - urlParams: string|object. If a string, it is assumed to be a
48 URI-encoded list of params in the form "key1=val1&key2=val2...",
49 with NO leading '?'. If it is an object, all of its properties get
50 converted to that form. Either way, the parameters get appended to
51 the URL before submitting the request.
 
 
 
 
 
 
 
 
 
 
 
52
53 When an options object does not provide onload() or onerror()
54 handlers of its own, this function falls back to
55 fossil.fetch.onload() and fossil.fetch.onerror() as defaults. The
56 default implementations route the data through the dev console and
@@ -61,11 +74,11 @@
61 Returns this object, noting that the XHR request is asynchronous,
62 and still in transit (or has yet to be sent) when that happens.
63 */
64 window.fossil.fetch = function f(uri,opt){
65 const F = fossil;
66 if(!f.onerror){
67 f.onerror = function(e/*event or exception*/){
68 console.error("Ajax error:",e);
69 if(e instanceof Error){
70 F.error('Exception:',e);
71 }
@@ -83,11 +96,23 @@
83 F.error(txt)
84 }
85 }
86 };
87 f.onload = (r)=>console.debug('ajax response:',r);
88 }
 
 
 
 
 
 
 
 
 
 
 
 
89 if('/'===uri[0]) uri = uri.substr(1);
90 if(!opt) opt = {};
91 else if('function'===typeof opt) opt={onload:opt};
92 if(!opt.onload) opt.onload = f.onload;
93 if(!opt.onerror) opt.onerror = f.onerror;
@@ -118,23 +143,35 @@
118 jsonResponse = true;
119 x.responseType = 'text';
120 }else{
121 x.responseType = opt.responseType||'text';
122 }
123 if(opt.onload){
124 x.onload = function(e){
125 if(200!==this.status){
126 if(opt.onerror) opt.onerror(e);
127 return;
128 }
129 try{
130 opt.onload((jsonResponse && this.response)
131 ? JSON.parse(this.response) : this.response);
132 }catch(e){
133 if(opt.onerror) opt.onerror(e);
134 }
135 }
136 }
 
 
 
 
 
 
 
 
 
 
 
 
137 if(undefined!==payload) x.send(payload);
138 else x.send();
139 return this;
140 };
141
--- src/fossil.fetch.js
+++ src/fossil.fetch.js
@@ -40,17 +40,30 @@
40
41 - responseType: optional string. One of ("text", "arraybuffer",
42 "blob", or "document") (as specified by XHR2). Default = "text".
43 As an extension, it supports "json", which tells it that the
44 response is expected to be text and that it should be JSON.parse()d
45 before passing it on to the onload() callback. If parsing of such
46 an object fails, the onload callback is not called, and the
47 onerror() callback is passed the exception from the parsing error.
48
49 - urlParams: string|object. If a string, it is assumed to be a
50 URI-encoded list of params in the form "key1=val1&key2=val2...",
51 with NO leading '?'. If it is an object, all of its properties get
52 converted to that form. Either way, the parameters get appended to
53 the URL before submitting the request.
54
55 - responseHeaders: If true, the onload() callback is passed an
56 additional argument: a map of all of the response headers. If it's
57 a string value, the 2nd argument passed to onload() is instead the
58 value of that single header. If it's an array, it's treated as a
59 list of headers to return, and the 2nd argument is a map of those
60 header values. When a map is passed on, all of its keys are
61 lower-cased. When a single header is requested and that header is
62 set multiple times, they are (per the XHR docs) concatenated
63 together with ", " between them.
64
65
66 When an options object does not provide onload() or onerror()
67 handlers of its own, this function falls back to
68 fossil.fetch.onload() and fossil.fetch.onerror() as defaults. The
69 default implementations route the data through the dev console and
@@ -61,11 +74,11 @@
74 Returns this object, noting that the XHR request is asynchronous,
75 and still in transit (or has yet to be sent) when that happens.
76 */
77 window.fossil.fetch = function f(uri,opt){
78 const F = fossil;
79 if(!f.onerror){/* "static" functions... */
80 f.onerror = function(e/*event or exception*/){
81 console.error("Ajax error:",e);
82 if(e instanceof Error){
83 F.error('Exception:',e);
84 }
@@ -83,11 +96,23 @@
96 F.error(txt)
97 }
98 }
99 };
100 f.onload = (r)=>console.debug('ajax response:',r);
101 f.parseResponseHeaders = function(h){
102 const rc = {};
103 if(!h) return rc;
104 const ar = h.trim().split(/[\r\n]+/);
105 ar.forEach(function(line) {
106 const parts = line.split(': ');
107 const header = parts.shift();
108 const value = parts.join(': ');
109 rc[header.toLowerCase()] = value;
110 });
111 return rc;
112 };
113 }/*static init*/
114 if('/'===uri[0]) uri = uri.substr(1);
115 if(!opt) opt = {};
116 else if('function'===typeof opt) opt={onload:opt};
117 if(!opt.onload) opt.onload = f.onload;
118 if(!opt.onerror) opt.onerror = f.onerror;
@@ -118,23 +143,35 @@
143 jsonResponse = true;
144 x.responseType = 'text';
145 }else{
146 x.responseType = opt.responseType||'text';
147 }
148 x.onload = function(e){
149 if(200!==this.status){
150 if(opt.onerror) opt.onerror(e);
151 return;
152 }
153 const orh = opt.responseHeaders;
154 let head;
155 if(true===orh){
156 head = f.parseResponseHeaders(this.getAllResponseHeaders());
157 }else if('string'===typeof orh){
158 head = this.getResponseHeader(orh);
159 }else if(orh instanceof Array){
160 head = {};
161 orh.forEach((s)=>{
162 if('string' === typeof s) head[s.toLowerCase()] = x.getResponseHeader(s);
163 });
164 }
165 try{
166 const args = [(jsonResponse && this.response)
167 ? JSON.parse(this.response) : this.response];
168 if(head) args.push(head);
169 opt.onload.apply(opt, args);
170 }catch(e){
171 if(opt.onerror) opt.onerror(e);
172 }
173 };
174 if(undefined!==payload) x.send(payload);
175 else x.send();
176 return this;
177 };
178

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button