createElement : (function(){
try {
var el = document.createElement(''); //MSIE memory leak according to Drip
if(el.tagName.toLowerCase() != 'div' || el.name != 'foo')
throw 'create element error';
return function(tag, attrs){
var html = '<' + tag;
for(var name in attrs)
html += ' ' + name + '="' + attrs[name] + '"';
html += '>';
if(tag.toLowerCase() != 'input')
html += ''+tag+'>';
return document.createElement(html); //'<'+tag+' name="'+name+'">'+tag+'>'
};
}
catch(err){
return function(tag, attrs){
var el = document.createElement(tag);
for(var name in attrs)
el.setAttribute(name, attrs[name]);
return el;
};
}
})(),
//Sort elements in document order (from ppk)
sortNodes : (function(){
var n = document.documentElement.firstChild;
if(n.sourceIndex){
return function (a,b){
return a.sourceIndex - b.sourceIndex;
};
}
else if(n.compareDocumentPosition){
return function (a,b){
return 3 - (a.compareDocumentPosition(b) & 6);
};
}
})(),
//Shortcut to create new list items; used by default invalid event handler in listing the errors
createLI : function(text){
var li = document.createElement('li');
li.appendChild(document.createTextNode(text));
return li;
},
//Initially inspired by Paul Sowden
ISO8601RegExp : /^(?:(\d\d\d\d)-(W(0[1-9]|[1-4]\d|5[0-2])|(0\d|1[0-2])(-(0\d|[1-2]\d|3[0-1])(T(0\d|1\d|2[0-4]):([0-5]\d)(:([0-5]\d)(\.(\d+))?)?(Z)?)?)?)|(0\d|1\d|2[0-4]):([0-5]\d)(:([0-5]\d)(\.(\d+))?)?)$/,
parseISO8601 : function (str, type) {
var d = $wf2.validateDateTimeType(str, type);
if(!d)
return null;
var date = new Date(0);
var _timePos = 8;
if(d[15]){ //Time
if(type && type != 'time') // a time date
return null;
_timePos = 15;
}
else {
date.setUTCFullYear(d[1]);
//ISO8601 Week
if(d[3]){
if(type && type != 'week')
return null;
date.setUTCDate(date.getUTCDate() + ((8 - date.getUTCDay()) % 7) + (d[3]-1)*7); //set week day and week
return date;
}
//Other date-related types
else {
date.setUTCMonth(d[4] - 1); //Month must be supplied for WF2
if(d[6])
date.setUTCDate(d[6]);
}
}
//Set time-related fields
if(d[_timePos+0]) date.setUTCHours(d[_timePos+0]);
if(d[_timePos+1]) date.setUTCMinutes(d[_timePos+1]);
if(d[_timePos+2]) date.setUTCSeconds(d[_timePos+3]);
if(d[_timePos+4]) date.setUTCMilliseconds(Math.round(Number(d[_timePos+4]) * 1000));
//Set to local time if date given, hours present and no 'Z' provided
if(d[4] && d[_timePos+0] && !d[_timePos+6])
date.setUTCMinutes(date.getUTCMinutes()+date.getTimezoneOffset());
return date;
},
validateDateTimeType : function(value, type){ //returns RegExp matches
var isValid = false;
var d = $wf2.ISO8601RegExp.exec(value); //var d = string.match(new RegExp(regexp));
if(!d || !type)
return d;
type = type.toLowerCase();
if(type == 'week') // a week date
isValid = (d[2].toString().indexOf('W') === 0); //valid if W present
else if(type == 'time') // a time date
isValid = !!d[15];
else if(type == 'month')
isValid = !d[5];
else { //a date related value
//Verify that the number of days in the month are valid
if(d[6]){
var date = new Date(d[1], d[4]-1, d[6]);
if(date.getMonth() != d[4]-1)
isValid = false;
else switch(type){
case 'date':
isValid = (d[4] && !d[7]); //valid if day of month supplied and time field not present
break;
case 'datetime':
isValid = !!d[14]; //valid if Z present
break;
case 'datetime-local':
isValid = (d[7] && !d[14]); //valid if time present and Z not provided
break;
}
}
}
return isValid ? d : null;
},
zeroPad : function(num, pad){
if(!pad)
pad = 2;
var str = num.toString();
while(str.length < pad)
str = '0' + str;
return str;
},
dateToISO8601 : function(date, type){
type = String(type).toLowerCase();
var ms = '';
if(date.getUTCMilliseconds())
ms = '.' + $wf2.zeroPad(date.getUTCMilliseconds(), 3).replace(/0+$/,'');
switch(type){
case 'date':
return date.getUTCFullYear() + '-' + $wf2.zeroPad(date.getUTCMonth()+1) + '-' + $wf2.zeroPad(date.getUTCDate());
case 'datetime-local':
return date.getFullYear() + '-' + $wf2.zeroPad(date.getMonth()+1) + '-' + $wf2.zeroPad(date.getDate()) +
'T' + $wf2.zeroPad(date.getHours()) + ':' + $wf2.zeroPad(date.getMinutes()) + ':' + $wf2.zeroPad(date.getMinutes()) + ms + 'Z';
case 'month':
return date.getUTCFullYear() + '-' + $wf2.zeroPad(date.getUTCMonth()+1);
case 'week':
var week1 = $wf2.parseISO8601(date.getUTCFullYear() + '-W01');
return date.getUTCFullYear() + '-W' + $wf2.zeroPad(((date.valueOf() - week1.valueOf()) / (7*24*60*60*1000)) + 1);
case 'time':
return $wf2.zeroPad(date.getUTCHours()) + ':' + $wf2.zeroPad(date.getUTCMinutes()) + ':' + $wf2.zeroPad(date.getUTCMinutes()) + ms;
case 'datetime':
default:
return date.getUTCFullYear() + '-' + $wf2.zeroPad(date.getUTCMonth()+1) + '-' + $wf2.zeroPad(date.getUTCDate()) +
'T' + $wf2.zeroPad(date.getUTCHours()) + ':' + $wf2.zeroPad(date.getUTCMinutes()) + ':' + $wf2.zeroPad(date.getUTCMinutes()) + ms + 'Z';
}
},
/*
* Fires an event manually.
* @author Scott Andrew - http://www.scottandrew.com/weblog/articles/cbs-events
* @author John Resig - http://ejohn.org/projects/flexible-javascript-events/
* @param {Object} obj - a javascript object.
* @param {String} evType - an event attached to the object.
* @param {Function} fn - the function that is called when the event fires.
*
*/
fireEvent: function (element, event, options){
if(!element) {
return;
}
if (document.createEventObject){
return element.fireEvent('on' + event, $wf2.globalEvent);
} else{
// dispatch for firefox + others
$wf2.globalEvent.initEvent(event, true, true); // event type,bubbling,cancelable
return !element.dispatchEvent($wf2.globalEvent);
}
},
//Emulation of DOMException
DOMException : function(code){
var message = 'DOMException: ';
switch(code){
case 1: message += 'INDEX_SIZE_ERR'; break;
case 9: message += 'NOT_SUPPORTED_ERR'; break;
case 11: message += 'INVALID_STATE_ERR'; break;
case 12: message += 'SYNTAX_ERR'; break;
case 13: message += 'INVALID_MODIFICATION_ERR'; break;
}
var err = new Error(message);
err.code = code;
err.name = 'DOMException';
//Provide error codes and messages for the exception types that are raised by WF2
err.INDEX_SIZE_ERR = 1;
err.NOT_SUPPORTED_ERR = 9;
err.INVALID_STATE_ERR = 11;
err.SYNTAX_ERR = 12;
err.INVALID_MODIFICATION_ERR = 13;
//with($wf2.DOMException.prototype){
// INDEX_SIZE_ERR = 1;
// DOMSTRING_SIZE_ERR = 2;
// HIERARCHY_REQUEST_ERR = 3;
// WRONG_DOCUMENT_ERR = 4;
// INVALID_CHARACTER_ERR = 5;
// NO_DATA_ALLOWED_ERR = 6;
// NO_MODIFICATION_ALLOWED_ERR = 7;
// NOT_FOUND_ERR = 8;
// NOT_SUPPORTED_ERR = 9;
// INUSE_ATTRIBUTE_ERR = 10;
// INVALID_STATE_ERR = 11;
// SYNTAX_ERR = 12;
// INVALID_MODIFICATION_ERR = 13;
// NAMESPACE_ERR = 14;
// INVALID_ACCESS_ERR = 15;
//};
return err;
}
}; //End $wf2 = {
/*##############################################################################################
# Section: Repetition Model Definitions
##############################################################################################*/
var RepetitionElement = {
REPETITION_NONE:0,
REPETITION_TEMPLATE:1,
REPETITION_BLOCK:2
};
var RepetitionEvent = {
//the following takes a UIEvent and adds the required properties for a RepetitionEvent
_upgradeEvent : function(){
this.initRepetitionEvent = RepetitionEvent.initRepetitionEvent;
this.initRepetitionEventNS = RepetitionEvent.initRepetitionEventNS;
},
initRepetitionEvent : function(typeArg, canBubbleArg, cancelableArg, elementArg){
if(this.initEvent)
this.initEvent(typeArg, canBubbleArg, cancelableArg);
else { //manually initialize event (i.e., for MSIE)
this.type = typeArg;
// switch(typeArg.toLowerCase()){
// case 'added':
// this.type = 'add';
// break;
// case 'removed':
// this.type = 'remove';
// break;
// case 'moved':
// this.type = 'move';
// break;
// }
//this.srcElement = elementArg.repetitionTemplate;
//this.cancelBubble = false;
//this.cancelable = cancelableArg;
//this.returnValue = false;
if(!this.preventDefault)
this.preventDefault = function(){
this.returnValue = false;
};
if(!this.stopPropagation)
this.stopPropagation = function(){
this.cancelBubble = true;
};
}
this.element = elementArg;
this.relatedNode = elementArg; //for Opera (deprecated?)
},
initRepetitionEventNS : function(namespaceURIArg, typeArg, canBubbleArg, cancelableArg, elementArg){
throw Error("NOT IMPLEMENTED: RepetitionEvent.initRepetitionEventNS");
//this.initEvent(namespaceURIArg, typeArg, canBubbleArg, cancelableArg);
//this.element = elementArg;
//this.relatedNode = elementArg; //for Opera (deprecated?)
}
};
/*##############################################################################################
# Change the prototypes of HTML elements
##############################################################################################*/
//RepetitionElement interface must be implemented by all elements.
if(window.Element && Element.prototype){
Element.prototype.REPETITION_NONE = RepetitionElement.REPETITION_NONE;
Element.prototype.REPETITION_TEMPLATE = RepetitionElement.REPETITION_TEMPLATE;
Element.prototype.REPETITION_BLOCK = RepetitionElement.REPETITION_BLOCK;
Element.prototype.repetitionType = RepetitionElement.REPETITION_NONE;
Element.prototype.repetitionIndex = 0;
Element.prototype.repetitionTemplate = null; /*readonly*/
Element.prototype.repetitionBlocks = null; /*readonly*/
Element.prototype.repeatStart = 1;
Element.prototype.repeatMin = 0;
Element.prototype.repeatMax = Number.MAX_VALUE; //Infinity;
Element.prototype.addRepetitionBlock = $wf2.addRepetitionBlock;
Element.prototype.addRepetitionBlockByIndex = $wf2.addRepetitionBlockByIndex;
Element.prototype.moveRepetitionBlock = $wf2.moveRepetitionBlock;
Element.prototype.removeRepetitionBlock = $wf2.removeRepetitionBlock;
}
/*##############################################################################################
# Set mutation event handlers to automatically add WF2 behaviors
##############################################################################################*/
//When a form control is inserted into a document, the UA must check to see if it has [the autofocus]
// attribute set. If it does, and the control is not disabled, and it is of a type normally
// focusable in the user's operating environment, then the UA should focus the control, as if
// the control's focus() method was invoked. UAs with a viewport should also scroll the document
// enough to make the control visible, even if it is not of a type normally focusable.
//REVISE: there should be one handler for all attr events on the page.
if(document.addEventListener){
document.addEventListener('DOMNodeInsertedIntoDocument', function(evt){ //DOMNodeInserted? DOMNodeInsertedIntoDocument
if(evt.target.nodeType == 1 && evt.target.hasAttribute('autofocus')){
$wf2.initAutofocusElement(evt.target);
}
//[[UAs may ignore this attribute if the user has indicated (for example, by starting to type in a
// form control) that he does not wish focus to be changed.]]
}, false);
//NOT CURRENTLY IMPLEMENTABLE:
// Setting the DOM attribute to true must set the content attribute to the value autofocus.
// Setting the DOM attribute to false must remove the content attribute.
document.addEventListener('DOMAttrModified', function(evt){
//The autofocus DOM attribute must return true when the content attribute is present (regardless
// of its value, even if it is the empty string), and false when it is absent.
if(evt.attrName == 'autofocus'){
if(evt.attrChange == evt.ADDITION)
//evt.relatedNode.autofocus = true;
$wf2.initAutofocusElement(evt.target);
else if(evt.attrChange == evt.REMOVAL)
evt.target.autofocus = false;
}
}, false);
}
/*##################################################################################
# Execute WF2 code onDOMContentLoaded
# Some of the following code was borrowed from Dean Edwards, John Resig, et al
##################################################################################*/
(function(){
//Get the path to the library base directory
var match;
//For some reason, if not using documentElement, scriptaculous fails to load if reference to
// webforms2 script placed beforehand in Firefox
var scripts = document.documentElement.getElementsByTagName('script');
for(var i = 0; i < scripts.length; i++){
if(match = scripts[i].src.match(/^(.*)webforms2[^\/]+$/))
$wf2.libpath = match[1];
}
//The script has been included after the DOM has loaded (perhaps via Greasemonkey), so fire immediately
//NOTE: This does not work with XHTML documents in Gecko
if(document.body){
$wf2.onDOMContentLoaded();
return;
}
var eventSet = 0;
if(document.addEventListener){
//for Gecko and Opera
document.addEventListener('DOMContentLoaded', function(){
$wf2.onDOMContentLoaded();
}, false);
//for other browsers which do not support DOMContentLoaded use the following as a fallback to be called hopefully before all other onload handlers
window.addEventListener('load', function(){
$wf2.onDOMContentLoaded();
}, false);
eventSet = 1;
}
//for Safari
if (/WebKit/i.test(navigator.userAgent)) { //sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
clearInterval(_timer);
delete _timer;
$wf2.onDOMContentLoaded();
}
}, 10);
eventSet = 1;
}
//for Internet Explorer (formerly using conditional comments) //sniff
else if(/MSIE/i.test(navigator.userAgent) && !document.addEventListener && window.attachEvent){
//This following attached onload handler will attempt to be the first onload handler to be called and thus
// initiate the repetition model as early as possible if the DOMContentLoaded substitute fails.
window.attachEvent('onload', function(){
$wf2.onDOMContentLoaded();
});
//Dean Edward's first solution: http://dean.edwards.name/weblog/2005/09/busted/
//document.getElementsByTagName('*')[0].addBehavior(dirname + 'repetition-model.htc'); //use this if Behaviors are employed in 0.9
document.write("