Fix a problem that can occasionally occur with repeated syncs to/from a git repository,
where a fossil-generated mark clashes with a mark previously generated by git, causing
the sync to fail.
check-in: 69668f8c user: nick.lloyd tags: nick.lloyd-git-interop

License: Public Domain
*/
/**
Constructor for a new Fossil AJAJ client. ajajOpt may be an optional
object suitable for passing to the WhAjaj.Connector() constructor.
On returning, this.ajaj is-a WhAjaj.Connector instance which can
be used to send requests to the back-end (though the convenience
functions of this class are the preferred way to do it). Clients
are encouraged to use FossilAjaj.sendCommand() (and friends) instead
of the underlying WhAjaj.Connector API, since this class' API
contains Fossil-specific request-calling handling (e.g. of authentication
info) whereas WhAjaj is more generic.
*/
function FossilAjaj(ajajOpt)
{
this.ajaj = new WhAjaj.Connector(ajajOpt);
return this;
................................................................................
};
/**
Sends a command to the fossil back-end. Command should be the
path part of the URL, e.g. /json/stat, payload is a request-specific
value type (may often be null/undefined). ajajOpt is an optional object
holding WhAjaj.sendRequest()-compatible options.
This function constructs a Fossil/JSON request envelope based
on the given arguments and adds this.auth.authToken and a requestId
to it.
*/
FossilAjaj.prototype.sendCommand = function(command, payload, ajajOpt) {
var req;
ajajOpt = ajajOpt || {};
................................................................................
if(command) ajajOpt.url = this.ajaj.derivedOption('url',ajajOpt) + command;
this.ajaj.sendRequest(req,ajajOpt);
};
/**
Sends a login request to the back-end.
ajajOpt is an optional configuration object suitable for passing
to sendCommand().
After the response returns, this.auth will be
set to the response payload.
If name === 'anonymous' (the default if none is passed in) then this
function ignores the pw argument and must make two requests - the first
one gets the captcha code and the second one submits it.
ajajOpt.onResponse() (if set) is only called for the actual login
response (the 2nd one), as opposed to being called for both requests.
However, this.ajaj.callbacks.onResponse() _is_ called for both (because
it happens at a lower level).
If this object has an onLogin() function it is called (with
no arguments) before the onResponse() handler of the login is called
(that is the 2nd request for anonymous logins) and any exceptions
it throws are ignored.
*/
FossilAjaj.prototype.login = function(name,pw,ajajOpt) {
................................................................................
}
else doLogin();
};
/**
Logs out of fossil, invaliding this login token.
ajajOpt is an optional configuration object suitable for passing
to sendCommand().
If this object has an onLogout() function it is called (with
no arguments) before the onResponse() handler is called.
IFF the response succeeds then this.auth is unset.
*/
FossilAjaj.prototype.logout = function(ajajOpt) {
var self = this;
ajajOpt = this.ajaj.normalizeAjaxParameters( ajajOpt || {} );
................................................................................
};
this.sendCommand('/json/logout', undefined, ajajOpt );
};
/**
Sends a HAI request to the server. /json/HAI is an alias /json/version.
ajajOpt is an optional configuration object suitable for passing
to sendCommand().
*/
FossilAjaj.prototype.HAI = function(ajajOpt) {
this.sendCommand('/json/HAI', undefined, ajajOpt);
};
................................................................................
mode, feeds it the request envelope, and returns the response envelope
via the same mechanisms defined for the HTTP-based implementations.
The interface is otherwise compatible with the "normal"
FossilAjaj.sendCommand() front-end (it is, however, fossil-specific, and
not back-end agnostic like the WhAjaj.sendImpl() interface intends).
*/
FossilAjaj.rhinoLocalBinarySendImpl = function(request,args){
var self = this;
request = request || {};
if(!args.fossilBinary){
throw new Error("fossilBinary is not set on AJAX options!");
}
var url = args.url.split('?')[0].split(/\/+/);
if(url.length>1){
// 3x shift(): protocol, host, 'json' part of path
request.command = (url.shift(),url.shift(),url.shift(), url.join('/'));
}
delete args.url;
//print("rhinoLocalBinarySendImpl SENDING: "+WhAjaj.stringify(request));
var json;
try{
var pargs = [args.fossilBinary, 'json', '--json-input', '-'];
var p = java.lang.Runtime.getRuntime().exec(pargs);
var outs = p.getOutputStream();
var osr = new java.io.OutputStreamWriter(outs);
var osb = new java.io.BufferedWriter(osr);
json = JSON.stringify(request);
osb.write(json,0, json.length);
osb.close();
var ins = p.getInputStream();
var isr = new java.io.InputStreamReader(ins);
var br = new java.io.BufferedReader(isr);
var line;

License: Public Domain
*/
/**
Constructor for a new Fossil AJAJ client. ajajOpt may be an optional
object suitable for passing to the WhAjaj.Connector() constructor.
On returning, this.ajaj is-a WhAjaj.Connector instance which can
be used to send requests to the back-end (though the convenience
functions of this class are the preferred way to do it). Clients
are encouraged to use FossilAjaj.sendCommand() (and friends) instead
of the underlying WhAjaj.Connector API, since this class' API
contains Fossil-specific request-calling handling (e.g. of authentication
info) whereas WhAjaj is more generic.
*/
function FossilAjaj(ajajOpt)
{
this.ajaj = new WhAjaj.Connector(ajajOpt);
return this;
................................................................................
};
/**
Sends a command to the fossil back-end. Command should be the
path part of the URL, e.g. /json/stat, payload is a request-specific
value type (may often be null/undefined). ajajOpt is an optional object
holding WhAjaj.sendRequest()-compatible options.
This function constructs a Fossil/JSON request envelope based
on the given arguments and adds this.auth.authToken and a requestId
to it.
*/
FossilAjaj.prototype.sendCommand = function(command, payload, ajajOpt) {
var req;
ajajOpt = ajajOpt || {};
................................................................................
if(command) ajajOpt.url = this.ajaj.derivedOption('url',ajajOpt) + command;
this.ajaj.sendRequest(req,ajajOpt);
};
/**
Sends a login request to the back-end.
ajajOpt is an optional configuration object suitable for passing
to sendCommand().
After the response returns, this.auth will be
set to the response payload.
If name === 'anonymous' (the default if none is passed in) then this
function ignores the pw argument and must make two requests - the first
one gets the captcha code and the second one submits it.
ajajOpt.onResponse() (if set) is only called for the actual login
response (the 2nd one), as opposed to being called for both requests.
However, this.ajaj.callbacks.onResponse() _is_ called for both (because
it happens at a lower level).
If this object has an onLogin() function it is called (with
no arguments) before the onResponse() handler of the login is called
(that is the 2nd request for anonymous logins) and any exceptions
it throws are ignored.
*/
FossilAjaj.prototype.login = function(name,pw,ajajOpt) {
................................................................................
}
else doLogin();
};
/**
Logs out of fossil, invaliding this login token.
ajajOpt is an optional configuration object suitable for passing
to sendCommand().
If this object has an onLogout() function it is called (with
no arguments) before the onResponse() handler is called.
IFF the response succeeds then this.auth is unset.
*/
FossilAjaj.prototype.logout = function(ajajOpt) {
var self = this;
ajajOpt = this.ajaj.normalizeAjaxParameters( ajajOpt || {} );
................................................................................
};
this.sendCommand('/json/logout', undefined, ajajOpt );
};
/**
Sends a HAI request to the server. /json/HAI is an alias /json/version.
ajajOpt is an optional configuration object suitable for passing
to sendCommand().
*/
FossilAjaj.prototype.HAI = function(ajajOpt) {
this.sendCommand('/json/HAI', undefined, ajajOpt);
};
................................................................................
mode, feeds it the request envelope, and returns the response envelope
via the same mechanisms defined for the HTTP-based implementations.
The interface is otherwise compatible with the "normal"
FossilAjaj.sendCommand() front-end (it is, however, fossil-specific, and
not back-end agnostic like the WhAjaj.sendImpl() interface intends).
*/
FossilAjaj.rhinoLocalBinarySendImpl = function(request,args){
var self = this;
request = request || {};
if(!args.fossilBinary){
throw new Error("fossilBinary is not set on AJAX options!");
}
var url = args.url.split('?')[0].split(/\/+/);
if(url.length>1){
// 3x shift(): protocol, host, 'json' part of path
request.command = (url.shift(),url.shift(),url.shift(), url.join('/'));
}
delete args.url;
//print("rhinoLocalBinarySendImpl SENDING: "+WhAjaj.stringify(request));
var json;
try{
var pargs = [args.fossilBinary, 'json', '--json-input', '-'];
var p = java.lang.Runtime.getRuntime().exec(pargs);
var outs = p.getOutputStream();
var osr = new java.io.OutputStreamWriter(outs);
var osb = new java.io.BufferedWriter(osr);
json = JSON.stringify(request);
osb.write(json,0, json.length);
osb.close();
var ins = p.getInputStream();
var isr = new java.io.InputStreamReader(ins);
var br = new java.io.BufferedReader(isr);
var line;

All functionality is part of a class named WhAjaj, and that class
acts as namespace for this framework.
Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
License: Public Domain
This framework is directly derived from code originally found in
http://code.google.com/p/jsonmessage, and later in
http://whiki.wanderinghorse.net, where it contained quite a bit
of application-specific logic. It was eventually (the 3rd time i
needed it) split off into its own library to simplify inclusion
into my many mini-projects.
*/
/**
The WhAjaj function is primarily a namespace, and not intended
to called or instantiated via the 'new' operator.
*/
function WhAjaj()
{
}
/** Returns a millisecond Unix Epoch timestamp. */
................................................................................
WhAjaj.msTimestamp = function()
{
return (new Date()).getTime();
};
/** Returns a Unix Epoch timestamp (in seconds) in integer format.
Reminder to self: (1.1 %1.2) evaluates to a floating-point value
in JS, and thus this implementation is less than optimal.
*/
WhAjaj.unixTimestamp = function()
{
var ts = (new Date()).getTime();
return parseInt( ""+((ts / 1000) % ts) );
};
................................................................................
)
;
};
/**
Parses window.location.search-style string into an object
containing key/value pairs of URL arguments (already urldecoded).
If the str argument is not passed (arguments.length==0) then
window.location.search.substring(1) is used by default. If
neither str is passed in nor window exists then false is returned.
On success it returns an Object containing the key/value pairs
parsed from the string. Keys which have no value are treated
has having the boolean true value.
FIXME: for keys in the form "name[]", build an array of results,
like PHP does.
*/
WhAjaj.processUrlArgs = function(str) {
if( 0 === arguments.length ) {
if( ('undefined' === typeof window) ||
!window.location ||
!window.location.search ) return false;
else str = (''+window.location.search).substring(1);
................................................................................
};
/**
A simple wrapper around JSON.stringify(), using my own personal
preferred values for the 2nd and 3rd parameters. To globally
set its indentation level, assign WhAjaj.stringify.indent to
an integer value (0 for no intendation).
This function is intended only for human-readable output, not
generic over-the-wire JSON output (where JSON.stringify(val) will
produce smaller results).
*/
WhAjaj.stringify = function(val) {
if( ! arguments.callee.indent ) arguments.callee.indent = 4;
return JSON.stringify(val,0,arguments.callee.indent);
};
/**
Each instance of this class holds state information for making
AJAJ requests to a back-end system. While clients may use one
"requester" object per connection attempt, for connections to the
same back-end, using an instance configured for that back-end
can simplify usage. This class is designed so that the actual
connection-related details (i.e. _how_ it connects to the
back-end) may be re-implemented to use a client's preferred
connection mechanism (e.g. jQuery).
The optional opt paramater may be an object with any (or all) of
the properties documented for WhAjaj.Connector.options.ajax.
Properties set here (or later via modification of the "options"
property of this object) will be used in calls to
WhAjaj.Connector.sendRequest(), and these override (normally) any
options set in WhAjaj.Connector.options.ajax. Note that
WhAjaj.Connector.sendRequest() _also_ takes an options object,
and ones passed there will override, for purposes of that one
request, any options passed in here or defined in
WhAjaj.Connector.options.ajax. See WhAjaj.Connector.options.ajax
and WhAjaj.Connector.prototype.sendRequest() for more details
about the precedence of options.
Sample usage:
@code
// Set up common connection-level options:
var cgi = new WhAjaj.Connector({
url: '/cgi-bin/my.cgi',
timeout:10000,
onResponse(resp,req) { alert(JSON.stringify(resp,0.4)); },
onError(req,opt) {
................................................................................
onResponse(resp,req){ alert(WhAjaj.stringify(resp)); }
});
@endcode
For common request types, clients can add functions to this
object which act as wrappers for backend-specific functionality. As
a simple example:
@code
cgi.login = function(name,pw,ajajOpt) {
this.sendRequest(
{command:"json/login",
name:name,
password:pw
}, ajajOpt );
};
@endcode
TODOs:
- Caching of page-load requests, with a configurable lifetime.
- Use-cases like the above login() function are a tiny bit
problematic to implement when each request has a different URL
path (i know this from the whiki and fossil implementations).
This is partly a side-effect of design descisions made back in
the very first days of this code's life. i need to go through
and see where i can bend those conventions a bit (where it won't
break my other apps unduly).
................................................................................
WhAjaj.Connector.options = {
/**
A (meaningless) prefix to apply to WhAjaj.Connector-generated
request IDs.
*/
requestIdPrefix:'WhAjaj.Connector-',
/**
Default options for WhAjaj.Connector.sendRequest() connection
parameters. This object holds only connection-related
options and callbacks (all optional), and not options
related to the required JSON structure of any given request.
i.e. the page name used in a get-page request are not set
here but are specified as part of the request object.
These connection options are a "normalized form" of options
often found in various AJAX libraries like jQuery,
Prototype, dojo, etc. This approach allows us to swap out
the real connection-related parts by writing a simple proxy
which transforms our "normalized" form to the
backend-specific form. For examples, see the various
implementations stored in WhAjaj.Connector.sendImpls.
The following callback options are, in practice, almost
always set globally to some app-wide defaults:
- onError() to report errors using a common mechanism.
- beforeSend() to start a visual activity notification
- afterSend() to disable the visual activity notification
However, be aware that if any given WhAjaj.Connector instance is
given its own before/afterSend callback then those will
override these. Mixing shared/global and per-instance
callbacks can potentially lead to confusing results if, e.g.,
the beforeSend() and afterSend() functions have side-effects
but are not used with their proper before/after partner.
TODO: rename this to 'ajaj' (the name is historical). The
problem with renaming it is is that the word 'ajax' is
pretty prevelant in the source tree, so i can't globally
swap it out.
*/
ajax: {
/**
URL of the back-end server/CGI.
*/
url: '/some/path',
/**
Connection method. Some connection-related functions might
override any client-defined setting.
Must be one of 'GET' or 'POST'. For custom connection
implementation, it may optionally be some
implementation-specified value.
Normally the API can derive this value automatically - if the
request uses JSON data it is POSTed, else it is GETted.
*/
method:'GET',
/**
A hint whether to run the operation asynchronously or
not. Not all concrete WhAjaj.Connector.sendImpl()
implementations can support this. Interestingly, at
least one popular AJAX toolkit does not document
supporting _synchronous_ AJAX operations. All common
browser-side implementations support async operation, but
non-browser implementations might not.
*/
asynchronous:true,
/**
A HTTP authentication login name for the AJAX
connection. Not all concrete WhAjaj.Connector.sendImpl()
implementations can support this.
*/
loginName:undefined,
/**
An HTTP authentication login password for the AJAJ
connection. Not all concrete WhAjaj.Connector.sendImpl()
implementations can support this.
*/
loginPassword:undefined,
/**
A connection timeout, in milliseconds, for establishing
an AJAJ connection. Not all concrete
WhAjaj.Connector.sendImpl() implementations can support this.
*/
timeout:10000,
/**
If an AJAJ request receives JSON data from the back-end,
that data is passed as a plain Object as the response
................................................................................
ignore it (only those which need a way to map specific
requests to responses will need it). The 3rd parameter
is the same as the 'this' object for the context of the
callback, but is provided because the instance-level
callbacks (set in (WhAjaj.Connector instance).callbacks,
require it in some cases (because their 'this' is
different!).
Note that the response might contain error information
which comes from the back-end. The difference between
this error info and the info passed to the onError()
callback is that this data indicates an
application-level error, whereas onError() is used to
report connection-level problems or when the backend
produces non-JSON data (which, when not in jsonp mode,
is unexpected and is as fatal to the request as a
connection error).
*/
onResponse: function(response, request, opt){},
/**
If an AJAX request fails to establish a connection or it
receives non-JSON data from the back-end, this function
is called (e.g. timeout error or host name not
resolvable). It is passed the originating request and the
"normalized" connection parameters used for that
request. The connectOpt object "should" (or "might")
have an "errorMessage" property which describes the
nature of the problem.
Clients will almost always want to replace the default
implementation with something which integrates into
their application.
*/
onError: function(request, connectOpt)
{
alert('AJAJ request failed:\n'
+'Connection information:\n'
+JSON.stringify(connectOpt,0,4)
);
},
/**
Called before each connection attempt is made. Clients
can use this to, e.g., enable a visual "network activity
notification" for the user. It is passed the original
request object and the normalized connection parameters
for the request. If this function changes opt, those
changes _are_ applied to the subsequent request. If this
function throws, neither the onError() nor afterSend()
callbacks are triggered and WhAjaj.Connector.sendImpl()
propagates the exception back to the caller.
*/
beforeSend: function(request,opt){},
/**
Called after an AJAJ connection attempt completes,
regardless of success or failure. Passed the same
parameters as beforeSend() (see that function for
details).
Here's an example of setting up a visual notification on
ajax operations using jQuery (but it's also easy to do
without jQuery as well):
@code
function startAjaxNotif(req,opt) {
var me = arguments.callee;
var c = ++me.ajaxCount;
me.element.text( c + " pending AJAX operation(s)..." );
if( 1 == c ) me.element.stop().fadeIn();
}
startAjaxNotif.ajaxCount = 0.
startAjaxNotif.element = jQuery('#whikiAjaxNotification');
function endAjaxNotif() {
var c = --startAjaxNotif.ajaxCount;
startAjaxNotif.element.text( c+" pending AJAX operation(s)..." );
if( 0 == c ) startAjaxNotif.element.stop().fadeOut();
}
@endcode
Set the beforeSend/afterSend properties to those
functions to enable the notifications by default.
*/
afterSend: function(request,opt){},
/**
If jsonp is a string then the WhAjaj-internal response
handling code ASSUMES that the response contains a JSONP-style
construct and eval()s it after afterSend() but before onResponse().
In this case, onResponse() will get a string value for the response
instead of a response object parsed from JSON.
*/
jsonp:undefined,
/**
Don't use yet. Planned future option.
*/
propagateExceptions:false
}
................................................................................
else v = this.options[key];
if( undefined !== v ) return v;
else v = WhAjaj.Connector.options.ajax[key];
return v;
};
/**
Returns a unique string on each call containing a generic
reandom request identifier string. This is not used by the core
API but can be used by client code to generate unique IDs for
each request (if needed).
The exact format is unspecified and may change in the future.
Request IDs can be used by clients to "match up" responses to
specific requests if needed. In practice, however, they are
seldom, if ever, needed. When passing several concurrent
requests through the same response callback, it might be useful
for some clients to be able to distinguish, possibly re-routing
them through other handlers based on the originating request type.
If this.options.requestIdPrefix or
WhAjaj.Connector.options.requestIdPrefix is set then that text
is prefixed to the returned string.
*/
WhAjaj.Connector.prototype.generateRequestId = function()
{
if( undefined === arguments.callee.sequence )
{
................................................................................
if( ! opt.hasOwnProperty(k) ) continue /* proactive Prototype kludge! */;
this.options[k] = opt[k];
}
return this.options;
};
/**
An internal helper object which holds several functions intended
to simplify the creation of concrete communication channel
implementations for WhAjaj.Connector.sendImpl(). These operations
take care of some of the more error-prone parts of ensuring that
onResponse(), onError(), etc. callbacks are called consistently
using the same rules.
*/
WhAjaj.Connector.sendHelper = {
/**
opt is assumed to be a normalized set of
WhAjaj.Connector.sendRequest() options. This function
creates a url by concatenating opt.url and some form of
opt.urlParam.
If opt.urlParam is an object or string then it is appended
to the url. An object is assumed to be a one-dimensional set
of simple (urlencodable) key/value pairs, and not larger
data structures. A string value is assumed to be a
well-formed, urlencoded set of key/value pairs separated by
'&' characters.
The new/normalized URL is returned (opt is not modified). If
opt.urlParam is not set then opt.url is returned (or an
empty string if opt.url is itself a false value).
TODO: if opt is-a Object and any key points to an array,
build up a list of keys in the form "keyname[]". We could
arguably encode sub-objects like "keyname[subkey]=...", but
i don't know if that's conventions-compatible with other
frameworks.
*/
normalizeURL: function(opt) {
var u = opt.url || '';
if( opt.urlParam ) {
var addQ = (u.indexOf('?') >= 0) ? false : true;
var addA = addQ ? false : ((u.indexOf('&')>=0) ? true : false);
................................................................................
tail = opt.urlParam;
}
u = u + (addQ ? '?' : '') + (addA ? '&' : '') + tail;
}
return u;
},
/**
Should be called by WhAjaj.Connector.sendImpl()
implementations after a response has come back. This
function takes care of most of ensuring that framework-level
conventions involving WhAjaj.Connector.options.ajax
properties are followed.
The request argument must be the original request passed to
the sendImpl() function. It may legally be null for GET requests.
The opt object should be the normalized AJAX options used
for the connection.
The resp argument may be either a plain Object or a string
(in which case it is assumed to be JSON).
The 'this' object for this call MUST be a WhAjaj.Connector
instance in order for callback processing to work properly.
This function takes care of the following:
- Calling opt.afterSend()
- If resp is a string, de-JSON-izing it to an object.
- Calling opt.onResponse()
- Calling opt.onError() in several common (potential) error
cases.
- If resp is-a String and opt.jsonp then resp is assumed to be
a JSONP-form construct and is eval()d BEFORE opt.onResponse()
is called. It is arguable to eval() it first, but the logic
integrates better with the non-jsonp handler.
The sendImpl() should return immediately after calling this.
The sendImpl() must call only one of onSendSuccess() or
onSendError(). It must call one of them or it must implement
its own response/error handling, which is not recommended
because getting the documented semantics of the
onError/onResponse/afterSend handling correct can be tedious.
*/
onSendSuccess:function(request,resp,opt) {
var cb = this.callbacks || {};
if( WhAjaj.isFunction(cb.afterSend) ) {
try {cb.afterSend( request, opt );}
catch(e){}
................................................................................
},
/**
Should be called by sendImpl() implementations after a response
has failed to connect (e.g. could not resolve host or timeout
reached). This function takes care of most of ensuring that
framework-level conventions involving WhAjaj.Connector.options.ajax
properties are followed.
The request argument must be the original request passed to
the sendImpl() function. It may legally be null for GET
requests.
The 'this' object for this call MUST be a WhAjaj.Connector
instance in order for callback processing to work properly.
The opt object should be the normalized AJAX options used
for the connection. By convention, the caller of this
function "should" set opt.errorMessage to contain a
human-readable description of the error.
The sendImpl() should return immediately after calling this. The
return value from this function is unspecified.
*/
onSendError: function(request,opt) {
var cb = this.callbacks || {};
if( WhAjaj.isFunction(cb.afterSend) ) {
try {cb.afterSend( request, opt );}
................................................................................
try {opt.onError( request, opt );}
catch(e) {/*ignore*/}
}
}
};
/**
WhAjaj.Connector.sendImpls holds several concrete
implementations of WhAjaj.Connector.prototype.sendImpl(). To use
a specific implementation by default assign
WhAjaj.Connector.prototype.sendImpl to one of these functions.
The functions defined here require that the 'this' object be-a
WhAjaj.Connector instance.
Historical notes:
a) We once had an implementation based on Prototype, but that
library just pisses me off (they change base-most types'
prototypes, introducing side-effects in client code which
doesn't even use Prototype). The Prototype version at the time
had a serious toJSON() bug which caused empty arrays to
serialize as the string "[]", which broke a bunch of my code.
(That has been fixed in the mean time, but i don't use
Prototype.)
b) We once had an implementation for the dojo library,
If/when the time comes to add Prototype/dojo support, we simply
need to port:
http://code.google.com/p/jsonmessage/source/browse/trunk/lib/JSONMessage/JSONMessage.inc.js
(search that file for "dojo" and "Prototype") to this tree. That
code is this code's generic grandfather and they are still very
similar, so a port is trivial.
*/
WhAjaj.Connector.sendImpls = {
/**
This is a concrete implementation of
WhAjaj.Connector.prototype.sendImpl() which uses the
environment's native XMLHttpRequest class to send whiki
requests and fetch the responses.
The only argument must be a connection properties object, as
constructed by WhAjaj.Connector.normalizeAjaxParameters().
If window.firebug is set then window.firebug.watchXHR() is
called to enable monitoring of the XMLHttpRequest object.
This implementation honors the loginName and loginPassword
connection parameters.
Returns the XMLHttpRequest object.
This implementation requires that the 'this' object be-a
WhAjaj.Connector.
This implementation uses setTimeout() to implement the
timeout support, and thus the JS engine must provide that
functionality.
*/
XMLHttpRequest: function(request, args)
{
var json = WhAjaj.isObject(request) ? JSON.stringify(request) : request;
var xhr = new XMLHttpRequest();
var startTime = (new Date()).getTime();
................................................................................
{
args.errorMessage = e.toString();
WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
return undefined;
}
}/*XMLHttpRequest()*/,
/**
This is a concrete implementation of
WhAjaj.Connector.prototype.sendImpl() which uses the jQuery
AJAX API to send requests and fetch the responses.
The first argument may be either null/false, an Object
containing toJSON-able data to post to the back-end, or such an
object in JSON string form.
The second argument must be a connection properties object, as
constructed by WhAjaj.Connector.normalizeAjaxParameters().
If window.firebug is set then window.firebug.watchXHR() is
called to enable monitoring of the XMLHttpRequest object.
This implementation honors the loginName and loginPassword
connection parameters.
Returns the XMLHttpRequest object.
This implementation requires that the 'this' object be-a
WhAjaj.Connector.
*/
jQuery:function(request,args)
{
var data = request || undefined;
var whself = this;
if( data ) {
................................................................................
{
args.errorMessage = e.toString();
WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
return undefined;
}
}/*jQuery()*/,
/**
This is a concrete implementation of
WhAjaj.Connector.prototype.sendImpl() which uses the rhino
Java API to send requests and fetch the responses.
Limitations vis-a-vis the interface:
- timeouts are not supported.
- asynchronous mode is not supported because implementing it
................................................................................
json = json.join('');
//print("READ IN JSON: "+json);
WhAjaj.Connector.sendHelper.onSendSuccess.apply( self, [request, json, args] );
}/*rhino*/
};
/**
An internal function which takes an object containing properties
for a WhAjaj.Connector network request. This function creates a new
object containing a superset of the properties from:
a) opt
b) this.options
c) WhAjaj.Connector.options.ajax
in that order, using the first one it finds.
All non-function properties are _deeply_ copied via JSON cloning
in order to prevent accidental "cross-request pollenation" (been
there, done that). Functions cannot be cloned and are simply
copied by reference.
This function throws if JSON-copying one of the options fails
(e.g. due to cyclic data structures).
Reminder to self: this function does not "normalize" opt.urlParam
by encoding it into opt.url, mainly for historical reasons, but
also because that behaviour was specifically undesirable in this
code's genetic father.
*/
WhAjaj.Connector.prototype.normalizeAjaxParameters = function (opt)
{
................................................................................
cp( this.options );
cp( WhAjaj.Connector.options.ajax );
// no, not here: rc.url = WhAjaj.Connector.sendHelper.normalizeURL(rc);
return rc;
};
/**
This is the generic interface for making calls to a back-end
JSON-producing request handler. It is a simple wrapper around
WhAjaj.Connector.prototype.sendImpl(), which just normalizes the
connection options for sendImpl() and makes sure that
opt.beforeSend() is (possibly) called.
The request parameter must either be false/null/empty or a
fully-populated JSON-able request object (which will be sent as
unencoded application/json text), depending on the type of
request being made. It is never semantically legal (in this API)
for request to be a string/number/true/array value. As a rule,
only POST requests use the request data. GET requests should
encode their data in opt.url or opt.urlParam (see below).
opt must contain the network-related parameters for the request.
Paramters _not_ set in opt are pulled from this.options or
WhAjaj.Connector.options.ajax (in that order, using the first
value it finds). Thus the set of connection-level options used
for the request are a superset of those various sources.
The "normalized" (or "superimposed") opt object's URL may be
modified before the request is sent, as follows:
if opt.urlParam is a string then it is assumed to be properly
URL-encoded parameters and is appended to the opt.url. If it is
an Object then it is assumed to be a one-dimensional set of
key/value pairs with simple values (numbers, strings, booleans,
null, and NOT objects/arrays). The keys/values are URL-encoded
and appended to the URL.
The beforeSend() callback (see below) can modify the options
object before the request attempt is made.
The callbacks in the normalized opt object will be triggered as
follows (if they are set to Function values):
- beforeSend(request,opt) will be called before any network
processing starts. If beforeSend() throws then no other
callbacks are triggered and this function propagates the
exception. This function is passed normalized connection options
as its second parameter, and changes this function makes to that
object _will_ be used for the pending connection attempt.
- onError(request,opt) will be called if a connection to the
back-end cannot be established. It will be passed the original
request object (which might be null, depending on the request
type) and the normalized options object. In the error case, the
opt object passed to onError() "should" have a property called
"errorMessage" which contains a description of the problem.
- onError(request,opt) will also be called if connection
succeeds but the response is not JSON data.
- onResponse(response,request) will be called if the response
returns JSON data. That data might hold an error response code -
clients need to check for that. It is passed the response object
(a plain object) and the original request object.
- afterSend(request,opt) will be called directly after the
AJAX request is finished, before onError() or onResonse() are
called. Possible TODO: we explicitly do NOT pass the response to
this function in order to keep the line between the responsibilities
of the various callback clear (otherwise this could be used the same
as onResponse()). In practice it would sometimes be useful have the
response passed to this function, mainly for logging/debugging
................................................................................
{
if( !WhAjaj.isFunction(this.sendImpl) )
{
throw new Error("This object has no sendImpl() member function! I don't know how to send the request!");
}
var ex = false;
var av = Array.prototype.slice.apply( arguments, [0] );
/**
FIXME: how to handle the error, vis-a-vis- the callbacks, if
normalizeAjaxParameters() throws? It can throw if
(de)JSON-izing fails.
*/
var norm = this.normalizeAjaxParameters( WhAjaj.isObject(opt) ? opt : {} );
norm.url = WhAjaj.Connector.sendHelper.normalizeURL(norm);
if( ! request ) norm.method = 'GET';
var cb = this.callbacks || {};
if( this.callbacks && WhAjaj.isFunction(this.callbacks.beforeSend) ) {

All functionality is part of a class named WhAjaj, and that class
acts as namespace for this framework.
Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
License: Public Domain
This framework is directly derived from code originally found in
http://code.google.com/p/jsonmessage, and later in
http://whiki.wanderinghorse.net, where it contained quite a bit
of application-specific logic. It was eventually (the 3rd time i
needed it) split off into its own library to simplify inclusion
into my many mini-projects.
*/
/**
The WhAjaj function is primarily a namespace, and not intended
to called or instantiated via the 'new' operator.
*/
function WhAjaj()
{
}
/** Returns a millisecond Unix Epoch timestamp. */
................................................................................
WhAjaj.msTimestamp = function()
{
return (new Date()).getTime();
};
/** Returns a Unix Epoch timestamp (in seconds) in integer format.
Reminder to self: (1.1 %1.2) evaluates to a floating-point value
in JS, and thus this implementation is less than optimal.
*/
WhAjaj.unixTimestamp = function()
{
var ts = (new Date()).getTime();
return parseInt( ""+((ts / 1000) % ts) );
};
................................................................................
)
;
};
/**
Parses window.location.search-style string into an object
containing key/value pairs of URL arguments (already urldecoded).
If the str argument is not passed (arguments.length==0) then
window.location.search.substring(1) is used by default. If
neither str is passed in nor window exists then false is returned.
On success it returns an Object containing the key/value pairs
parsed from the string. Keys which have no value are treated
has having the boolean true value.
FIXME: for keys in the form "name[]", build an array of results,
like PHP does.
*/
WhAjaj.processUrlArgs = function(str) {
if( 0 === arguments.length ) {
if( ('undefined' === typeof window) ||
!window.location ||
!window.location.search ) return false;
else str = (''+window.location.search).substring(1);
................................................................................
};
/**
A simple wrapper around JSON.stringify(), using my own personal
preferred values for the 2nd and 3rd parameters. To globally
set its indentation level, assign WhAjaj.stringify.indent to
an integer value (0 for no intendation).
This function is intended only for human-readable output, not
generic over-the-wire JSON output (where JSON.stringify(val) will
produce smaller results).
*/
WhAjaj.stringify = function(val) {
if( ! arguments.callee.indent ) arguments.callee.indent = 4;
return JSON.stringify(val,0,arguments.callee.indent);
};
/**
Each instance of this class holds state information for making
AJAJ requests to a back-end system. While clients may use one
"requester" object per connection attempt, for connections to the
same back-end, using an instance configured for that back-end
can simplify usage. This class is designed so that the actual
connection-related details (i.e. _how_ it connects to the
back-end) may be re-implemented to use a client's preferred
connection mechanism (e.g. jQuery).
The optional opt paramater may be an object with any (or all) of
the properties documented for WhAjaj.Connector.options.ajax.
Properties set here (or later via modification of the "options"
property of this object) will be used in calls to
WhAjaj.Connector.sendRequest(), and these override (normally) any
options set in WhAjaj.Connector.options.ajax. Note that
WhAjaj.Connector.sendRequest() _also_ takes an options object,
and ones passed there will override, for purposes of that one
request, any options passed in here or defined in
WhAjaj.Connector.options.ajax. See WhAjaj.Connector.options.ajax
and WhAjaj.Connector.prototype.sendRequest() for more details
about the precedence of options.
Sample usage:
@code
// Set up common connection-level options:
var cgi = new WhAjaj.Connector({
url: '/cgi-bin/my.cgi',
timeout:10000,
onResponse(resp,req) { alert(JSON.stringify(resp,0.4)); },
onError(req,opt) {
................................................................................
onResponse(resp,req){ alert(WhAjaj.stringify(resp)); }
});
@endcode
For common request types, clients can add functions to this
object which act as wrappers for backend-specific functionality. As
a simple example:
@code
cgi.login = function(name,pw,ajajOpt) {
this.sendRequest(
{command:"json/login",
name:name,
password:pw
}, ajajOpt );
};
@endcode
TODOs:
- Caching of page-load requests, with a configurable lifetime.
- Use-cases like the above login() function are a tiny bit
problematic to implement when each request has a different URL
path (i know this from the whiki and fossil implementations).
This is partly a side-effect of design descisions made back in
the very first days of this code's life. i need to go through
and see where i can bend those conventions a bit (where it won't
break my other apps unduly).
................................................................................
WhAjaj.Connector.options = {
/**
A (meaningless) prefix to apply to WhAjaj.Connector-generated
request IDs.
*/
requestIdPrefix:'WhAjaj.Connector-',
/**
Default options for WhAjaj.Connector.sendRequest() connection
parameters. This object holds only connection-related
options and callbacks (all optional), and not options
related to the required JSON structure of any given request.
i.e. the page name used in a get-page request are not set
here but are specified as part of the request object.
These connection options are a "normalized form" of options
often found in various AJAX libraries like jQuery,
Prototype, dojo, etc. This approach allows us to swap out
the real connection-related parts by writing a simple proxy
which transforms our "normalized" form to the
backend-specific form. For examples, see the various
implementations stored in WhAjaj.Connector.sendImpls.
The following callback options are, in practice, almost
always set globally to some app-wide defaults:
- onError() to report errors using a common mechanism.
- beforeSend() to start a visual activity notification
- afterSend() to disable the visual activity notification
However, be aware that if any given WhAjaj.Connector instance is
given its own before/afterSend callback then those will
override these. Mixing shared/global and per-instance
callbacks can potentially lead to confusing results if, e.g.,
the beforeSend() and afterSend() functions have side-effects
but are not used with their proper before/after partner.
TODO: rename this to 'ajaj' (the name is historical). The
problem with renaming it is is that the word 'ajax' is
pretty prevelant in the source tree, so i can't globally
swap it out.
*/
ajax: {
/**
URL of the back-end server/CGI.
*/
url: '/some/path',
/**
Connection method. Some connection-related functions might
override any client-defined setting.
Must be one of 'GET' or 'POST'. For custom connection
implementation, it may optionally be some
implementation-specified value.
Normally the API can derive this value automatically - if the
request uses JSON data it is POSTed, else it is GETted.
*/
method:'GET',
/**
A hint whether to run the operation asynchronously or
not. Not all concrete WhAjaj.Connector.sendImpl()
implementations can support this. Interestingly, at
least one popular AJAX toolkit does not document
supporting _synchronous_ AJAX operations. All common
browser-side implementations support async operation, but
non-browser implementations might not.
*/
asynchronous:true,
/**
A HTTP authentication login name for the AJAX
connection. Not all concrete WhAjaj.Connector.sendImpl()
implementations can support this.
*/
loginName:undefined,
/**
An HTTP authentication login password for the AJAJ
connection. Not all concrete WhAjaj.Connector.sendImpl()
implementations can support this.
*/
loginPassword:undefined,
/**
A connection timeout, in milliseconds, for establishing
an AJAJ connection. Not all concrete
WhAjaj.Connector.sendImpl() implementations can support this.
*/
timeout:10000,
/**
If an AJAJ request receives JSON data from the back-end,
that data is passed as a plain Object as the response
................................................................................
ignore it (only those which need a way to map specific
requests to responses will need it). The 3rd parameter
is the same as the 'this' object for the context of the
callback, but is provided because the instance-level
callbacks (set in (WhAjaj.Connector instance).callbacks,
require it in some cases (because their 'this' is
different!).
Note that the response might contain error information
which comes from the back-end. The difference between
this error info and the info passed to the onError()
callback is that this data indicates an
application-level error, whereas onError() is used to
report connection-level problems or when the backend
produces non-JSON data (which, when not in jsonp mode,
is unexpected and is as fatal to the request as a
connection error).
*/
onResponse: function(response, request, opt){},
/**
If an AJAX request fails to establish a connection or it
receives non-JSON data from the back-end, this function
is called (e.g. timeout error or host name not
resolvable). It is passed the originating request and the
"normalized" connection parameters used for that
request. The connectOpt object "should" (or "might")
have an "errorMessage" property which describes the
nature of the problem.
Clients will almost always want to replace the default
implementation with something which integrates into
their application.
*/
onError: function(request, connectOpt)
{
alert('AJAJ request failed:\n'
+'Connection information:\n'
+JSON.stringify(connectOpt,0,4)
);
},
/**
Called before each connection attempt is made. Clients
can use this to, e.g., enable a visual "network activity
notification" for the user. It is passed the original
request object and the normalized connection parameters
for the request. If this function changes opt, those
changes _are_ applied to the subsequent request. If this
function throws, neither the onError() nor afterSend()
callbacks are triggered and WhAjaj.Connector.sendImpl()
propagates the exception back to the caller.
*/
beforeSend: function(request,opt){},
/**
Called after an AJAJ connection attempt completes,
regardless of success or failure. Passed the same
parameters as beforeSend() (see that function for
details).
Here's an example of setting up a visual notification on
ajax operations using jQuery (but it's also easy to do
without jQuery as well):
@code
function startAjaxNotif(req,opt) {
var me = arguments.callee;
var c = ++me.ajaxCount;
me.element.text( c + " pending AJAX operation(s)..." );
if( 1 == c ) me.element.stop().fadeIn();
}
startAjaxNotif.ajaxCount = 0.
startAjaxNotif.element = jQuery('#whikiAjaxNotification');
function endAjaxNotif() {
var c = --startAjaxNotif.ajaxCount;
startAjaxNotif.element.text( c+" pending AJAX operation(s)..." );
if( 0 == c ) startAjaxNotif.element.stop().fadeOut();
}
@endcode
Set the beforeSend/afterSend properties to those
functions to enable the notifications by default.
*/
afterSend: function(request,opt){},
/**
If jsonp is a string then the WhAjaj-internal response
handling code ASSUMES that the response contains a JSONP-style
construct and eval()s it after afterSend() but before onResponse().
In this case, onResponse() will get a string value for the response
instead of a response object parsed from JSON.
*/
jsonp:undefined,
/**
Don't use yet. Planned future option.
*/
propagateExceptions:false
}
................................................................................
else v = this.options[key];
if( undefined !== v ) return v;
else v = WhAjaj.Connector.options.ajax[key];
return v;
};
/**
Returns a unique string on each call containing a generic
reandom request identifier string. This is not used by the core
API but can be used by client code to generate unique IDs for
each request (if needed).
The exact format is unspecified and may change in the future.
Request IDs can be used by clients to "match up" responses to
specific requests if needed. In practice, however, they are
seldom, if ever, needed. When passing several concurrent
requests through the same response callback, it might be useful
for some clients to be able to distinguish, possibly re-routing
them through other handlers based on the originating request type.
If this.options.requestIdPrefix or
WhAjaj.Connector.options.requestIdPrefix is set then that text
is prefixed to the returned string.
*/
WhAjaj.Connector.prototype.generateRequestId = function()
{
if( undefined === arguments.callee.sequence )
{
................................................................................
if( ! opt.hasOwnProperty(k) ) continue /* proactive Prototype kludge! */;
this.options[k] = opt[k];
}
return this.options;
};
/**
An internal helper object which holds several functions intended
to simplify the creation of concrete communication channel
implementations for WhAjaj.Connector.sendImpl(). These operations
take care of some of the more error-prone parts of ensuring that
onResponse(), onError(), etc. callbacks are called consistently
using the same rules.
*/
WhAjaj.Connector.sendHelper = {
/**
opt is assumed to be a normalized set of
WhAjaj.Connector.sendRequest() options. This function
creates a url by concatenating opt.url and some form of
opt.urlParam.
If opt.urlParam is an object or string then it is appended
to the url. An object is assumed to be a one-dimensional set
of simple (urlencodable) key/value pairs, and not larger
data structures. A string value is assumed to be a
well-formed, urlencoded set of key/value pairs separated by
'&' characters.
The new/normalized URL is returned (opt is not modified). If
opt.urlParam is not set then opt.url is returned (or an
empty string if opt.url is itself a false value).
TODO: if opt is-a Object and any key points to an array,
build up a list of keys in the form "keyname[]". We could
arguably encode sub-objects like "keyname[subkey]=...", but
i don't know if that's conventions-compatible with other
frameworks.
*/
normalizeURL: function(opt) {
var u = opt.url || '';
if( opt.urlParam ) {
var addQ = (u.indexOf('?') >= 0) ? false : true;
var addA = addQ ? false : ((u.indexOf('&')>=0) ? true : false);
................................................................................
tail = opt.urlParam;
}
u = u + (addQ ? '?' : '') + (addA ? '&' : '') + tail;
}
return u;
},
/**
Should be called by WhAjaj.Connector.sendImpl()
implementations after a response has come back. This
function takes care of most of ensuring that framework-level
conventions involving WhAjaj.Connector.options.ajax
properties are followed.
The request argument must be the original request passed to
the sendImpl() function. It may legally be null for GET requests.
The opt object should be the normalized AJAX options used
for the connection.
The resp argument may be either a plain Object or a string
(in which case it is assumed to be JSON).
The 'this' object for this call MUST be a WhAjaj.Connector
instance in order for callback processing to work properly.
This function takes care of the following:
- Calling opt.afterSend()
- If resp is a string, de-JSON-izing it to an object.
- Calling opt.onResponse()
- Calling opt.onError() in several common (potential) error
cases.
- If resp is-a String and opt.jsonp then resp is assumed to be
a JSONP-form construct and is eval()d BEFORE opt.onResponse()
is called. It is arguable to eval() it first, but the logic
integrates better with the non-jsonp handler.
The sendImpl() should return immediately after calling this.
The sendImpl() must call only one of onSendSuccess() or
onSendError(). It must call one of them or it must implement
its own response/error handling, which is not recommended
because getting the documented semantics of the
onError/onResponse/afterSend handling correct can be tedious.
*/
onSendSuccess:function(request,resp,opt) {
var cb = this.callbacks || {};
if( WhAjaj.isFunction(cb.afterSend) ) {
try {cb.afterSend( request, opt );}
catch(e){}
................................................................................
},
/**
Should be called by sendImpl() implementations after a response
has failed to connect (e.g. could not resolve host or timeout
reached). This function takes care of most of ensuring that
framework-level conventions involving WhAjaj.Connector.options.ajax
properties are followed.
The request argument must be the original request passed to
the sendImpl() function. It may legally be null for GET
requests.
The 'this' object for this call MUST be a WhAjaj.Connector
instance in order for callback processing to work properly.
The opt object should be the normalized AJAX options used
for the connection. By convention, the caller of this
function "should" set opt.errorMessage to contain a
human-readable description of the error.
The sendImpl() should return immediately after calling this. The
return value from this function is unspecified.
*/
onSendError: function(request,opt) {
var cb = this.callbacks || {};
if( WhAjaj.isFunction(cb.afterSend) ) {
try {cb.afterSend( request, opt );}
................................................................................
try {opt.onError( request, opt );}
catch(e) {/*ignore*/}
}
}
};
/**
WhAjaj.Connector.sendImpls holds several concrete
implementations of WhAjaj.Connector.prototype.sendImpl(). To use
a specific implementation by default assign
WhAjaj.Connector.prototype.sendImpl to one of these functions.
The functions defined here require that the 'this' object be-a
WhAjaj.Connector instance.
Historical notes:
a) We once had an implementation based on Prototype, but that
library just pisses me off (they change base-most types'
prototypes, introducing side-effects in client code which
doesn't even use Prototype). The Prototype version at the time
had a serious toJSON() bug which caused empty arrays to
serialize as the string "[]", which broke a bunch of my code.
(That has been fixed in the mean time, but i don't use
Prototype.)
b) We once had an implementation for the dojo library,
If/when the time comes to add Prototype/dojo support, we simply
need to port:
http://code.google.com/p/jsonmessage/source/browse/trunk/lib/JSONMessage/JSONMessage.inc.js
(search that file for "dojo" and "Prototype") to this tree. That
code is this code's generic grandfather and they are still very
similar, so a port is trivial.
*/
WhAjaj.Connector.sendImpls = {
/**
This is a concrete implementation of
WhAjaj.Connector.prototype.sendImpl() which uses the
environment's native XMLHttpRequest class to send whiki
requests and fetch the responses.
The only argument must be a connection properties object, as
constructed by WhAjaj.Connector.normalizeAjaxParameters().
If window.firebug is set then window.firebug.watchXHR() is
called to enable monitoring of the XMLHttpRequest object.
This implementation honors the loginName and loginPassword
connection parameters.
Returns the XMLHttpRequest object.
This implementation requires that the 'this' object be-a
WhAjaj.Connector.
This implementation uses setTimeout() to implement the
timeout support, and thus the JS engine must provide that
functionality.
*/
XMLHttpRequest: function(request, args)
{
var json = WhAjaj.isObject(request) ? JSON.stringify(request) : request;
var xhr = new XMLHttpRequest();
var startTime = (new Date()).getTime();
................................................................................
{
args.errorMessage = e.toString();
WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
return undefined;
}
}/*XMLHttpRequest()*/,
/**
This is a concrete implementation of
WhAjaj.Connector.prototype.sendImpl() which uses the jQuery
AJAX API to send requests and fetch the responses.
The first argument may be either null/false, an Object
containing toJSON-able data to post to the back-end, or such an
object in JSON string form.
The second argument must be a connection properties object, as
constructed by WhAjaj.Connector.normalizeAjaxParameters().
If window.firebug is set then window.firebug.watchXHR() is
called to enable monitoring of the XMLHttpRequest object.
This implementation honors the loginName and loginPassword
connection parameters.
Returns the XMLHttpRequest object.
This implementation requires that the 'this' object be-a
WhAjaj.Connector.
*/
jQuery:function(request,args)
{
var data = request || undefined;
var whself = this;
if( data ) {
................................................................................
{
args.errorMessage = e.toString();
WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
return undefined;
}
}/*jQuery()*/,
/**
This is a concrete implementation of
WhAjaj.Connector.prototype.sendImpl() which uses the rhino
Java API to send requests and fetch the responses.
Limitations vis-a-vis the interface:
- timeouts are not supported.
- asynchronous mode is not supported because implementing it
................................................................................
json = json.join('');
//print("READ IN JSON: "+json);
WhAjaj.Connector.sendHelper.onSendSuccess.apply( self, [request, json, args] );
}/*rhino*/
};
/**
An internal function which takes an object containing properties
for a WhAjaj.Connector network request. This function creates a new
object containing a superset of the properties from:
a) opt
b) this.options
c) WhAjaj.Connector.options.ajax
in that order, using the first one it finds.
All non-function properties are _deeply_ copied via JSON cloning
in order to prevent accidental "cross-request pollenation" (been
there, done that). Functions cannot be cloned and are simply
copied by reference.
This function throws if JSON-copying one of the options fails
(e.g. due to cyclic data structures).
Reminder to self: this function does not "normalize" opt.urlParam
by encoding it into opt.url, mainly for historical reasons, but
also because that behaviour was specifically undesirable in this
code's genetic father.
*/
WhAjaj.Connector.prototype.normalizeAjaxParameters = function (opt)
{
................................................................................
cp( this.options );
cp( WhAjaj.Connector.options.ajax );
// no, not here: rc.url = WhAjaj.Connector.sendHelper.normalizeURL(rc);
return rc;
};
/**
This is the generic interface for making calls to a back-end
JSON-producing request handler. It is a simple wrapper around
WhAjaj.Connector.prototype.sendImpl(), which just normalizes the
connection options for sendImpl() and makes sure that
opt.beforeSend() is (possibly) called.
The request parameter must either be false/null/empty or a
fully-populated JSON-able request object (which will be sent as
unencoded application/json text), depending on the type of
request being made. It is never semantically legal (in this API)
for request to be a string/number/true/array value. As a rule,
only POST requests use the request data. GET requests should
encode their data in opt.url or opt.urlParam (see below).
opt must contain the network-related parameters for the request.
Paramters _not_ set in opt are pulled from this.options or
WhAjaj.Connector.options.ajax (in that order, using the first
value it finds). Thus the set of connection-level options used
for the request are a superset of those various sources.
The "normalized" (or "superimposed") opt object's URL may be
modified before the request is sent, as follows:
if opt.urlParam is a string then it is assumed to be properly
URL-encoded parameters and is appended to the opt.url. If it is
an Object then it is assumed to be a one-dimensional set of
key/value pairs with simple values (numbers, strings, booleans,
null, and NOT objects/arrays). The keys/values are URL-encoded
and appended to the URL.
The beforeSend() callback (see below) can modify the options
object before the request attempt is made.
The callbacks in the normalized opt object will be triggered as
follows (if they are set to Function values):
- beforeSend(request,opt) will be called before any network
processing starts. If beforeSend() throws then no other
callbacks are triggered and this function propagates the
exception. This function is passed normalized connection options
as its second parameter, and changes this function makes to that
object _will_ be used for the pending connection attempt.
- onError(request,opt) will be called if a connection to the
back-end cannot be established. It will be passed the original
request object (which might be null, depending on the request
type) and the normalized options object. In the error case, the
opt object passed to onError() "should" have a property called
"errorMessage" which contains a description of the problem.
- onError(request,opt) will also be called if connection
succeeds but the response is not JSON data.
- onResponse(response,request) will be called if the response
returns JSON data. That data might hold an error response code -
clients need to check for that. It is passed the response object
(a plain object) and the original request object.
- afterSend(request,opt) will be called directly after the
AJAX request is finished, before onError() or onResonse() are
called. Possible TODO: we explicitly do NOT pass the response to
this function in order to keep the line between the responsibilities
of the various callback clear (otherwise this could be used the same
as onResponse()). In practice it would sometimes be useful have the
response passed to this function, mainly for logging/debugging
................................................................................
{
if( !WhAjaj.isFunction(this.sendImpl) )
{
throw new Error("This object has no sendImpl() member function! I don't know how to send the request!");
}
var ex = false;
var av = Array.prototype.slice.apply( arguments, [0] );
/**
FIXME: how to handle the error, vis-a-vis- the callbacks, if
normalizeAjaxParameters() throws? It can throw if
(de)JSON-izing fails.
*/
var norm = this.normalizeAjaxParameters( WhAjaj.isObject(opt) ? opt : {} );
norm.url = WhAjaj.Connector.sendHelper.normalizeURL(norm);
if( ! request ) norm.method = 'GET';
var cb = this.callbacks || {};
if( this.callbacks && WhAjaj.isFunction(this.callbacks.beforeSend) ) {

}
/* Commit */
db_end_transaction(0);
/* Do an autosync push, if requested */
if( !isPrivate ) autosync_loop(SYNC_PUSH, db_get_int("autosync-tries",1),0);
}
#if INTERFACE
/*
** Allows bits in the mBplqFlags parameter to branch_prepare_list_query().
*/
#define BRL_CLOSED_ONLY 0x001 /* Show only closed branches */
#define BRL_OPEN_ONLY 0x002 /* Show only open branches */
#define BRL_BOTH 0x003 /* Show both open and closed branches */
#define BRL_OPEN_CLOSED_MASK 0x003
#define BRL_MTIME 0x004 /* Include lastest check-in time */
#define BRL_ORDERBY_MTIME 0x008 /* Sort by MTIME. (otherwise sort by name)*/
#endif /* INTERFACE */
/*
** Prepare a query that will list branches.
**
** If (which<0) then the query pulls only closed branches. If
................................................................................
** Create a new branch BRANCH-NAME off of check-in BASIS.
** Supported options for this subcommand include:
** --private branch is private (i.e., remains local)
** --bgcolor COLOR use COLOR instead of automatic background
** --nosign do not sign contents on this branch
** --date-override DATE DATE to use instead of 'now'
** --user-override USER USER to use instead of the current default
**** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in** year-month-day form, it may be truncated, the "T" may be** replaced by a space, and it may also name a timezone offset** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward).** Either no timezone suffix or "Z" means UTC.
**
** %fossil branch list ?-a|--all|-c|--closed?
** %fossil branch ls ?-a|--all|-c|--closed?
**
** List all branches. Use -a or --all to list all branches and
** -c or --closed to list all closed branches. The default is to
** show only open branches.

/*
** SQL code used to initialize the schema of a bundle.
**
** The bblob.delta field can be an integer, a text string, or NULL.
** If an integer, then the corresponding blobid is the delta basis.
** If a text string, then that string is a SHA1 hash for the delta
** basis, which is presumably in the master repository. If NULL, then
** data contains contain without delta compression.
*/
static const char zBundleInit[] =
@ CREATE TABLE IF NOT EXISTS "%w".bconfig(
@ bcname TEXT,
@ bcvalue ANY
@ );
@ CREATE TABLE IF NOT EXISTS "%w".bblob(
................................................................................
db_multi_exec(
"INSERT INTO bconfig(bcname,bcvalue)"
" VALUES('mtime',datetime('now'));"
);
db_multi_exec(
"INSERT INTO bconfig(bcname,bcvalue)"
" SELECT name, value FROM config"
" WHERE name IN ('project-code');"
);
/* Directly copy content from the repository into the bundle as long
** as the repository content is a delta from some other artifact that
** is also in the bundle.
*/
db_multi_exec(
................................................................................
deltaFrom = db_int(0,
"SELECT max(fid) FROM mlink"
" WHERE fnid=(SELECT fnid FROM mlink WHERE fid=%d)"
" AND fid<%d", rid, mnToBundle);
}
}
/* Try to insert the insert the artifact as a delta
*/
if( deltaFrom ){
Blob basis, delta;
content_get(deltaFrom, &basis);
blob_delta_create(&basis, &content, &delta);
if( blob_size(&delta)>0.9*blob_size(&content) ){
deltaFrom = 0;
................................................................................
** any check-ins that are descendants of check-ins already in the bundle,
** and any tags that apply to artifacts in the bundle.
**
** fossil bundle import BUNDLE ?--publish?
**
** Import all content from BUNDLE into the repository. By default, the
** imported files are private and will not sync. Use the --publish
** option makes the import public.
**
** fossil bundle ls BUNDLE
**
** List the contents of BUNDLE on standard output
**
** fossil bundle purge BUNDLE
**

/*
** SQL code used to initialize the schema of a bundle.
**
** The bblob.delta field can be an integer, a text string, or NULL.
** If an integer, then the corresponding blobid is the delta basis.
** If a text string, then that string is a SHA1 hash for the delta
** basis, which is presumably in the master repository. If NULL, then
** data contains content without delta compression.
*/
static const char zBundleInit[] =
@ CREATE TABLE IF NOT EXISTS "%w".bconfig(
@ bcname TEXT,
@ bcvalue ANY
@ );
@ CREATE TABLE IF NOT EXISTS "%w".bblob(
................................................................................
db_multi_exec(
"INSERT INTO bconfig(bcname,bcvalue)"
" VALUES('mtime',datetime('now'));"
);
db_multi_exec(
"INSERT INTO bconfig(bcname,bcvalue)"
" SELECT name, value FROM config"
" WHERE name IN ('project-code','parent-project-code');"
);
/* Directly copy content from the repository into the bundle as long
** as the repository content is a delta from some other artifact that
** is also in the bundle.
*/
db_multi_exec(
................................................................................
deltaFrom = db_int(0,
"SELECT max(fid) FROM mlink"
" WHERE fnid=(SELECT fnid FROM mlink WHERE fid=%d)"
" AND fid<%d", rid, mnToBundle);
}
}
/* Try to insert the artifact as a delta
*/
if( deltaFrom ){
Blob basis, delta;
content_get(deltaFrom, &basis);
blob_delta_create(&basis, &content, &delta);
if( blob_size(&delta)>0.9*blob_size(&content) ){
deltaFrom = 0;
................................................................................
** any check-ins that are descendants of check-ins already in the bundle,
** and any tags that apply to artifacts in the bundle.
**
** fossil bundle import BUNDLE ?--publish?
**
** Import all content from BUNDLE into the repository. By default, the
** imported files are private and will not sync. Use the --publish
** option to make the import public.
**
** fossil bundle ls BUNDLE
**
** List the contents of BUNDLE on standard output
**
** fossil bundle purge BUNDLE
**

files change, the entire program must be recompiled.
It also happens that those important .h files tend to be the ones that
change most frequently.
This means that the entire program must be recompiled frequently,
leading to a lengthy modify-compile-test cycle and a corresponding
decrease in programmer productivity.
<p><li>
The C programming language requires that declarations depending upon
each other must occur in a particular order.
In a program with complex, interwoven data structures, the correct
declaration order can become very difficult to determine manually,
especially when the declarations involved are spread out over several
files.
</ol>
</p>
<a name="H0004"></a>
<h3>1.2 The Makeheaders Solution</h3>
<p>
The makeheaders program is designed to ameliorate the problems associated
with the traditional C programming model by automatically generating
the interface information in the .h files from
interface information contained in other .h files and
from implementation information in the .c files.
When the makeheaders program is run, it scans the source
files for a project,
then generates a series of new .h files, one for each .c file.
The generated .h files contain exactly those declarations required by the
corresponding .c files, no more and no less.
................................................................................
a problem.
Simply rerun makeheaders to resynchronize everything.
<p><li>
The generated .h file contains the minimal set of declarations needed
by the .c file.
This means that when something changes, a minimal amount of recompilation
is required to produce an updated executable.
Experience has shown that this gives a dramatic improvement
in programmer productivity by facilitating a rapid modify-compile-test
cycle during development.
<p><li>
The makeheaders program automatically sorts declarations into the
correct order, completely eliminating the wearisome and error-prone
task of sorting declarations by hand.
</ol>
................................................................................
but manually entered .h files
that contain structure declarations and so forth will be scanned and
the declarations will be copied into the generated .h files as
appropriate.
But if makeheaders sees that the .h file that it has generated is no
different from the .h file it generated last time, it doesn't update
the file.
This prevents the corresponding .c files from having to
be needlessly recompiled.
</p>
<p>
There are several options to the makeheaders program that can
be used to alter its behavior.
The default behavior is to write a single .h file for each .c file and
................................................................................
In this example, makeheaders will scan the three files named
``alpha.c'',
``beta.c'' and
``gamma.c''
but because of the colon on the end of third filename
it will only generate headers for the first two files.
Unfortunately,
it is not possible to get makeheaders to process any file whose
name contains a colon.
</p>
<p>
In a large project, the length of the command line for makeheaders
can become very long.
If the operating system doesn't support long command lines
................................................................................
Such prototypes are normally omitted.
</p>
<p>
Finally, makeheaders also includes a ``-doc'' option.
This command line option prevents makeheaders from generating any
headers at all.
Instead, makeheaders will write to standard output
information about every definition and declaration that it encounters
in its scan of source files.
The information output includes the type of the definition or
declaration and any comment that preceeds the definition or
declaration.
The output is in a format that can be easily parsed, and is
intended to be read by another program that will generate
................................................................................
<a name="H0007"></a>
<h3>3.1 The Basic Setup</h3>
<p>
The simpliest way to use makeheaders is to put all definitions in
one or more .c files and all structure and type declarations in
separate .h files.
The only restriction is that you should take care to chose basenames
for your .h files that are different from the basenames for you
.c files.
Recall that if your .c file is named (for example) ``alpha.c''
makeheaders will attempt to generate a corresponding header file
named ``alpha.h''.
For that reason, you don't want to use that name for
any of the .h files you write since that will prevent makeheaders
................................................................................
<pre>
makeheaders *.[ch]
</pre>
The makeheaders program will scan all of the .c files and all of the
manually written .h files and then automatically generate .h files
corresponding to all .c files.
</p>
<p>
Note that
the wildcard expression used in the above example,
``<code>*.[ch]</code>'',
will expand to include all .h files in the current directory, both
those entered manually be the programmer and others generated automatically
by a prior run of makeheaders.
But that is not a problem.
The makeheaders program will recognize and ignore any files it
has previously generated that show up on its input list.
</p>
<a name="H0008"></a>
<h3>3.2 What Declarations Get Copied</h3>
<p>
................................................................................
declaration of that variable is placed in the header of every
.c file that uses the variable.
</p>
<p><li>
When a structure, union or enumeration declaration or a
function prototype or a C++ class declaration appears in a
manually produced .h file, that declaration is copied into the
automatically generated
.h files of all .c files that use the structure, union, enumeration,
function or class.
But declarations that appear in a
.c file are considered private to that .c file and are not copied into
any automatically generated files.
</p>
................................................................................
<p>
You can instruct makeheaders to treat any part of a .c file as if
it were a .h file by enclosing that part of the .c file within:
<pre>
#if INTERFACE
#endif
</pre>
Thus any structure definitions that appear after the
``#if INTERFACE'' but before the corresponding
``#endif'' are eligable to be copied into the
automatically generated
.h files of other .c files.
</p>
<p>
If you use the ``#if INTERFACE'' mechanism in a .c file,
then the generated header for that .c file will contain a line
................................................................................
<pre>
#if EXPORT_INTERFACE
#endif
</pre>
will become part of the exported interface.
The ``#if EXPORT_INTERFACE'' mechanism can be used in either
.c or .h files.
(The ``#if INTERFACE'' can also be used in both .h and .c files,
but since it's use in a .h file would be redundant, we haven't mentioned
it before.)
</p>
<a name="H0011"></a>
<h3>3.5 Local declarations processed by makeheaders</h3>
................................................................................
<p>
Sometimes it is convenient to have makeheaders sort a sequence
of private declarations into the correct order for us automatically.
Or, we could have static functions and procedures for which we would like
makeheaders to generate prototypes, but the arguments to these
functions and procedures uses private declarations.
In both of these cases, we want makeheaders to be aware of the
private declarations and copy them into the local header file,
but we don't want makeheaders to propagate the
declarations outside of the file in which they are declared.
</p>
<p>
When this situation arises, enclose the private declarations
................................................................................
file ``alpha.cpp'' will induce makeheaders to
generate a header file named ``alpha.hpp''.
</p>
<p>
Makeheaders augments class definitions by inserting prototypes to
methods were appropriate. If a method definition begins with one
of the special keywords <b>PUBLIC</b>, <b>PROTECTED</b>, or
<b>PRIVATE</b> (in upper-case to distinguish them from the regular
C++ keywords with the same meaning) then a prototype for that
method will be inserted into the class definition. If none of
these keywords appear, then the prototype is not inserted. For
example, in the following code, the constructor is not explicitly
declared in the class definition but makeheaders will add it there
because of the PUBLIC keyword that appears before the constructor
................................................................................
Perhaps these issued will be addressed in future revisions.
</p>
<a name="H0013"></a>
<h3>3.7 Conditional Compilation</h3>
<p>
The makeheaders program understands and tracks the conditional
compilation constructs in the source code files it scans.
Hence, if the following code appears in a source file
<pre>
#ifdef UNIX
# define WORKS_WELL 1
#else
# define WORKS_WELL 0
................................................................................
as well as Cygwin32 and MSVC 5.0 for Win32.
</p>
<a name="H0017"></a>
<h2>6.0 Summary And Conclusion</h2>
<p>
The makeheaders program will automatically generate a minimal header file
for each of a set of C source and header files, and will
generate a composite header file for the entire source file suite,
for either internal or external use.
It can also be used as the parser in an automated program
documentation system.
</p>

files change, the entire program must be recompiled.
It also happens that those important .h files tend to be the ones that
change most frequently.
This means that the entire program must be recompiled frequently,
leading to a lengthy modify-compile-test cycle and a corresponding
decrease in programmer productivity.
<p><li>
The C programming language requires that declarations depending upon
each other must occur in a particular order.
In a program with complex, interwoven data structures, the correct
declaration order can become very difficult to determine manually,
especially when the declarations involved are spread out over several
files.
</ol>
</p>
<a name="H0004"></a>
<h3>1.2 The Makeheaders Solution</h3>
<p>
The makeheaders program is designed to ameliorate the problems associated
with the traditional C programming model by automatically generating
the interface information in the .h files from
interface information contained in other .h files and
from implementation information in the .c files.
When the makeheaders program is run, it scans the source
files for a project,
then generates a series of new .h files, one for each .c file.
The generated .h files contain exactly those declarations required by the
corresponding .c files, no more and no less.
................................................................................
a problem.
Simply rerun makeheaders to resynchronize everything.
<p><li>
The generated .h file contains the minimal set of declarations needed
by the .c file.
This means that when something changes, a minimal amount of recompilation
is required to produce an updated executable.
Experience has shown that this gives a dramatic improvement
in programmer productivity by facilitating a rapid modify-compile-test
cycle during development.
<p><li>
The makeheaders program automatically sorts declarations into the
correct order, completely eliminating the wearisome and error-prone
task of sorting declarations by hand.
</ol>
................................................................................
but manually entered .h files
that contain structure declarations and so forth will be scanned and
the declarations will be copied into the generated .h files as
appropriate.
But if makeheaders sees that the .h file that it has generated is no
different from the .h file it generated last time, it doesn't update
the file.
This prevents the corresponding .c files from having to
be needlessly recompiled.
</p>
<p>
There are several options to the makeheaders program that can
be used to alter its behavior.
The default behavior is to write a single .h file for each .c file and
................................................................................
In this example, makeheaders will scan the three files named
``alpha.c'',
``beta.c'' and
``gamma.c''
but because of the colon on the end of third filename
it will only generate headers for the first two files.
Unfortunately,
it is not possible to get makeheaders to process any file whose
name contains a colon.
</p>
<p>
In a large project, the length of the command line for makeheaders
can become very long.
If the operating system doesn't support long command lines
................................................................................
Such prototypes are normally omitted.
</p>
<p>
Finally, makeheaders also includes a ``-doc'' option.
This command line option prevents makeheaders from generating any
headers at all.
Instead, makeheaders will write to standard output
information about every definition and declaration that it encounters
in its scan of source files.
The information output includes the type of the definition or
declaration and any comment that preceeds the definition or
declaration.
The output is in a format that can be easily parsed, and is
intended to be read by another program that will generate
................................................................................
<a name="H0007"></a>
<h3>3.1 The Basic Setup</h3>
<p>
The simpliest way to use makeheaders is to put all definitions in
one or more .c files and all structure and type declarations in
separate .h files.
The only restriction is that you should take care to chose basenames
for your .h files that are different from the basenames for you
.c files.
Recall that if your .c file is named (for example) ``alpha.c''
makeheaders will attempt to generate a corresponding header file
named ``alpha.h''.
For that reason, you don't want to use that name for
any of the .h files you write since that will prevent makeheaders
................................................................................
<pre>
makeheaders *.[ch]
</pre>
The makeheaders program will scan all of the .c files and all of the
manually written .h files and then automatically generate .h files
corresponding to all .c files.
</p>
<p>
Note that
the wildcard expression used in the above example,
``<code>*.[ch]</code>'',
will expand to include all .h files in the current directory, both
those entered manually be the programmer and others generated automatically
by a prior run of makeheaders.
But that is not a problem.
The makeheaders program will recognize and ignore any files it
has previously generated that show up on its input list.
</p>
<a name="H0008"></a>
<h3>3.2 What Declarations Get Copied</h3>
<p>
................................................................................
declaration of that variable is placed in the header of every
.c file that uses the variable.
</p>
<p><li>
When a structure, union or enumeration declaration or a
function prototype or a C++ class declaration appears in a
manually produced .h file, that declaration is copied into the
automatically generated
.h files of all .c files that use the structure, union, enumeration,
function or class.
But declarations that appear in a
.c file are considered private to that .c file and are not copied into
any automatically generated files.
</p>
................................................................................
<p>
You can instruct makeheaders to treat any part of a .c file as if
it were a .h file by enclosing that part of the .c file within:
<pre>
#if INTERFACE
#endif
</pre>
Thus any structure definitions that appear after the
``#if INTERFACE'' but before the corresponding
``#endif'' are eligable to be copied into the
automatically generated
.h files of other .c files.
</p>
<p>
If you use the ``#if INTERFACE'' mechanism in a .c file,
then the generated header for that .c file will contain a line
................................................................................
<pre>
#if EXPORT_INTERFACE
#endif
</pre>
will become part of the exported interface.
The ``#if EXPORT_INTERFACE'' mechanism can be used in either
.c or .h files.
(The ``#if INTERFACE'' can also be used in both .h and .c files,
but since it's use in a .h file would be redundant, we haven't mentioned
it before.)
</p>
<a name="H0011"></a>
<h3>3.5 Local declarations processed by makeheaders</h3>
................................................................................
<p>
Sometimes it is convenient to have makeheaders sort a sequence
of private declarations into the correct order for us automatically.
Or, we could have static functions and procedures for which we would like
makeheaders to generate prototypes, but the arguments to these
functions and procedures uses private declarations.
In both of these cases, we want makeheaders to be aware of the
private declarations and copy them into the local header file,
but we don't want makeheaders to propagate the
declarations outside of the file in which they are declared.
</p>
<p>
When this situation arises, enclose the private declarations
................................................................................
file ``alpha.cpp'' will induce makeheaders to
generate a header file named ``alpha.hpp''.
</p>
<p>
Makeheaders augments class definitions by inserting prototypes to
methods were appropriate. If a method definition begins with one
of the special keywords <b>PUBLIC</b>, <b>PROTECTED</b>, or
<b>PRIVATE</b> (in upper-case to distinguish them from the regular
C++ keywords with the same meaning) then a prototype for that
method will be inserted into the class definition. If none of
these keywords appear, then the prototype is not inserted. For
example, in the following code, the constructor is not explicitly
declared in the class definition but makeheaders will add it there
because of the PUBLIC keyword that appears before the constructor
................................................................................
Perhaps these issued will be addressed in future revisions.
</p>
<a name="H0013"></a>
<h3>3.7 Conditional Compilation</h3>
<p>
The makeheaders program understands and tracks the conditional
compilation constructs in the source code files it scans.
Hence, if the following code appears in a source file
<pre>
#ifdef UNIX
# define WORKS_WELL 1
#else
# define WORKS_WELL 0
................................................................................
as well as Cygwin32 and MSVC 5.0 for Win32.
</p>
<a name="H0017"></a>
<h2>6.0 Summary And Conclusion</h2>
<p>
The makeheaders program will automatically generate a minimal header file
for each of a set of C source and header files, and will
generate a composite header file for the entire source file suite,
for either internal or external use.
It can also be used as the parser in an automated program
documentation system.
</p>

# Markdown formatting rulesIn addition to its native Wiki formatting syntax, Fossil supports Markdown syntax as specified by[John Gruber's original Markdown implementation](http://daringfireball.net/projects/markdown/).For lots of examples - not repeated here - please refer to its[syntax description](http://daringfireball.net/projects/markdown/syntax), of which the page youare reading is an extract.This page itself uses Markdown formatting.## Summary - Block elements * A **paragraph** is a group of consecutive lines. Paragraphs are separated by blank lines. * A **Header** is a line of text underlined with equal signs or hyphens, or prefixed by a number of hash marks. * **Block quotes** are blocks of text prefixed by '>'. * **Ordered list** items are prefixed by a number and a period. **Unordered list** items are prefixed by a hyphen, asterisk or plus sign. Prefix and item text are separated by whitespace. * **Code blocks** are formed by lines of text (possibly including empty lines) prefixed by at least 4 spaces or a tab. * A **horizontal rule** is a line consisting of 3 or more asterisks, hyphens or underscores, with optional whitespace between them. - Span elements * 3 types of **links** exist: - **automatic links** are URLs or email addresses enclosed in angle brackets ('<' and '>'), and are displayed as such. - **inline links** consist of the displayed link text in square brackets ('[' and ']'), followed by the link target in parentheses. - **reference links** separate _link instance_ from _link definition_. A link instance consists of the displayed link text in square brackets, followed by a link definition name in square brackets. The corresponding link definition can occur anywhere on the page, and consists of the link definition name in square brackets followed by a colon, whitespace and the link target. * **Emphasis** can be given by wrapping text in one or two asterisks or underscores - use one for HTML `<em>`, and two for `<strong>` emphasis. * A **code span** is text wrapped in backticks ('`'). * **Images** use a syntax much like inline or reference links, but with alt attribute text ('img alt=...') instead of link text, and the first pair of square brackets in an image instance prefixed by an exclamation mark. - **Inline HTML** is mostly interpreted automatically. - **Escaping** Markdown punctuation characters is done by prefixing them by a backslash ('\\').## Details### Paragraphs
To cause an explicit line break within a paragraph, use 2 or more spaces at the end of a line.Any line containing only whitespace (space or tab characters) is considered a blank line.
### Headers#### 'Setext' style headers (underlined)The number of underlining equal signs or hyphens used has no impact on the resulting header.Underlining using equal sign(s) creates a top level header (corresponding to HTML `<h1>`),while hyphen(s) create a second level header (HTML `<h2>`). Thus, only 2 levels of headerscan be made this way.#### 'Atx' style headers (hash prefixed)1 to 6 hash characters can be used to indicate header levels 1 (HTML `<h1>`) to 6 (`<h6>`).Headers may optionally be 'closed' for cosmetic reasons, by appending a whitespace and hashcharacters to the header. The number of trailing hash characters has no impact on the headerlevel.### Block quotesNot every line in a paragraph needs to be prefixed by '>' in order to make it a block quote,only the first line.Block quoted paragraphs can be nested by using multiple '>' characters as prefix.Within a block quote, Markdown formatting (e.g. lists, emphasis) still works as normal.
### ListsA list item prefix need not occur first on its line; up to 3 leading spaces are allowed(4 spaces would make a code block out of the following text).For unordered lists, asterisks, hyphens and plus signs can be used interchangeably.For ordered lists, arbitrary numbers can be used as part of an item prefix; the items will berenumbered during rendering. However, future implementations may demand that the number usedfor the first item in a list indicates an offset to be used for subsequent items.For list items spanning multiple lines, subsequent lines can be indented using an arbitrary amountof whitespace.List items will be wrapped in HTML `<p>` tags if they are separated by blank lines.A list item may span multiple paragraphs. At least the first line of each such paragraph mustbe indented using at least 4 spaces or a tab character.Block quotes within list items must have their '>' delimiters indented using 4 up to 7 spaces.Code blocks within list items need to be indented _twice_, that is, using 8 spaces or 2 tabcharacters.### Code blocksLines within a code block are rendered verbatim using HTML `<pre>` and `<code>` tags, except thatHTML punctuation characters like '<' and '&' are automatically converted to HTML entities. Thus,there is no need to explicitly escape HTML syntax within a code block.A code block runs until the first non blank line with indent less than 4 spaces or 1 tab character.Regular Markdown syntax is not processed within code blocks.
### Links#### Automatic linksWhen rendering automatic links to email addresses, HTML encoding obfuscation is used toprevent some spambots from harvesting.#### Inline linksLinks to resources on the same server can use relative paths (i.e. can start with a '/').An optional title for the link (e.g. to have mouseover text in the browser) may be given behindthe link target but within the parentheses, in single and double quotes, and separated from thelink target by whitespace.#### Reference links> Each reference link consists of
>
> - one or more _link instances_ at appropriate locations in the page text> - a single _link definition_ at an arbitrary location on the page
>
> During rendering, each link instance is resolved, and the corresponding definition is> filled in. No separate link definition clauses occur in the rendered output.>> There are 3 fields involved in link instances and definitions:>> - link text (i.e. the text that is displayed at the resulting link)> - link definition name (i.e. an unique ID binding link instances to link definition)> - link target (a target URL for the link)Multiple link instances may reference the same link definition using its link definitionname.Link definition names are case insensitive, and may contain letters, numbers, spaces andpunctuation.##### Link instanceA space may be inserted between the bracket pairs for link text and link definition name.A link instance can use an _implicit link definition name_ shortcut, in which case the linktext is used as the link definition name. The second set of brackets then remains empty, e.g.'[Google][]' ('Google' being used as both link text and link definition name).##### Link definitionThe first bracket pair containing the link definition name may be indented using up to 3 spaces.The link target may optionally be surrounded by angle brackets ('<' and '>').A link target may be followed by an optional title (e.g. to have mouseover text in the browser).This title may be enclosed in parentheses, single or double quotes.Link definitions may be split into 2 lines, with the title on the second line, arbitrarilyindented. This may be more visually pleasing when using long link targets.### EmphasisThe same character(s) used for starting the emphasis must be used to end it; don't mixasterisks and underscores.Emphasis can be used in the middle of a word. That is, there need not be whitespace on eitherside of emphasis start or end punctuation characters.### Code spansTo include a literal backtick character in a code span, use multiple backticks as opening andclosing delimiters.Whitespace may exist immediately after the opening delimiter and before the closing delimiterof a code span, to allow for code fragments starting or ending with a backtick.Within a code span - like within a code block - angle brackets and ampersands are automatically encoded to make includingHTML fragments easier.### ImagesIf necessary, HTML must be used to specify image dimensions. Markdown has no provision for this.### Inline HTMLStart and end tags ofa HTML block level construct (`<div>`, `<table>` etc) must be separated from surroundingcontext using blank lines, and must both occur at the start of a line.No extra unwanted `<p>` HTML tags are added around HTML block level tags.Markdown formatting within HTML block level tags is not processed; however, formatting withinspan level tags (e.g. `<mark>`) is processed normally.### Escaping Markdown punctuationThe following punctuation characters can be escaped using backslash: - \\ backslash - ` backtick - * asterisk - _ underscore - {} curly braces - [] square brackets - () parentheses - # hash mark - + plus sign - - minus sign (hyphen) - . dot - ! exclamation markTo render a literal backslash, use 2 backslashes ('\\\\').