| | @@ -10,22 +10,22 @@ |
| 10 | 10 | acts as namespace for this framework. |
| 11 | 11 | |
| 12 | 12 | Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) |
| 13 | 13 | |
| 14 | 14 | License: Public Domain |
| 15 | | - |
| 16 | | - This framework is directly derived from code originally found in |
| 17 | | - http://code.google.com/p/jsonmessage, and later in |
| 18 | | - http://whiki.wanderinghorse.net, where it contained quite a bit |
| 19 | | - of application-specific logic. It was eventually (the 3rd time i |
| 20 | | - needed it) split off into its own library to simplify inclusion |
| 15 | + |
| 16 | + This framework is directly derived from code originally found in |
| 17 | + http://code.google.com/p/jsonmessage, and later in |
| 18 | + http://whiki.wanderinghorse.net, where it contained quite a bit |
| 19 | + of application-specific logic. It was eventually (the 3rd time i |
| 20 | + needed it) split off into its own library to simplify inclusion |
| 21 | 21 | into my many mini-projects. |
| 22 | 22 | */ |
| 23 | 23 | |
| 24 | 24 | |
| 25 | 25 | /** |
| 26 | | - The WhAjaj function is primarily a namespace, and not intended |
| 26 | + The WhAjaj function is primarily a namespace, and not intended |
| 27 | 27 | to called or instantiated via the 'new' operator. |
| 28 | 28 | */ |
| 29 | 29 | function WhAjaj() |
| 30 | 30 | { |
| 31 | 31 | } |
| | @@ -36,11 +36,11 @@ |
| 36 | 36 | return (new Date()).getTime(); |
| 37 | 37 | }; |
| 38 | 38 | |
| 39 | 39 | /** Returns a Unix Epoch timestamp (in seconds) in integer format. |
| 40 | 40 | |
| 41 | | - Reminder to self: (1.1 %1.2) evaluates to a floating-point value |
| 41 | + Reminder to self: (1.1 %1.2) evaluates to a floating-point value |
| 42 | 42 | in JS, and thus this implementation is less than optimal. |
| 43 | 43 | */ |
| 44 | 44 | WhAjaj.unixTimestamp = function() |
| 45 | 45 | { |
| 46 | 46 | var ts = (new Date()).getTime(); |
| | @@ -88,22 +88,22 @@ |
| 88 | 88 | }; |
| 89 | 89 | |
| 90 | 90 | /** |
| 91 | 91 | Parses window.location.search-style string into an object |
| 92 | 92 | containing key/value pairs of URL arguments (already urldecoded). |
| 93 | | - |
| 94 | | - If the str argument is not passed (arguments.length==0) then |
| 95 | | - window.location.search.substring(1) is used by default. If |
| 93 | + |
| 94 | + If the str argument is not passed (arguments.length==0) then |
| 95 | + window.location.search.substring(1) is used by default. If |
| 96 | 96 | neither str is passed in nor window exists then false is returned. |
| 97 | 97 | |
| 98 | 98 | On success it returns an Object containing the key/value pairs |
| 99 | 99 | parsed from the string. Keys which have no value are treated |
| 100 | 100 | has having the boolean true value. |
| 101 | | - |
| 101 | + |
| 102 | 102 | FIXME: for keys in the form "name[]", build an array of results, |
| 103 | 103 | like PHP does. |
| 104 | | - |
| 104 | + |
| 105 | 105 | */ |
| 106 | 106 | WhAjaj.processUrlArgs = function(str) { |
| 107 | 107 | if( 0 === arguments.length ) { |
| 108 | 108 | if( ('undefined' === typeof window) || |
| 109 | 109 | !window.location || |
| | @@ -127,11 +127,11 @@ |
| 127 | 127 | /** |
| 128 | 128 | A simple wrapper around JSON.stringify(), using my own personal |
| 129 | 129 | preferred values for the 2nd and 3rd parameters. To globally |
| 130 | 130 | set its indentation level, assign WhAjaj.stringify.indent to |
| 131 | 131 | an integer value (0 for no intendation). |
| 132 | | - |
| 132 | + |
| 133 | 133 | This function is intended only for human-readable output, not |
| 134 | 134 | generic over-the-wire JSON output (where JSON.stringify(val) will |
| 135 | 135 | produce smaller results). |
| 136 | 136 | */ |
| 137 | 137 | WhAjaj.stringify = function(val) { |
| | @@ -138,34 +138,34 @@ |
| 138 | 138 | if( ! arguments.callee.indent ) arguments.callee.indent = 4; |
| 139 | 139 | return JSON.stringify(val,0,arguments.callee.indent); |
| 140 | 140 | }; |
| 141 | 141 | |
| 142 | 142 | /** |
| 143 | | - Each instance of this class holds state information for making |
| 144 | | - AJAJ requests to a back-end system. While clients may use one |
| 143 | + Each instance of this class holds state information for making |
| 144 | + AJAJ requests to a back-end system. While clients may use one |
| 145 | 145 | "requester" object per connection attempt, for connections to the |
| 146 | | - same back-end, using an instance configured for that back-end |
| 147 | | - can simplify usage. This class is designed so that the actual |
| 148 | | - connection-related details (i.e. _how_ it connects to the |
| 149 | | - back-end) may be re-implemented to use a client's preferred |
| 146 | + same back-end, using an instance configured for that back-end |
| 147 | + can simplify usage. This class is designed so that the actual |
| 148 | + connection-related details (i.e. _how_ it connects to the |
| 149 | + back-end) may be re-implemented to use a client's preferred |
| 150 | 150 | connection mechanism (e.g. jQuery). |
| 151 | | - |
| 152 | | - The optional opt paramater may be an object with any (or all) of |
| 153 | | - the properties documented for WhAjaj.Connector.options.ajax. |
| 154 | | - Properties set here (or later via modification of the "options" |
| 155 | | - property of this object) will be used in calls to |
| 151 | + |
| 152 | + The optional opt paramater may be an object with any (or all) of |
| 153 | + the properties documented for WhAjaj.Connector.options.ajax. |
| 154 | + Properties set here (or later via modification of the "options" |
| 155 | + property of this object) will be used in calls to |
| 156 | 156 | WhAjaj.Connector.sendRequest(), and these override (normally) any |
| 157 | | - options set in WhAjaj.Connector.options.ajax. Note that |
| 158 | | - WhAjaj.Connector.sendRequest() _also_ takes an options object, |
| 159 | | - and ones passed there will override, for purposes of that one |
| 160 | | - request, any options passed in here or defined in |
| 157 | + options set in WhAjaj.Connector.options.ajax. Note that |
| 158 | + WhAjaj.Connector.sendRequest() _also_ takes an options object, |
| 159 | + and ones passed there will override, for purposes of that one |
| 160 | + request, any options passed in here or defined in |
| 161 | 161 | WhAjaj.Connector.options.ajax. See WhAjaj.Connector.options.ajax |
| 162 | 162 | and WhAjaj.Connector.prototype.sendRequest() for more details |
| 163 | 163 | about the precedence of options. |
| 164 | | - |
| 164 | + |
| 165 | 165 | Sample usage: |
| 166 | | - |
| 166 | + |
| 167 | 167 | @code |
| 168 | 168 | // Set up common connection-level options: |
| 169 | 169 | var cgi = new WhAjaj.Connector({ |
| 170 | 170 | url: '/cgi-bin/my.cgi', |
| 171 | 171 | timeout:10000, |
| | @@ -185,25 +185,25 @@ |
| 185 | 185 | @endcode |
| 186 | 186 | |
| 187 | 187 | For common request types, clients can add functions to this |
| 188 | 188 | object which act as wrappers for backend-specific functionality. As |
| 189 | 189 | a simple example: |
| 190 | | - |
| 190 | + |
| 191 | 191 | @code |
| 192 | 192 | cgi.login = function(name,pw,ajajOpt) { |
| 193 | 193 | this.sendRequest( |
| 194 | 194 | {command:"json/login", |
| 195 | 195 | name:name, |
| 196 | 196 | password:pw |
| 197 | 197 | }, ajajOpt ); |
| 198 | 198 | }; |
| 199 | 199 | @endcode |
| 200 | | - |
| 200 | + |
| 201 | 201 | TODOs: |
| 202 | | - |
| 202 | + |
| 203 | 203 | - Caching of page-load requests, with a configurable lifetime. |
| 204 | | - |
| 204 | + |
| 205 | 205 | - Use-cases like the above login() function are a tiny bit |
| 206 | 206 | problematic to implement when each request has a different URL |
| 207 | 207 | path (i know this from the whiki and fossil implementations). |
| 208 | 208 | This is partly a side-effect of design descisions made back in |
| 209 | 209 | the very first days of this code's life. i need to go through |
| | @@ -230,42 +230,42 @@ |
| 230 | 230 | A (meaningless) prefix to apply to WhAjaj.Connector-generated |
| 231 | 231 | request IDs. |
| 232 | 232 | */ |
| 233 | 233 | requestIdPrefix:'WhAjaj.Connector-', |
| 234 | 234 | /** |
| 235 | | - Default options for WhAjaj.Connector.sendRequest() connection |
| 236 | | - parameters. This object holds only connection-related |
| 237 | | - options and callbacks (all optional), and not options |
| 238 | | - related to the required JSON structure of any given request. |
| 239 | | - i.e. the page name used in a get-page request are not set |
| 235 | + Default options for WhAjaj.Connector.sendRequest() connection |
| 236 | + parameters. This object holds only connection-related |
| 237 | + options and callbacks (all optional), and not options |
| 238 | + related to the required JSON structure of any given request. |
| 239 | + i.e. the page name used in a get-page request are not set |
| 240 | 240 | here but are specified as part of the request object. |
| 241 | 241 | |
| 242 | | - These connection options are a "normalized form" of options |
| 243 | | - often found in various AJAX libraries like jQuery, |
| 244 | | - Prototype, dojo, etc. This approach allows us to swap out |
| 245 | | - the real connection-related parts by writing a simple proxy |
| 246 | | - which transforms our "normalized" form to the |
| 247 | | - backend-specific form. For examples, see the various |
| 242 | + These connection options are a "normalized form" of options |
| 243 | + often found in various AJAX libraries like jQuery, |
| 244 | + Prototype, dojo, etc. This approach allows us to swap out |
| 245 | + the real connection-related parts by writing a simple proxy |
| 246 | + which transforms our "normalized" form to the |
| 247 | + backend-specific form. For examples, see the various |
| 248 | 248 | implementations stored in WhAjaj.Connector.sendImpls. |
| 249 | 249 | |
| 250 | | - The following callback options are, in practice, almost |
| 250 | + The following callback options are, in practice, almost |
| 251 | 251 | always set globally to some app-wide defaults: |
| 252 | 252 | |
| 253 | 253 | - onError() to report errors using a common mechanism. |
| 254 | 254 | - beforeSend() to start a visual activity notification |
| 255 | 255 | - afterSend() to disable the visual activity notification |
| 256 | 256 | |
| 257 | | - However, be aware that if any given WhAjaj.Connector instance is |
| 258 | | - given its own before/afterSend callback then those will |
| 257 | + However, be aware that if any given WhAjaj.Connector instance is |
| 258 | + given its own before/afterSend callback then those will |
| 259 | 259 | override these. Mixing shared/global and per-instance |
| 260 | 260 | callbacks can potentially lead to confusing results if, e.g., |
| 261 | 261 | the beforeSend() and afterSend() functions have side-effects |
| 262 | 262 | but are not used with their proper before/after partner. |
| 263 | | - |
| 264 | | - TODO: rename this to 'ajaj' (the name is historical). The |
| 265 | | - problem with renaming it is is that the word 'ajax' is |
| 266 | | - pretty prevelant in the source tree, so i can't globally |
| 263 | + |
| 264 | + TODO: rename this to 'ajaj' (the name is historical). The |
| 265 | + problem with renaming it is is that the word 'ajax' is |
| 266 | + pretty prevelant in the source tree, so i can't globally |
| 267 | 267 | swap it out. |
| 268 | 268 | */ |
| 269 | 269 | ajax: { |
| 270 | 270 | /** |
| 271 | 271 | URL of the back-end server/CGI. |
| | @@ -273,48 +273,48 @@ |
| 273 | 273 | url: '/some/path', |
| 274 | 274 | |
| 275 | 275 | /** |
| 276 | 276 | Connection method. Some connection-related functions might |
| 277 | 277 | override any client-defined setting. |
| 278 | | - |
| 279 | | - Must be one of 'GET' or 'POST'. For custom connection |
| 280 | | - implementation, it may optionally be some |
| 278 | + |
| 279 | + Must be one of 'GET' or 'POST'. For custom connection |
| 280 | + implementation, it may optionally be some |
| 281 | 281 | implementation-specified value. |
| 282 | 282 | |
| 283 | 283 | Normally the API can derive this value automatically - if the |
| 284 | 284 | request uses JSON data it is POSTed, else it is GETted. |
| 285 | 285 | */ |
| 286 | 286 | method:'GET', |
| 287 | 287 | |
| 288 | 288 | /** |
| 289 | | - A hint whether to run the operation asynchronously or |
| 290 | | - not. Not all concrete WhAjaj.Connector.sendImpl() |
| 291 | | - implementations can support this. Interestingly, at |
| 292 | | - least one popular AJAX toolkit does not document |
| 293 | | - supporting _synchronous_ AJAX operations. All common |
| 294 | | - browser-side implementations support async operation, but |
| 289 | + A hint whether to run the operation asynchronously or |
| 290 | + not. Not all concrete WhAjaj.Connector.sendImpl() |
| 291 | + implementations can support this. Interestingly, at |
| 292 | + least one popular AJAX toolkit does not document |
| 293 | + supporting _synchronous_ AJAX operations. All common |
| 294 | + browser-side implementations support async operation, but |
| 295 | 295 | non-browser implementations might not. |
| 296 | 296 | */ |
| 297 | 297 | asynchronous:true, |
| 298 | 298 | |
| 299 | 299 | /** |
| 300 | | - A HTTP authentication login name for the AJAX |
| 301 | | - connection. Not all concrete WhAjaj.Connector.sendImpl() |
| 300 | + A HTTP authentication login name for the AJAX |
| 301 | + connection. Not all concrete WhAjaj.Connector.sendImpl() |
| 302 | 302 | implementations can support this. |
| 303 | 303 | */ |
| 304 | 304 | loginName:undefined, |
| 305 | 305 | |
| 306 | 306 | /** |
| 307 | | - An HTTP authentication login password for the AJAJ |
| 308 | | - connection. Not all concrete WhAjaj.Connector.sendImpl() |
| 307 | + An HTTP authentication login password for the AJAJ |
| 308 | + connection. Not all concrete WhAjaj.Connector.sendImpl() |
| 309 | 309 | implementations can support this. |
| 310 | 310 | */ |
| 311 | 311 | loginPassword:undefined, |
| 312 | 312 | |
| 313 | 313 | /** |
| 314 | | - A connection timeout, in milliseconds, for establishing |
| 315 | | - an AJAJ connection. Not all concrete |
| 314 | + A connection timeout, in milliseconds, for establishing |
| 315 | + an AJAJ connection. Not all concrete |
| 316 | 316 | WhAjaj.Connector.sendImpl() implementations can support this. |
| 317 | 317 | */ |
| 318 | 318 | timeout:10000, |
| 319 | 319 | |
| 320 | 320 | /** |
| | @@ -328,11 +328,11 @@ |
| 328 | 328 | is the same as the 'this' object for the context of the |
| 329 | 329 | callback, but is provided because the instance-level |
| 330 | 330 | callbacks (set in (WhAjaj.Connector instance).callbacks, |
| 331 | 331 | require it in some cases (because their 'this' is |
| 332 | 332 | different!). |
| 333 | | - |
| 333 | + |
| 334 | 334 | Note that the response might contain error information |
| 335 | 335 | which comes from the back-end. The difference between |
| 336 | 336 | this error info and the info passed to the onError() |
| 337 | 337 | callback is that this data indicates an |
| 338 | 338 | application-level error, whereas onError() is used to |
| | @@ -342,21 +342,21 @@ |
| 342 | 342 | connection error). |
| 343 | 343 | */ |
| 344 | 344 | onResponse: function(response, request, opt){}, |
| 345 | 345 | |
| 346 | 346 | /** |
| 347 | | - If an AJAX request fails to establish a connection or it |
| 348 | | - receives non-JSON data from the back-end, this function |
| 349 | | - is called (e.g. timeout error or host name not |
| 347 | + If an AJAX request fails to establish a connection or it |
| 348 | + receives non-JSON data from the back-end, this function |
| 349 | + is called (e.g. timeout error or host name not |
| 350 | 350 | resolvable). It is passed the originating request and the |
| 351 | | - "normalized" connection parameters used for that |
| 352 | | - request. The connectOpt object "should" (or "might") |
| 353 | | - have an "errorMessage" property which describes the |
| 351 | + "normalized" connection parameters used for that |
| 352 | + request. The connectOpt object "should" (or "might") |
| 353 | + have an "errorMessage" property which describes the |
| 354 | 354 | nature of the problem. |
| 355 | | - |
| 356 | | - Clients will almost always want to replace the default |
| 357 | | - implementation with something which integrates into |
| 355 | + |
| 356 | + Clients will almost always want to replace the default |
| 357 | + implementation with something which integrates into |
| 358 | 358 | their application. |
| 359 | 359 | */ |
| 360 | 360 | onError: function(request, connectOpt) |
| 361 | 361 | { |
| 362 | 362 | alert('AJAJ request failed:\n' |
| | @@ -364,60 +364,60 @@ |
| 364 | 364 | +JSON.stringify(connectOpt,0,4) |
| 365 | 365 | ); |
| 366 | 366 | }, |
| 367 | 367 | |
| 368 | 368 | /** |
| 369 | | - Called before each connection attempt is made. Clients |
| 369 | + Called before each connection attempt is made. Clients |
| 370 | 370 | can use this to, e.g., enable a visual "network activity |
| 371 | | - notification" for the user. It is passed the original |
| 372 | | - request object and the normalized connection parameters |
| 373 | | - for the request. If this function changes opt, those |
| 374 | | - changes _are_ applied to the subsequent request. If this |
| 375 | | - function throws, neither the onError() nor afterSend() |
| 376 | | - callbacks are triggered and WhAjaj.Connector.sendImpl() |
| 371 | + notification" for the user. It is passed the original |
| 372 | + request object and the normalized connection parameters |
| 373 | + for the request. If this function changes opt, those |
| 374 | + changes _are_ applied to the subsequent request. If this |
| 375 | + function throws, neither the onError() nor afterSend() |
| 376 | + callbacks are triggered and WhAjaj.Connector.sendImpl() |
| 377 | 377 | propagates the exception back to the caller. |
| 378 | 378 | */ |
| 379 | 379 | beforeSend: function(request,opt){}, |
| 380 | 380 | |
| 381 | 381 | /** |
| 382 | | - Called after an AJAJ connection attempt completes, |
| 383 | | - regardless of success or failure. Passed the same |
| 384 | | - parameters as beforeSend() (see that function for |
| 382 | + Called after an AJAJ connection attempt completes, |
| 383 | + regardless of success or failure. Passed the same |
| 384 | + parameters as beforeSend() (see that function for |
| 385 | 385 | details). |
| 386 | | - |
| 387 | | - Here's an example of setting up a visual notification on |
| 388 | | - ajax operations using jQuery (but it's also easy to do |
| 386 | + |
| 387 | + Here's an example of setting up a visual notification on |
| 388 | + ajax operations using jQuery (but it's also easy to do |
| 389 | 389 | without jQuery as well): |
| 390 | | - |
| 390 | + |
| 391 | 391 | @code |
| 392 | 392 | function startAjaxNotif(req,opt) { |
| 393 | 393 | var me = arguments.callee; |
| 394 | 394 | var c = ++me.ajaxCount; |
| 395 | 395 | me.element.text( c + " pending AJAX operation(s)..." ); |
| 396 | 396 | if( 1 == c ) me.element.stop().fadeIn(); |
| 397 | 397 | } |
| 398 | 398 | startAjaxNotif.ajaxCount = 0. |
| 399 | 399 | startAjaxNotif.element = jQuery('#whikiAjaxNotification'); |
| 400 | | - |
| 400 | + |
| 401 | 401 | function endAjaxNotif() { |
| 402 | 402 | var c = --startAjaxNotif.ajaxCount; |
| 403 | 403 | startAjaxNotif.element.text( c+" pending AJAX operation(s)..." ); |
| 404 | 404 | if( 0 == c ) startAjaxNotif.element.stop().fadeOut(); |
| 405 | 405 | } |
| 406 | 406 | @endcode |
| 407 | 407 | |
| 408 | | - Set the beforeSend/afterSend properties to those |
| 409 | | - functions to enable the notifications by default. |
| 408 | + Set the beforeSend/afterSend properties to those |
| 409 | + functions to enable the notifications by default. |
| 410 | 410 | */ |
| 411 | 411 | afterSend: function(request,opt){}, |
| 412 | 412 | |
| 413 | 413 | /** |
| 414 | 414 | If jsonp is a string then the WhAjaj-internal response |
| 415 | 415 | handling code ASSUMES that the response contains a JSONP-style |
| 416 | 416 | construct and eval()s it after afterSend() but before onResponse(). |
| 417 | 417 | In this case, onResponse() will get a string value for the response |
| 418 | | - instead of a response object parsed from JSON. |
| 418 | + instead of a response object parsed from JSON. |
| 419 | 419 | */ |
| 420 | 420 | jsonp:undefined, |
| 421 | 421 | /** |
| 422 | 422 | Don't use yet. Planned future option. |
| 423 | 423 | */ |
| | @@ -468,25 +468,25 @@ |
| 468 | 468 | else v = WhAjaj.Connector.options.ajax[key]; |
| 469 | 469 | return v; |
| 470 | 470 | }; |
| 471 | 471 | |
| 472 | 472 | /** |
| 473 | | - Returns a unique string on each call containing a generic |
| 474 | | - reandom request identifier string. This is not used by the core |
| 475 | | - API but can be used by client code to generate unique IDs for |
| 473 | + Returns a unique string on each call containing a generic |
| 474 | + reandom request identifier string. This is not used by the core |
| 475 | + API but can be used by client code to generate unique IDs for |
| 476 | 476 | each request (if needed). |
| 477 | 477 | |
| 478 | 478 | The exact format is unspecified and may change in the future. |
| 479 | 479 | |
| 480 | | - Request IDs can be used by clients to "match up" responses to |
| 481 | | - specific requests if needed. In practice, however, they are |
| 482 | | - seldom, if ever, needed. When passing several concurrent |
| 483 | | - requests through the same response callback, it might be useful |
| 484 | | - for some clients to be able to distinguish, possibly re-routing |
| 480 | + Request IDs can be used by clients to "match up" responses to |
| 481 | + specific requests if needed. In practice, however, they are |
| 482 | + seldom, if ever, needed. When passing several concurrent |
| 483 | + requests through the same response callback, it might be useful |
| 484 | + for some clients to be able to distinguish, possibly re-routing |
| 485 | 485 | them through other handlers based on the originating request type. |
| 486 | | - |
| 487 | | - If this.options.requestIdPrefix or |
| 486 | + |
| 487 | + If this.options.requestIdPrefix or |
| 488 | 488 | WhAjaj.Connector.options.requestIdPrefix is set then that text |
| 489 | 489 | is prefixed to the returned string. |
| 490 | 490 | */ |
| 491 | 491 | WhAjaj.Connector.prototype.generateRequestId = function() |
| 492 | 492 | { |
| | @@ -512,39 +512,39 @@ |
| 512 | 512 | } |
| 513 | 513 | return this.options; |
| 514 | 514 | }; |
| 515 | 515 | |
| 516 | 516 | /** |
| 517 | | - An internal helper object which holds several functions intended |
| 518 | | - to simplify the creation of concrete communication channel |
| 517 | + An internal helper object which holds several functions intended |
| 518 | + to simplify the creation of concrete communication channel |
| 519 | 519 | implementations for WhAjaj.Connector.sendImpl(). These operations |
| 520 | 520 | take care of some of the more error-prone parts of ensuring that |
| 521 | | - onResponse(), onError(), etc. callbacks are called consistently |
| 521 | + onResponse(), onError(), etc. callbacks are called consistently |
| 522 | 522 | using the same rules. |
| 523 | 523 | */ |
| 524 | 524 | WhAjaj.Connector.sendHelper = { |
| 525 | 525 | /** |
| 526 | | - opt is assumed to be a normalized set of |
| 527 | | - WhAjaj.Connector.sendRequest() options. This function |
| 528 | | - creates a url by concatenating opt.url and some form of |
| 526 | + opt is assumed to be a normalized set of |
| 527 | + WhAjaj.Connector.sendRequest() options. This function |
| 528 | + creates a url by concatenating opt.url and some form of |
| 529 | 529 | opt.urlParam. |
| 530 | | - |
| 531 | | - If opt.urlParam is an object or string then it is appended |
| 532 | | - to the url. An object is assumed to be a one-dimensional set |
| 533 | | - of simple (urlencodable) key/value pairs, and not larger |
| 534 | | - data structures. A string value is assumed to be a |
| 535 | | - well-formed, urlencoded set of key/value pairs separated by |
| 530 | + |
| 531 | + If opt.urlParam is an object or string then it is appended |
| 532 | + to the url. An object is assumed to be a one-dimensional set |
| 533 | + of simple (urlencodable) key/value pairs, and not larger |
| 534 | + data structures. A string value is assumed to be a |
| 535 | + well-formed, urlencoded set of key/value pairs separated by |
| 536 | 536 | '&' characters. |
| 537 | | - |
| 538 | | - The new/normalized URL is returned (opt is not modified). If |
| 539 | | - opt.urlParam is not set then opt.url is returned (or an |
| 537 | + |
| 538 | + The new/normalized URL is returned (opt is not modified). If |
| 539 | + opt.urlParam is not set then opt.url is returned (or an |
| 540 | 540 | empty string if opt.url is itself a false value). |
| 541 | | - |
| 542 | | - TODO: if opt is-a Object and any key points to an array, |
| 543 | | - build up a list of keys in the form "keyname[]". We could |
| 544 | | - arguably encode sub-objects like "keyname[subkey]=...", but |
| 545 | | - i don't know if that's conventions-compatible with other |
| 541 | + |
| 542 | + TODO: if opt is-a Object and any key points to an array, |
| 543 | + build up a list of keys in the form "keyname[]". We could |
| 544 | + arguably encode sub-objects like "keyname[subkey]=...", but |
| 545 | + i don't know if that's conventions-compatible with other |
| 546 | 546 | frameworks. |
| 547 | 547 | */ |
| 548 | 548 | normalizeURL: function(opt) { |
| 549 | 549 | var u = opt.url || ''; |
| 550 | 550 | if( opt.urlParam ) { |
| | @@ -564,50 +564,50 @@ |
| 564 | 564 | u = u + (addQ ? '?' : '') + (addA ? '&' : '') + tail; |
| 565 | 565 | } |
| 566 | 566 | return u; |
| 567 | 567 | }, |
| 568 | 568 | /** |
| 569 | | - Should be called by WhAjaj.Connector.sendImpl() |
| 570 | | - implementations after a response has come back. This |
| 571 | | - function takes care of most of ensuring that framework-level |
| 572 | | - conventions involving WhAjaj.Connector.options.ajax |
| 569 | + Should be called by WhAjaj.Connector.sendImpl() |
| 570 | + implementations after a response has come back. This |
| 571 | + function takes care of most of ensuring that framework-level |
| 572 | + conventions involving WhAjaj.Connector.options.ajax |
| 573 | 573 | properties are followed. |
| 574 | | - |
| 575 | | - The request argument must be the original request passed to |
| 574 | + |
| 575 | + The request argument must be the original request passed to |
| 576 | 576 | the sendImpl() function. It may legally be null for GET requests. |
| 577 | | - |
| 578 | | - The opt object should be the normalized AJAX options used |
| 577 | + |
| 578 | + The opt object should be the normalized AJAX options used |
| 579 | 579 | for the connection. |
| 580 | | - |
| 581 | | - The resp argument may be either a plain Object or a string |
| 580 | + |
| 581 | + The resp argument may be either a plain Object or a string |
| 582 | 582 | (in which case it is assumed to be JSON). |
| 583 | 583 | |
| 584 | 584 | The 'this' object for this call MUST be a WhAjaj.Connector |
| 585 | 585 | instance in order for callback processing to work properly. |
| 586 | | - |
| 586 | + |
| 587 | 587 | This function takes care of the following: |
| 588 | | - |
| 588 | + |
| 589 | 589 | - Calling opt.afterSend() |
| 590 | | - |
| 590 | + |
| 591 | 591 | - If resp is a string, de-JSON-izing it to an object. |
| 592 | | - |
| 592 | + |
| 593 | 593 | - Calling opt.onResponse() |
| 594 | | - |
| 595 | | - - Calling opt.onError() in several common (potential) error |
| 594 | + |
| 595 | + - Calling opt.onError() in several common (potential) error |
| 596 | 596 | cases. |
| 597 | 597 | |
| 598 | 598 | - If resp is-a String and opt.jsonp then resp is assumed to be |
| 599 | 599 | a JSONP-form construct and is eval()d BEFORE opt.onResponse() |
| 600 | 600 | is called. It is arguable to eval() it first, but the logic |
| 601 | 601 | integrates better with the non-jsonp handler. |
| 602 | 602 | |
| 603 | 603 | The sendImpl() should return immediately after calling this. |
| 604 | | - |
| 605 | | - The sendImpl() must call only one of onSendSuccess() or |
| 606 | | - onSendError(). It must call one of them or it must implement |
| 607 | | - its own response/error handling, which is not recommended |
| 608 | | - because getting the documented semantics of the |
| 604 | + |
| 605 | + The sendImpl() must call only one of onSendSuccess() or |
| 606 | + onSendError(). It must call one of them or it must implement |
| 607 | + its own response/error handling, which is not recommended |
| 608 | + because getting the documented semantics of the |
| 609 | 609 | onError/onResponse/afterSend handling correct can be tedious. |
| 610 | 610 | */ |
| 611 | 611 | onSendSuccess:function(request,resp,opt) { |
| 612 | 612 | var cb = this.callbacks || {}; |
| 613 | 613 | if( WhAjaj.isFunction(cb.afterSend) ) { |
| | @@ -666,23 +666,23 @@ |
| 666 | 666 | Should be called by sendImpl() implementations after a response |
| 667 | 667 | has failed to connect (e.g. could not resolve host or timeout |
| 668 | 668 | reached). This function takes care of most of ensuring that |
| 669 | 669 | framework-level conventions involving WhAjaj.Connector.options.ajax |
| 670 | 670 | properties are followed. |
| 671 | | - |
| 672 | | - The request argument must be the original request passed to |
| 673 | | - the sendImpl() function. It may legally be null for GET |
| 671 | + |
| 672 | + The request argument must be the original request passed to |
| 673 | + the sendImpl() function. It may legally be null for GET |
| 674 | 674 | requests. |
| 675 | 675 | |
| 676 | 676 | The 'this' object for this call MUST be a WhAjaj.Connector |
| 677 | 677 | instance in order for callback processing to work properly. |
| 678 | | - |
| 679 | | - The opt object should be the normalized AJAX options used |
| 680 | | - for the connection. By convention, the caller of this |
| 681 | | - function "should" set opt.errorMessage to contain a |
| 678 | + |
| 679 | + The opt object should be the normalized AJAX options used |
| 680 | + for the connection. By convention, the caller of this |
| 681 | + function "should" set opt.errorMessage to contain a |
| 682 | 682 | human-readable description of the error. |
| 683 | | - |
| 683 | + |
| 684 | 684 | The sendImpl() should return immediately after calling this. The |
| 685 | 685 | return value from this function is unspecified. |
| 686 | 686 | */ |
| 687 | 687 | onSendError: function(request,opt) { |
| 688 | 688 | var cb = this.callbacks || {}; |
| | @@ -704,64 +704,64 @@ |
| 704 | 704 | } |
| 705 | 705 | } |
| 706 | 706 | }; |
| 707 | 707 | |
| 708 | 708 | /** |
| 709 | | - WhAjaj.Connector.sendImpls holds several concrete |
| 710 | | - implementations of WhAjaj.Connector.prototype.sendImpl(). To use |
| 711 | | - a specific implementation by default assign |
| 709 | + WhAjaj.Connector.sendImpls holds several concrete |
| 710 | + implementations of WhAjaj.Connector.prototype.sendImpl(). To use |
| 711 | + a specific implementation by default assign |
| 712 | 712 | WhAjaj.Connector.prototype.sendImpl to one of these functions. |
| 713 | | - |
| 713 | + |
| 714 | 714 | The functions defined here require that the 'this' object be-a |
| 715 | 715 | WhAjaj.Connector instance. |
| 716 | | - |
| 716 | + |
| 717 | 717 | Historical notes: |
| 718 | 718 | |
| 719 | | - a) We once had an implementation based on Prototype, but that |
| 720 | | - library just pisses me off (they change base-most types' |
| 721 | | - prototypes, introducing side-effects in client code which |
| 722 | | - doesn't even use Prototype). The Prototype version at the time |
| 723 | | - had a serious toJSON() bug which caused empty arrays to |
| 724 | | - serialize as the string "[]", which broke a bunch of my code. |
| 725 | | - (That has been fixed in the mean time, but i don't use |
| 719 | + a) We once had an implementation based on Prototype, but that |
| 720 | + library just pisses me off (they change base-most types' |
| 721 | + prototypes, introducing side-effects in client code which |
| 722 | + doesn't even use Prototype). The Prototype version at the time |
| 723 | + had a serious toJSON() bug which caused empty arrays to |
| 724 | + serialize as the string "[]", which broke a bunch of my code. |
| 725 | + (That has been fixed in the mean time, but i don't use |
| 726 | 726 | Prototype.) |
| 727 | | - |
| 728 | | - b) We once had an implementation for the dojo library, |
| 729 | | - |
| 727 | + |
| 728 | + b) We once had an implementation for the dojo library, |
| 729 | + |
| 730 | 730 | If/when the time comes to add Prototype/dojo support, we simply |
| 731 | 731 | need to port: |
| 732 | | - |
| 732 | + |
| 733 | 733 | http://code.google.com/p/jsonmessage/source/browse/trunk/lib/JSONMessage/JSONMessage.inc.js |
| 734 | | - |
| 735 | | - (search that file for "dojo" and "Prototype") to this tree. That |
| 736 | | - code is this code's generic grandfather and they are still very |
| 737 | | - similar, so a port is trivial. |
| 738 | | - |
| 734 | + |
| 735 | + (search that file for "dojo" and "Prototype") to this tree. That |
| 736 | + code is this code's generic grandfather and they are still very |
| 737 | + similar, so a port is trivial. |
| 738 | + |
| 739 | 739 | */ |
| 740 | 740 | WhAjaj.Connector.sendImpls = { |
| 741 | 741 | /** |
| 742 | | - This is a concrete implementation of |
| 743 | | - WhAjaj.Connector.prototype.sendImpl() which uses the |
| 744 | | - environment's native XMLHttpRequest class to send whiki |
| 742 | + This is a concrete implementation of |
| 743 | + WhAjaj.Connector.prototype.sendImpl() which uses the |
| 744 | + environment's native XMLHttpRequest class to send whiki |
| 745 | 745 | requests and fetch the responses. |
| 746 | 746 | |
| 747 | | - The only argument must be a connection properties object, as |
| 747 | + The only argument must be a connection properties object, as |
| 748 | 748 | constructed by WhAjaj.Connector.normalizeAjaxParameters(). |
| 749 | 749 | |
| 750 | | - If window.firebug is set then window.firebug.watchXHR() is |
| 750 | + If window.firebug is set then window.firebug.watchXHR() is |
| 751 | 751 | called to enable monitoring of the XMLHttpRequest object. |
| 752 | 752 | |
| 753 | | - This implementation honors the loginName and loginPassword |
| 753 | + This implementation honors the loginName and loginPassword |
| 754 | 754 | connection parameters. |
| 755 | 755 | |
| 756 | 756 | Returns the XMLHttpRequest object. |
| 757 | 757 | |
| 758 | | - This implementation requires that the 'this' object be-a |
| 758 | + This implementation requires that the 'this' object be-a |
| 759 | 759 | WhAjaj.Connector. |
| 760 | | - |
| 761 | | - This implementation uses setTimeout() to implement the |
| 762 | | - timeout support, and thus the JS engine must provide that |
| 760 | + |
| 761 | + This implementation uses setTimeout() to implement the |
| 762 | + timeout support, and thus the JS engine must provide that |
| 763 | 763 | functionality. |
| 764 | 764 | */ |
| 765 | 765 | XMLHttpRequest: function(request, args) |
| 766 | 766 | { |
| 767 | 767 | var json = WhAjaj.isObject(request) ? JSON.stringify(request) : request; |
| | @@ -864,30 +864,30 @@ |
| 864 | 864 | WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); |
| 865 | 865 | return undefined; |
| 866 | 866 | } |
| 867 | 867 | }/*XMLHttpRequest()*/, |
| 868 | 868 | /** |
| 869 | | - This is a concrete implementation of |
| 870 | | - WhAjaj.Connector.prototype.sendImpl() which uses the jQuery |
| 869 | + This is a concrete implementation of |
| 870 | + WhAjaj.Connector.prototype.sendImpl() which uses the jQuery |
| 871 | 871 | AJAX API to send requests and fetch the responses. |
| 872 | 872 | |
| 873 | | - The first argument may be either null/false, an Object |
| 873 | + The first argument may be either null/false, an Object |
| 874 | 874 | containing toJSON-able data to post to the back-end, or such an |
| 875 | 875 | object in JSON string form. |
| 876 | 876 | |
| 877 | | - The second argument must be a connection properties object, as |
| 877 | + The second argument must be a connection properties object, as |
| 878 | 878 | constructed by WhAjaj.Connector.normalizeAjaxParameters(). |
| 879 | 879 | |
| 880 | | - If window.firebug is set then window.firebug.watchXHR() is |
| 880 | + If window.firebug is set then window.firebug.watchXHR() is |
| 881 | 881 | called to enable monitoring of the XMLHttpRequest object. |
| 882 | 882 | |
| 883 | | - This implementation honors the loginName and loginPassword |
| 883 | + This implementation honors the loginName and loginPassword |
| 884 | 884 | connection parameters. |
| 885 | 885 | |
| 886 | 886 | Returns the XMLHttpRequest object. |
| 887 | 887 | |
| 888 | | - This implementation requires that the 'this' object be-a |
| 888 | + This implementation requires that the 'this' object be-a |
| 889 | 889 | WhAjaj.Connector. |
| 890 | 890 | */ |
| 891 | 891 | jQuery:function(request,args) |
| 892 | 892 | { |
| 893 | 893 | var data = request || undefined; |
| | @@ -943,12 +943,12 @@ |
| 943 | 943 | WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); |
| 944 | 944 | return undefined; |
| 945 | 945 | } |
| 946 | 946 | }/*jQuery()*/, |
| 947 | 947 | /** |
| 948 | | - This is a concrete implementation of |
| 949 | | - WhAjaj.Connector.prototype.sendImpl() which uses the rhino |
| 948 | + This is a concrete implementation of |
| 949 | + WhAjaj.Connector.prototype.sendImpl() which uses the rhino |
| 950 | 950 | Java API to send requests and fetch the responses. |
| 951 | 951 | |
| 952 | 952 | Limitations vis-a-vis the interface: |
| 953 | 953 | |
| 954 | 954 | - timeouts are not supported. |
| | @@ -1051,28 +1051,28 @@ |
| 1051 | 1051 | WhAjaj.Connector.sendHelper.onSendSuccess.apply( self, [request, json, args] ); |
| 1052 | 1052 | }/*rhino*/ |
| 1053 | 1053 | }; |
| 1054 | 1054 | |
| 1055 | 1055 | /** |
| 1056 | | - An internal function which takes an object containing properties |
| 1057 | | - for a WhAjaj.Connector network request. This function creates a new |
| 1056 | + An internal function which takes an object containing properties |
| 1057 | + for a WhAjaj.Connector network request. This function creates a new |
| 1058 | 1058 | object containing a superset of the properties from: |
| 1059 | 1059 | |
| 1060 | 1060 | a) opt |
| 1061 | 1061 | b) this.options |
| 1062 | 1062 | c) WhAjaj.Connector.options.ajax |
| 1063 | 1063 | |
| 1064 | 1064 | in that order, using the first one it finds. |
| 1065 | 1065 | |
| 1066 | | - All non-function properties are _deeply_ copied via JSON cloning |
| 1067 | | - in order to prevent accidental "cross-request pollenation" (been |
| 1068 | | - there, done that). Functions cannot be cloned and are simply |
| 1066 | + All non-function properties are _deeply_ copied via JSON cloning |
| 1067 | + in order to prevent accidental "cross-request pollenation" (been |
| 1068 | + there, done that). Functions cannot be cloned and are simply |
| 1069 | 1069 | copied by reference. |
| 1070 | | - |
| 1070 | + |
| 1071 | 1071 | This function throws if JSON-copying one of the options fails |
| 1072 | 1072 | (e.g. due to cyclic data structures). |
| 1073 | | - |
| 1073 | + |
| 1074 | 1074 | Reminder to self: this function does not "normalize" opt.urlParam |
| 1075 | 1075 | by encoding it into opt.url, mainly for historical reasons, but |
| 1076 | 1076 | also because that behaviour was specifically undesirable in this |
| 1077 | 1077 | code's genetic father. |
| 1078 | 1078 | */ |
| | @@ -1100,68 +1100,68 @@ |
| 1100 | 1100 | // no, not here: rc.url = WhAjaj.Connector.sendHelper.normalizeURL(rc); |
| 1101 | 1101 | return rc; |
| 1102 | 1102 | }; |
| 1103 | 1103 | |
| 1104 | 1104 | /** |
| 1105 | | - This is the generic interface for making calls to a back-end |
| 1106 | | - JSON-producing request handler. It is a simple wrapper around |
| 1107 | | - WhAjaj.Connector.prototype.sendImpl(), which just normalizes the |
| 1108 | | - connection options for sendImpl() and makes sure that |
| 1105 | + This is the generic interface for making calls to a back-end |
| 1106 | + JSON-producing request handler. It is a simple wrapper around |
| 1107 | + WhAjaj.Connector.prototype.sendImpl(), which just normalizes the |
| 1108 | + connection options for sendImpl() and makes sure that |
| 1109 | 1109 | opt.beforeSend() is (possibly) called. |
| 1110 | | - |
| 1111 | | - The request parameter must either be false/null/empty or a |
| 1112 | | - fully-populated JSON-able request object (which will be sent as |
| 1113 | | - unencoded application/json text), depending on the type of |
| 1114 | | - request being made. It is never semantically legal (in this API) |
| 1115 | | - for request to be a string/number/true/array value. As a rule, |
| 1116 | | - only POST requests use the request data. GET requests should |
| 1110 | + |
| 1111 | + The request parameter must either be false/null/empty or a |
| 1112 | + fully-populated JSON-able request object (which will be sent as |
| 1113 | + unencoded application/json text), depending on the type of |
| 1114 | + request being made. It is never semantically legal (in this API) |
| 1115 | + for request to be a string/number/true/array value. As a rule, |
| 1116 | + only POST requests use the request data. GET requests should |
| 1117 | 1117 | encode their data in opt.url or opt.urlParam (see below). |
| 1118 | | - |
| 1119 | | - opt must contain the network-related parameters for the request. |
| 1120 | | - Paramters _not_ set in opt are pulled from this.options or |
| 1121 | | - WhAjaj.Connector.options.ajax (in that order, using the first |
| 1122 | | - value it finds). Thus the set of connection-level options used |
| 1118 | + |
| 1119 | + opt must contain the network-related parameters for the request. |
| 1120 | + Paramters _not_ set in opt are pulled from this.options or |
| 1121 | + WhAjaj.Connector.options.ajax (in that order, using the first |
| 1122 | + value it finds). Thus the set of connection-level options used |
| 1123 | 1123 | for the request are a superset of those various sources. |
| 1124 | | - |
| 1125 | | - The "normalized" (or "superimposed") opt object's URL may be |
| 1124 | + |
| 1125 | + The "normalized" (or "superimposed") opt object's URL may be |
| 1126 | 1126 | modified before the request is sent, as follows: |
| 1127 | 1127 | |
| 1128 | | - if opt.urlParam is a string then it is assumed to be properly |
| 1129 | | - URL-encoded parameters and is appended to the opt.url. If it is |
| 1130 | | - an Object then it is assumed to be a one-dimensional set of |
| 1131 | | - key/value pairs with simple values (numbers, strings, booleans, |
| 1132 | | - null, and NOT objects/arrays). The keys/values are URL-encoded |
| 1128 | + if opt.urlParam is a string then it is assumed to be properly |
| 1129 | + URL-encoded parameters and is appended to the opt.url. If it is |
| 1130 | + an Object then it is assumed to be a one-dimensional set of |
| 1131 | + key/value pairs with simple values (numbers, strings, booleans, |
| 1132 | + null, and NOT objects/arrays). The keys/values are URL-encoded |
| 1133 | 1133 | and appended to the URL. |
| 1134 | 1134 | |
| 1135 | 1135 | The beforeSend() callback (see below) can modify the options |
| 1136 | 1136 | object before the request attempt is made. |
| 1137 | | - |
| 1137 | + |
| 1138 | 1138 | The callbacks in the normalized opt object will be triggered as |
| 1139 | 1139 | follows (if they are set to Function values): |
| 1140 | | - |
| 1141 | | - - beforeSend(request,opt) will be called before any network |
| 1142 | | - processing starts. If beforeSend() throws then no other |
| 1143 | | - callbacks are triggered and this function propagates the |
| 1140 | + |
| 1141 | + - beforeSend(request,opt) will be called before any network |
| 1142 | + processing starts. If beforeSend() throws then no other |
| 1143 | + callbacks are triggered and this function propagates the |
| 1144 | 1144 | exception. This function is passed normalized connection options |
| 1145 | 1145 | as its second parameter, and changes this function makes to that |
| 1146 | 1146 | object _will_ be used for the pending connection attempt. |
| 1147 | | - |
| 1148 | | - - onError(request,opt) will be called if a connection to the |
| 1149 | | - back-end cannot be established. It will be passed the original |
| 1150 | | - request object (which might be null, depending on the request |
| 1151 | | - type) and the normalized options object. In the error case, the |
| 1152 | | - opt object passed to onError() "should" have a property called |
| 1147 | + |
| 1148 | + - onError(request,opt) will be called if a connection to the |
| 1149 | + back-end cannot be established. It will be passed the original |
| 1150 | + request object (which might be null, depending on the request |
| 1151 | + type) and the normalized options object. In the error case, the |
| 1152 | + opt object passed to onError() "should" have a property called |
| 1153 | 1153 | "errorMessage" which contains a description of the problem. |
| 1154 | | - |
| 1155 | | - - onError(request,opt) will also be called if connection |
| 1154 | + |
| 1155 | + - onError(request,opt) will also be called if connection |
| 1156 | 1156 | succeeds but the response is not JSON data. |
| 1157 | | - |
| 1158 | | - - onResponse(response,request) will be called if the response |
| 1159 | | - returns JSON data. That data might hold an error response code - |
| 1160 | | - clients need to check for that. It is passed the response object |
| 1157 | + |
| 1158 | + - onResponse(response,request) will be called if the response |
| 1159 | + returns JSON data. That data might hold an error response code - |
| 1160 | + clients need to check for that. It is passed the response object |
| 1161 | 1161 | (a plain object) and the original request object. |
| 1162 | | - |
| 1162 | + |
| 1163 | 1163 | - afterSend(request,opt) will be called directly after the |
| 1164 | 1164 | AJAX request is finished, before onError() or onResonse() are |
| 1165 | 1165 | called. Possible TODO: we explicitly do NOT pass the response to |
| 1166 | 1166 | this function in order to keep the line between the responsibilities |
| 1167 | 1167 | of the various callback clear (otherwise this could be used the same |
| | @@ -1179,14 +1179,14 @@ |
| 1179 | 1179 | { |
| 1180 | 1180 | throw new Error("This object has no sendImpl() member function! I don't know how to send the request!"); |
| 1181 | 1181 | } |
| 1182 | 1182 | var ex = false; |
| 1183 | 1183 | var av = Array.prototype.slice.apply( arguments, [0] ); |
| 1184 | | - |
| 1184 | + |
| 1185 | 1185 | /** |
| 1186 | | - FIXME: how to handle the error, vis-a-vis- the callbacks, if |
| 1187 | | - normalizeAjaxParameters() throws? It can throw if |
| 1186 | + FIXME: how to handle the error, vis-a-vis- the callbacks, if |
| 1187 | + normalizeAjaxParameters() throws? It can throw if |
| 1188 | 1188 | (de)JSON-izing fails. |
| 1189 | 1189 | */ |
| 1190 | 1190 | var norm = this.normalizeAjaxParameters( WhAjaj.isObject(opt) ? opt : {} ); |
| 1191 | 1191 | norm.url = WhAjaj.Connector.sendHelper.normalizeURL(norm); |
| 1192 | 1192 | if( ! request ) norm.method = 'GET'; |
| 1193 | 1193 | |