wizard.js
Summary
Zapatec Wizard.
Copyright (c) 2004-2006 by Zapatec, Inc.
http://www.zapatec.com
1700 MLK Way, Berkeley, California,
94709, U.S.A.
All rights reserved.
Zapatec.Wizard = function(args) {
this.args = args;
this.validators = Zapatec.Wizard.defaultValidators;
this._tabsEl = document.getElementById(args.tabsID);
};
Zapatec.Wizard.defaultValidators = {
"numeric.int" : function(value, range) {
var isnum = /^-?[0-9]+$/.test(value);
if (isnum) {
isnum = parseInt(value, 10);
range[0] = parseInt(range[0], 10);
range[1] = parseInt(range[1], 10);
if (isnum < range[0] || isnum > range[1])
return "Must be in [" + range[0] + ", " + range[1] + "]";
return true;
} else
return "Must be numeric, integer.";
},
"numeric.float" : function(value, range) {
var isfloat = strlen(value) > 0 && /^-?([0-9]*)\.?([0-9]*)$/.test(value);
if (isfloat) {
isfloat = parseFloat(value, 10);
range[0] = parseFloat(range[0], 10);
range[1] = parseFloat(range[1], 10);
if (isfloat < range[0] || isfloat > range[1])
return "Must be in [" + range[0] + ", " + range[1] + "]";
return true;
} else
return "Must be numeric, float.";
},
"email" : function(value) {
return /^([\w.-_]+)@([\w.-_]+)\.(\w+)$/.test(value) ?
true : "Must be an email address.";
},
"url" : function(value) {
return /^(https?|ftps?):\/\/([^\s\x22\x27(){},]+)$/i.test(value) ?
true : "Must be an URL.";
}
};
Zapatec.Wizard.prototype.init = function() {
this._setupTabs();
this.onInit();
};
Zapatec.Wizard.prototype.changeTab = function(newTab) {
var currentTab = this.getCurrentTab(), tab;
if (currentTab != newTab) {
if (!currentTab || this.onBeforeTabChange(currentTab, newTab)) {
if (currentTab) {
tab = this.tabs[currentTab];
tab.cont_el.style.display = "none";
Zapatec.Utils.removeClass(tab.tab_el, "active");
}
tab = this.tabs[newTab];
tab.cont_el.style.display = "block";
Zapatec.Utils.addClass(tab.tab_el, "active");
this.tabsArray.current = tab.index;
window.location = tab.tab_el.href;
this.onTabChange(currentTab, newTab);
if (this.btnHome)
this.btnHome.style.visibility = this.isFirstTab() ? "hidden" : "visible";
if (this.btnPrev)
this.btnPrev.style.visibility = this.isFirstTab() ? "hidden" : "visible";
if (this.btnNext)
this.btnNext.style.visibility = this.isLastTab() ? "hidden" : "visible";
if (this.btnEnd)
this.btnEnd.style.visibility = this.isLastTab() ? "hidden" : "visible";
if (this.btnAdvanced)
this._updateAdvancedButton();
if (tab.tab_el.__msh_onclick_action) {
var func = tab.tab_el.__msh_onclick_action;
if (typeof func == "string")
eval(func);
else if (typeof func == "function")
func();
}
}
}
return this;
};
Zapatec.Wizard.prototype.nextTab = function() {
if (this.tabsArray.current < this.tabsArray.length - 1)
this.changeTab(this.tabsArray[this.tabsArray.current + 1].id);
return this;
};
Zapatec.Wizard.prototype.prevTab = function() {
if (this.tabsArray.current > 0)
this.changeTab(this.tabsArray[this.tabsArray.current - 1].id);
return this;
};
Zapatec.Wizard.prototype.firstTab = function() {
this.changeTab(this.tabsArray[0].id);
};
Zapatec.Wizard.prototype.lastTab = function() {
this.changeTab(this.tabsArray[this.tabsArray.length - 1].id);
};
Zapatec.Wizard.prototype.getCurrentTab = function() {
var tab = this.tabsArray[this.tabsArray.current];
return tab ? tab.id : null;
};
Zapatec.Wizard.prototype.isFirstTab = function() {
return this.tabsArray.current == 0;
};
Zapatec.Wizard.prototype.isLastTab = function() {
return this.tabsArray.current == this.tabsArray.length - 1;
};
Zapatec.Wizard.prototype.toggleAdvanced = function() {
var
tab = this.tabs[this.getCurrentTab()],
a = tab.advanced_els,
el,
i = 0,
visible = (tab.advanced =! tab.advanced);
while (el = a[i++]) {
Zapatec.Utils.removeClass(el, "wizard-advanced");
if (!visible)
Zapatec.Utils.addClass(el, "wizard-advanced");
}
this._updateAdvancedButton();
};
Zapatec.Wizard.prototype.setupNav = function(parent) {
var div = Zapatec.Utils.createElement("div", parent || this._tabsEl.parentNode);
div.className = "navigation";
var self = this, btn;
btn = Zapatec.Utils.createElement("button", div);
btn.innerHTML = "Show advanced options";
btn.className = "btn-advanced";
btn.onclick = function() { self.toggleAdvanced(); };
this.btnAdvanced = btn;
btn = Zapatec.Utils.createElement("button", div);
btn.innerHTML = "Begin";
btn.className = "btn-begin";
btn.onclick = function() { self.firstTab(); };
this.btnHome = btn;
btn = Zapatec.Utils.createElement("button", div);
btn.innerHTML = "« <u>P</u>rev.";
btn.accessKey = "p";
btn.className = "btn-prev";
btn.onclick = function() { self.prevTab(); };
this.btnPrev = btn;
btn = Zapatec.Utils.createElement("button", div);
btn.innerHTML = "<u>N</u>ext »";
btn.accessKey = "n";
btn.className = "btn-next";
btn.onclick = function() { self.nextTab(); };
this.btnNext = btn;
btn = Zapatec.Utils.createElement("button", div);
btn.innerHTML = "Finish";
btn.className = "btn-finish";
btn.onclick = function() { self.lastTab(); };
this.btnEnd = btn;
return div;
};
Zapatec.Wizard.prototype.validate = function(value, validator, args) {
var f = this.validators[validator];
if (f)
return f(value, args, validator);
else
throw "Validator “" + validator + "” is NOT defined.";
};
Zapatec.Wizard.prototype.addCustomValidator = function(name, func) {
if (!/^[a-z0-9.]+$/i.test(name)) {
throw "Illegal validator ID: '" + name +
"'. Accepted values can only contain letters, digits and the dot sign.";
} else
this.validators[name] = func;
return this;
};
Zapatec.Wizard.prototype.addValidator = function(name, regexp, error) {
this.addCustomValidator(name, function(value) {
return regexp.test(value) ? true : error;
});
};
Zapatec.Wizard.prototype._setupTabs = function() {
var self = this;
var tabs = this._tabsEl;
Zapatec.Utils.addClass(tabs, "tabs");
var bar = document.getElementById(this.args.tabBarID);
Zapatec.Utils.addClass(bar, "tab-bar");
this.tabs = {};
this.tabsArray = [];
for (var i = tabs.firstChild; i; i = i.nextSibling) {
if (i.nodeType != 1)
continue;
var tab = {
tab_el : Zapatec.Utils.createElement("a", bar),
cont_el : i,
id : i.id,
index : this.tabsArray.length,
advanced : false,
advanced_els : []
};
tab.tab_el.href = "#" + i.id;
var tmp = Zapatec.Utils.getFirstChild(i, "label");
if (tmp)
while (tmp.firstChild)
tab.tab_el.appendChild(tmp.firstChild);
if (tmp.accessKey) {
tab.tab_el.accessKey = tmp.accessKey;
tmp.accessKey = "";
}
tab.tab_el.title = tmp.title;
tab.tab_el.__msh_onclick_action = tmp.onclick;
tmp.parentNode.removeChild(tmp);
tab.tab_el.__msh_info = tab;
tab.tab_el.onclick = function() {
self.changeTab(this.__msh_info.id);
if (typeof this.blur == "function")
this.blur();
return false;
};
if (Zapatec.is_ie)
tab.tab_el.onfocus = tab.tab_el.onclick;
this.tabsArray[this.tabsArray.length] = tab;
this.tabs[tab.id] = tab;
i.style.display = "none";
this._populateLists(tab);
}
this.tabsArray.current = -1;
var currentTab = this.tabsArray[0].id;
if (/#([^\/]+)$/.test(document.URL) && this.tabs[RegExp.$1])
currentTab = RegExp.$1;
this.changeTab(currentTab);
};
Zapatec.Wizard.prototype._populateLists = function(tab) {
var a = tab.cont_el.getElementsByTagName("*"), i = 0, el, c, self = this;
while (el = a[i++]) {
var c = el.className;
if (/(^|\s)wizard-advanced(\s|$)/i.test(c))
tab.advanced_els[tab.advanced_els.length] = el;
if (/(^|\s)validate-([^\s-]+)(-[^\s]+)?/i.test(c)) {
el.__msh_validator = RegExp.$2;
el.__msh_validator_args = RegExp.$3;
el.onblur = function(ev) {
ev || (ev = window.event);
return self._validateField(
this, this.__msh_validator,
this.__msh_validator_args, ev);
};
}
}
};
Zapatec.Wizard.prototype._validateField = function(field, validator, args, event) {
var value, tag = field.tagName.toLowerCase(), div, message;
if (typeof args != "undefined") {
args = args.replace(/^-/, '');
args = args.split(/-/);
} else
args = null;
try {
if (tag == "input" || tag == "select" || tag == "textarea") {
message = this.validate(field.value, validator, args);
if (typeof message == "boolean" && !message)
message = "This field must validate by “" + validator + "”";
if (typeof message == "string") {
div = field.__msh_message;
if (!div) {
div = field.__msh_message = Zapatec.Utils.createElement("div");
div.className = "validation-error";
field.parentNode.insertBefore(div, field.nextSibling);
}
div.innerHTML = message;
Zapatec.Utils.addClass(field, "field-error");
Zapatec.Utils.stopEvent(event);
return false;
} else {
div = field.__msh_message;
if (div) {
div.parentNode.removeChild(div);
field.__msh_message = null;
}
Zapatec.Utils.removeClass(field, "field-error");
}
} else
throw "I don't know how to validate <" + tag + "> elements.";
} catch(e) {
alert("Error: " + e);
}
};
Zapatec.Wizard.prototype._updateAdvancedButton = function(tab) {
if (this.btnAdvanced) {
if (!tab)
tab = this.tabs[this.getCurrentTab()];
this.btnAdvanced.innerHTML = tab.advanced ? "Hide advanced options" : "Show advanced options";
this.btnAdvanced.style.visibility = tab.advanced_els.length == 0 ? "hidden" : "visible";
}
};
Zapatec.Wizard._doNothing = function() { return true; };
Zapatec.Wizard.prototype.onInit = Zapatec.Wizard._doNothing;
Zapatec.Wizard.prototype.onTabChange = Zapatec.Wizard._doNothing;
Zapatec.Wizard.prototype.onBeforeTabChange = Zapatec.Wizard._doNothing;
Documentation generated by
JSDoc on Thu Aug 16 12:18:39 2007