/*	The purpose of this file is to fix a bug in Internet Explorer 6 and to make it possible
	to associate a Faces action with a button of type button. 
	In Internet Explorer the name-value pair is always submitted for each BUTTON-tag of type 'button', 'submit' or 'reset'.
	This is a bug! Furthermore the text node of the BUTTON-tag is always considered the value of the button.
	Any possible value attribute is ignored. Another bug!
	The fix is to disable all buttons of type submit and of type button and to transfer the name-value pair
	of the clicked button to a hidden field. In this way the server (Faces Servlet) will still think that
	the button was clicked. To disable all buttons also makes it impossible for the user to submit the form twice by
	mistake.
	The fix is implemented by giving each button an onclick event-handler which invokes the method
	FacesForm.submitAction. Note that the onclick handler is invoked before any possible onsubmit handler on the form!
	This also applies if the user presses ENTER to submit the form!
	The first submit button on the form is considered the default submit button. Just as the browser does.	*/

function FacesForm() {
}

FacesForm.enableFormAgainDelay = 5000;
FacesForm.hiddenActionName = "facesAction"; // you may change this value to accommodate your needs
FacesForm.dummyButtonName = "facesDummyButton";
FacesForm.disabledButtons = null; // used in disableButtons
FacesForm.listenerAdjusted = false;

/*	This method also prevents the user from clicking twice on the submit button (or clicking on another button).
	The method setHiddenField must be called before this method is invoked!
	Otherwise the name-value pair of the clicked button won't be sent to the server.	*/
FacesForm.disableButtons = function(buttons) {
	if (buttons != null) {
		var delay = parseInt(FacesForm.enableFormAgainDelay, 10);
		if (!isNaN(delay) && delay > 0) {
			FacesForm.disabledButtons = new Array();
			var button;
			for (var i = 0; i < buttons.length; i++) {
				button = buttons[i];
				if (typeof HTMLFormElement == "function" && button.form.timerId != null) {
					return; // means that Form.js has already disabled all buttons.
				}
				button.disabled = true;
				FacesForm.disabledButtons.push(button);
			}
			window.setTimeout(FacesForm.enableButtons, delay);
		}
		
	}
}

FacesForm.enableButtons = function() {
	if (FacesForm.disabledButtons != null) {
		for (var i = 0; i < FacesForm.disabledButtons.length; i++) {
			FacesForm.disabledButtons[i].disabled = false;
		}
	}
}

// when changing the name and the value of this hidden field, the server will think the button was clicked
FacesForm.setHiddenField = function(button) {
	if (button != null && button.form != null && typeof button.name == "string" && button.name != "") {
		var fieldForm = button.form;
		FacesForm.setHiddenFieldInForm(fieldForm, button.name, button.value);
	}
}

FacesForm.setHiddenFieldInForm = function(fieldForm, name, value) {
	var hiddenFieldName = (typeof FacesForm.hiddenActionName == "string" && FacesForm.hiddenActionName != "") ? FacesForm.hiddenActionName : "facesAction";
	var hiddenField = fieldForm[hiddenFieldName];
	if (hiddenField == null && document.createElement != null) {
		hiddenField = document.createElement("input");
		hiddenField.setAttribute("type", "hidden");
		fieldForm.appendChild(hiddenField);
	}
	if (hiddenField != null) {
		hiddenField.name = name;
		hiddenField.value = value;
	} else {
		alert("Your browser does not support this functionality!");
	}	
}

FacesForm.submitFormNoAction = function(fieldForm) {
	var dummyButtonName = (typeof FacesForm.dummyButtonName == "string" && FacesForm.dummyButtonName != "") ? FacesForm.hiddenActionName : "facesAction";
	var button = fieldForm[dummyButtonName];
	if (button == null && document.createElement != null) {
		//The button doesn't exist, so we create a new not visible submit button 
		button = document.createElement("input");
		button.setAttribute("type", "submit");
		button.setAttribute("style", "display: none");
		button.style.visibility="hidden";
		fieldForm.appendChild(button);
	}
	
	if (button != null) {
		FacesForm.disableButtons(fieldForm.getElementsByTagName("button"));
		button.click();
	}
	else {
		alert("Your browser does not support this functionality!");
	}
}

FacesForm.getDefaultSubmitButton = function(buttons) {
	if (buttons != null && typeof buttons.length == "number" && !isNaN(buttons.length)) {
		var button;
		for (var i = 0; i < buttons.length; i++) {
			button = buttons[i];
			if (button.type == "submit") {
				return button;
			}
		}
	}
	return null;
}

FacesForm.adjustOnSubmitListener = function(button, doValidate) {
	if (button != null && button.form != null) {
		doValidate = (typeof doValidate == "boolean") ? doValidate : true;
		if (doValidate) {
			if (!FacesForm.listenerAdjusted) {
				var oldHandler = button.form.onsubmit;
				button.form.onsubmit = function(e) {
					var ok = (typeof oldHandler == "function") ? oldHandler.apply(button.form, [e]) : true;
					if (ok) {
						FacesForm.setHiddenField(button);
						if (typeof button.tagName == "string" && button.tagName.toLowerCase() == "button" && button.form.getElementsByTagName != null) {		
							FacesForm.disableButtons(button.form.getElementsByTagName("button"));
						}
					}
					return ok;
				}
				FacesForm.listenerAdjusted = true;
			}
		} else {
			/*	Overwrite possible onsubmit handler because the immediate attribute of the Faces button tag is true.
				When immediate is true the validation phase is skipped and the action method is invoked. */
			button.form.onsubmit = function() {
				FacesForm.setHiddenField(button);
				if (typeof button.tagName == "string" && button.tagName.toLowerCase() == "button" && button.form.getElementsByTagName != null) {		
					FacesForm.disableButtons(button.form.getElementsByTagName("button"));
				}
				return true;
			}
		}
	}
}

/*	Should be invoked like this: <button ... onclick="return FacesForm.submitAction(event, this, true);">
	Is automatically rendered by the JSF button tag unless you specify your own onclick handler.
	The doValidate argument is false, if the immediate attribute on Faces button tag is true and vice versa.	*/
FacesForm.submitAction = function(button, doValidate) {
	if (button != null && typeof button.type == "string" && (button.type == "button" || button.type == "submit")) {
		FacesForm.adjustOnSubmitListener(button, doValidate);
	}
	return true;
}

FacesForm.submitActionLink = function(formId, linkId) {
	var form = document.forms[formId];
	FacesForm.setHiddenFieldInForm(form, linkId, 'dummyValue');
	FacesForm.submitFormNoAction(form);
	
	return true;
}

/*	Is to be called by a commandLink, like this <a ... onclick="return FacesForm.submitLinkAction(event, 'frmProfile', true);">
	The argument doValidate should be the opposite of the immediate attribute. */
FacesForm.submitLinkAction = function(formId, doValidate) {
	if (typeof formId == "string" && formId != "") {
		var form = document.forms[formId];
		if (form != null && form.getElementsByTagName != null) {
			doValidate = (typeof doValidate == "boolean") ? doValidate : true;
			if (doValidate) {
				var button = FacesForm.getDefaultSubmitButton(form.getElementsByTagName("button"));
				if (button != null) {
					button.name = ""; // do not fire possible action for default submit button
					if (typeof button.click != "undefined") { // typeof button.click is 'object', not 'function' in IE
						button.click(); // invokes possible onsubmit handler
					} else {
						// Safari 1.3 + 2.0 and Konqueror 3.5.5 goes here
						if (typeof Event == "function" && typeof Event.createEvent == "function") { // these functions are in Object.js
							var e = Event.createEvent();
							Event.initEvent(e, "submit");
							Event.dispatchEvent(e, "submit", button.form);
						}
					}
				}
			} else {
				form.submit(); // ignores possible onsubmit handler
			}
		}
	}
	return false;
}

/*	In Firefox and Opera submitting onchange (an onchange handler on a SELECT-tag) does NOT invoke any possible
	JSF action on a submit button. But in IE any JSF action on any button tag is fired!
	Should be invoked like this: <select ... onchange="FacesForm.submitOnchange(this, true, true);">
	Or simply: <select ... onchange="FacesForm.submitOnchange(this);">
	The second argument indicates if a possible action associated with the default submit button
	should be fired. Default is true.
	The third argument indicates if a possible onsubmit handler on the form should
	be fired. Default is true.	*/
FacesForm.submitOnchange = function(selObj, triggerSubmitAction, doValidate) {
	if (selObj != null && selObj.form != null) {
		if (typeof triggerSubmitAction != "boolean") {
			triggerSubmitAction = true;
		}
		if (typeof doValidate != "boolean") {
			doValidate = true;
		}
		var buttons = (selObj.form.getElementsByTagName != null) ? selObj.form.getElementsByTagName("button") : null;
		var submitButton = FacesForm.getDefaultSubmitButton(buttons);
		if (submitButton != null) {
			if (doValidate) {
				if (!triggerSubmitAction) {
					submitButton.name = "";
				}
				if (typeof submitButton.click != "undefined") { // typeof button.click is 'object', not 'function' in IE
					submitButton.click(); // invokes possible onsubmit handler
				} else {
					// Safari 1.3 + 2.0 and Konqueror 3.5.5 goes here
					if (typeof Event == "function" && typeof Event.createEvent == "function") { // these functions are in Object.js
						var e = Event.createEvent();
						Event.initEvent(e, "submit");
						Event.dispatchEvent(e, "submit", submitButton.form);
					}
				}
			} else {
				if (triggerSubmitAction) {
					FacesForm.setHiddenField(submitButton);
				}
				FacesForm.disableButtons(buttons);
				selObj.form.submit();
			}
		}
	}
}

/*
If your Faces form only has one INPUT-tag of type 'text' and has at least one button (of type 'button' or 'submit') associated
with a Faces action, then you should assign this method to the onkeypress event on your INPUT-tag:
<input type="text" ... onkeypress="return FacesForm.submitKeypressAction(event, this);">
This is necessary due to (another) bug in Internet Explorer.
If the user presses ENTER in the one and only INPUT-tag, then IE fails to invoke the onclick handler
of the (default) submit button (remember that the purpose of this onclick handler is to correct another bug in IE)!
If the form has more than one INPUT-tag, this is not the case.
*/
FacesForm.submitKeypressAction = function(e, field) {
	if (window.ActiveXObject != null && e != null && typeof e.type == "string" && e.type.indexOf("key") > -1 && field != null && field.form != null) {
		var key = e.keyCode;
		if (key == 13 && field.form.getElementsByTagName != null) {
			var submitButton = FacesForm.getDefaultSubmitButton(field.form.getElementsByTagName("button"));
			if (submitButton != null) {
				return FacesForm.submitAction(submitButton); // must return false to prevent submitting the form twice
			}
		}
	}
	return true;
}
