From 17bb6a4c7a134f24891e88cdc185d46748977ae3 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 8 Mar 2010 20:52:37 +0000 Subject: [PATCH] Monotone-Parent: e3d309fa0c25170ca568f73dc1467d549a6a3209 Monotone-Revision: 9b6a87c288fd476ce2774933261d8fc081fc8334 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-03-08T20:52:37 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 17 ++ UI/MainUI/SOGoRootPage.m | 51 ++-- UI/Templates/MainUI/SOGoRootPage.wox | 5 +- UI/Templates/PreferencesUI/UIxPreferences.wox | 2 +- UI/WebServerResources/PasswordPolicy.js | 98 +++++++ UI/WebServerResources/SOGoRootPage.css | 5 +- UI/WebServerResources/SOGoRootPage.js | 242 ++++++++++++++---- UI/WebServerResources/UIxPreferences.js | 113 +------- UI/WebServerResources/generic.css | 3 +- UI/WebServerResources/generic.js | 93 ++++++- 10 files changed, 437 insertions(+), 192 deletions(-) create mode 100644 UI/WebServerResources/PasswordPolicy.js diff --git a/ChangeLog b/ChangeLog index f1ce23190..98aa702fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 2010-03-08 Wolfgang Sourdeau + * UI/WebServerResources/generic.js (createDialog): new method + designed to provide a normalized interface for creating popup + dialogs with DOM methods. + (createButton): same as above for buttons. + (SetLogMessage): new normalizing method for putting typed log + message in specified containers via DOM methods. + + * UI/WebServerResources/SOGoRootPage.js: added code for popping up + a password change dialog whenever one is required by the server. + + * UI/MainUI/SOGoRootPage.m (_responseWithLDAPPolicyError:): new + method for returning password change and login-based LDAP policy + errors. + + * UI/WebServerResources/PasswordPolicy.js: new module that handle + the password change protocol and error codes. + * UI/WebServerResources/UIxPreferences.js (onComposeMessagesTypeChange): we now do the proper widget wizardry via DOM methods to alternate between the text-based or diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m index 1ebcb1e13..a9a5b6271 100644 --- a/UI/MainUI/SOGoRootPage.m +++ b/UI/MainUI/SOGoRootPage.m @@ -111,6 +111,22 @@ } /* actions */ +- (WOResponse *) _responseWithLDAPPolicyError: (int) error +{ + WOResponse *response; + NSDictionary *jsonError; + + jsonError + = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: error] + forKey: @"LDAPPasswordPolicyError"]; + response = [self responseWithStatus: 403 + andJSONRepresentation: jsonError]; + [response setHeader: @"application/json" + forKey: @"content-type"]; + + return response; +} + - (id ) connectAction { WOResponse *response; @@ -135,11 +151,8 @@ password = [request formValueForKey: @"password"]; language = [request formValueForKey: @"language"]; - if ((b = [auth checkLogin: username - password: password - perr: &err - expire: &expire - grace: &grace]) + if ((b = [auth checkLogin: username password: password + perr: &err expire: &expire grace: &grace]) && (err == PolicyNoError || err == PolicyChangeAfterReset)) { [self logWithFormat: @"successful login for user '%@'", username]; @@ -167,7 +180,7 @@ else { [self logWithFormat: @"Login for user '%@' might not have worked - password policy: %d bound: ", username, err, b]; - + if (err == PolicyNoError) { [self logWithFormat: @"failed login for user '%@' due to wrong password", username]; @@ -180,8 +193,8 @@ { // The password MUST be changed - we need to ask for the old password and the new one here } - - response = [self responseWithStatus: 403]; + + response = [self _responseWithLDAPPolicyError: err]; } return response; @@ -418,7 +431,9 @@ SOGoPasswordPolicyError error; WOResponse *response; WORequest *request; - NSDictionary *message, *jsonError; + NSDictionary *message; + SOGoWebAuthenticator *auth; + WOCookie *authCookie; request = [context request]; message = [NSMutableDictionary dictionaryWithJSONString: [request contentAsString]]; @@ -433,17 +448,17 @@ oldPassword: password newPassword: newPassword perr: &error]) - response = [self responseWith204]; - else { - jsonError - = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: error] - forKey: @"LDAPPasswordPolicyError"]; - response = [self responseWithStatus: 403 - andJSONRepresentation: jsonError]; - [response setHeader: @"application/json" - forKey: @"content-type"]; + response = [self responseWith204]; + auth = [[WOApplication application] + authenticatorInContext: context]; + authCookie = [self _cookieWithUsername: username + andPassword: newPassword + forAuthenticator: auth]; + [response addCookie: authCookie]; } + else + response = [self _responseWithLDAPPolicyError: error]; return response; } diff --git a/UI/Templates/MainUI/SOGoRootPage.wox b/UI/Templates/MainUI/SOGoRootPage.wox index 0f1d9e953..7a3be0756 100644 --- a/UI/Templates/MainUI/SOGoRootPage.wox +++ b/UI/Templates/MainUI/SOGoRootPage.wox @@ -7,6 +7,7 @@ xmlns:const="http://www.skyrix.com/od/constant" xmlns:rsrc="OGo:url" xmlns:label="OGo:label" + const:jsFiles="PasswordPolicy.js" const:popup="YES" > diff --git a/UI/Templates/PreferencesUI/UIxPreferences.wox b/UI/Templates/PreferencesUI/UIxPreferences.wox index abcf41a22..4914dc229 100644 --- a/UI/Templates/PreferencesUI/UIxPreferences.wox +++ b/UI/Templates/PreferencesUI/UIxPreferences.wox @@ -10,7 +10,7 @@ className="UIxPageFrame" title="title" const:popup="YES" - const:jsFiles="ckeditor/ckeditor.js" + const:jsFiles="PasswordPolicy.js,ckeditor/ckeditor.js" >
diff --git a/UI/WebServerResources/PasswordPolicy.js b/UI/WebServerResources/PasswordPolicy.js new file mode 100644 index 000000000..2bed50e0a --- /dev/null +++ b/UI/WebServerResources/PasswordPolicy.js @@ -0,0 +1,98 @@ +var PolicyPasswordChangeUnsupported = -3; +var PolicyPasswordSystemUnknown = -2; +var PolicyPasswordUnknown = -1; +var PolicyPasswordExpired = 0; +var PolicyAccountLocked = 1; +var PolicyChangeAfterReset = 2; +var PolicyPasswordModNotAllowed = 3; +var PolicyMustSupplyOldPassword = 4; +var PolicyInsufficientPasswordQuality = 5; +var PolicyPasswordTooShort = 6; +var PolicyPasswordTooYoung = 7; +var PolicyPasswordInHistory = 8; +var PolicyNoError = 65535; + +function _passwordPolicyAjaxCallback(http) { + if (http.readyState == 4) { + var policy = http.callbackData; + policy.callback(http); + } +} + +function PasswordPolicy(userName, password) { + this.userName = userName; + this.password = password; +} + +PasswordPolicy.prototype = { + userName: null, + password: null, + successCallback: null, + failureCallback: null, + + setCallbacks: function(successCallback, failureCallback) { + this.successCallback = successCallback; + this.failureCallback = failureCallback; + }, + + changePassword: function (newPassword) { + var content = Object.toJSON({ userName: this.userName, + password: this.password, + newPassword: newPassword }); + var urlParts = ApplicationBaseURL.split("/"); + var url = urlParts[1] + "/so/changePassword"; + triggerAjaxRequest(url, _passwordPolicyAjaxCallback, this, + content, {"content-type": "application/json"} ); + }, + + callback: function(http) { + if (isHttpStatus204(http.status)) { + if (this.successCallback) + this.successCallback(_("The password was changed successfully.")); + } else { + if (this.failureCallback) { + var perr = PolicyPasswordUnknown; + var error = ""; + switch (http.status) { + case 403: + if (http.getResponseHeader("content-type") + == "application/json") { + var jsonResponse = http.responseText.evalJSON(false); + perr = jsonResponse["LDAPPasswordPolicyError"]; + + // Normal password change failed + if (perr == PolicyNoError) { + error = _("Password change failed"); + } else if (perr == PolicyPasswordModNotAllowed) { + error = _("Password change failed - Permission denied"); + } else if (perr == PolicyInsufficientPasswordQuality) { + error = _("Password change failed - Insufficient password quality"); + } else if (perr == PolicyPasswordTooShort) { + error = _("Password change failed - Password is too short"); + } else if (perr == PolicyPasswordTooYoung) { + error = _("Password change failed - Password is too young"); + } else if (perr == PolicyPasswordInHistory) { + error = _("Password change failed - Password is in history"); + } else { + error = _("Unhandled policy error: %{0}").formatted(perr); + perr = PolicyPasswordUnknown; + } + } else { + perr = PolicyPasswordSystemUnknown; + error = _("Unhandled error response"); + } + break; + case 404: + perr = PolicyPasswordChangeUnsupported; + error = _("Password change is not supported."); + break; + default: + perr = PolicyPasswordSystemUnknown; + error = _("Unhandled HTTP error code: %{0]").formatted(http.status); + } + this.failureCallback(perr, error); + // showPasswordMessage(error); + } + } + } +}; diff --git a/UI/WebServerResources/SOGoRootPage.css b/UI/WebServerResources/SOGoRootPage.css index bb8596c98..62392c003 100644 --- a/UI/WebServerResources/SOGoRootPage.css +++ b/UI/WebServerResources/SOGoRootPage.css @@ -111,9 +111,10 @@ IMG#progressIndicator margin-top: 20px; margin-left: 5px; } -#noCookiesErrorMessage, -#loginErrorMessage +#errorMessage { color: #f00; + width: 400px; + margin: 0px auto; text-align: center; } P.browser diff --git a/UI/WebServerResources/SOGoRootPage.js b/UI/WebServerResources/SOGoRootPage.js index 501562f4e..e1af5b2c5 100644 --- a/UI/WebServerResources/SOGoRootPage.js +++ b/UI/WebServerResources/SOGoRootPage.js @@ -1,5 +1,7 @@ /* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +var dialogs = {}; + function initLogin() { var date = new Date(); date.setTime(date.getTime() - 86400000); @@ -13,10 +15,14 @@ function initLogin() { var about = $("about"); if (about) { - about.observe("click", function(event) { $("aboutBox").show(); }); + about.observe("click", function(event) { + $("aboutBox").show(); + event.stop() }); var aboutClose = $("aboutClose"); - aboutClose.observe("click", function(event) { $("aboutBox").hide(); }); + aboutClose.observe("click", function(event) { + $("aboutBox").hide(); + event.stop() }); } var submit = $("submit"); @@ -52,8 +58,7 @@ function onLoginClick(event) { var language = $("language"); if (userName.length > 0) { - $("loginErrorMessage").hide(); - $("noCookiesErrorMessage").hide(); + SetLogMessage("errorMessage", null); this.disabled = true; startAnimation($("animation")); @@ -61,11 +66,14 @@ function onLoginClick(event) { && loginSuffix.length > 0 && !userName.endsWith(loginSuffix)) userName += loginSuffix; + var url = $("connectForm").getAttribute("action"); - var parameters = "userName=" + encodeURIComponent(userName) + - "&password=" + encodeURIComponent(password); + var parameters = ("userName=" + encodeURIComponent(userName) + + "&password=" + encodeURIComponent(password)); if (language) - parameters += (language.value == "WONoSelectionString")?"":("&language=" + language.value); + parameters += ((language.value == "WONoSelectionString") + ? "" + : ("&language=" + language.value)); /// Discarded as it seems to create a cookie for nothing. To discard // a cookie in JS, have a look here: http://www.quirksmode.org/js/cookies.html //document.cookie = ""; @@ -82,64 +90,192 @@ function onLoginClick(event) { function onLoginCallback(http) { if (http.readyState == 4) { - var noCookiesErrorMessage = $("noCookiesErrorMessage"); - var loginErrorMessage = $("loginErrorMessage"); var submitBtn = $("submit"); if (isHttpStatus204(http.status)) { // Make sure browser's cookies are enabled - var cookieExists = 0; - var ca = document.cookie.split(';'); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) == ' ') c = c.substring(1, c.length); - if (c.indexOf("0xHIGHFLYxSOGo=") == 0) { - cookieExists = 1; - break; - } - } - if (cookieExists === 0) { - loginErrorMessage.hide(); - noCookiesErrorMessage.show(); + var loginCookie = readLoginCookie(); + if (!loginCookie) { + SetLogMessage("errorMessage", _("cookiesNotEnabled")); submitBtn.disabled = false; - return false; + return; } - - // Redirect to proper page - var userName = $("userName").value; - if (typeof(loginSuffix) != "undefined" - && loginSuffix.length > 0 - && !userName.endsWith(loginSuffix)) - userName += loginSuffix; - var address = "" + window.location.href; - var baseAddress = ApplicationBaseURL + encodeURIComponent(userName); - var altBaseAddress; - if (baseAddress[0] == "/") { - var parts = address.split("/"); - var hostpart = parts[2]; - var protocol = parts[0]; - baseAddress = protocol + "//" + hostpart + baseAddress; - } - var altBaseAddress; - var parts = baseAddress.split("/"); - parts.splice(3, 0); - altBaseAddress = parts.join("/"); - var newAddress; - if ((address.startsWith(baseAddress) - || address.startsWith(altBaseAddress)) - && !address.endsWith("/logoff")) - newAddress = address; - else - newAddress = baseAddress; - window.location.href = newAddress; + redirectToUserPage(); } else { - loginErrorMessage.show(); - noCookiesErrorMessage.hide(); + if (http.status == 403 + && http.getResponseHeader("content-type") + == "application/json") { + var jsonResponse = http.responseText.evalJSON(false); + handlePasswordError(jsonResponse); + } else { + SetLogMessage("errorMessage", _("An unhandled error occurred.")); + } submitBtn.disabled = false; } } } +function redirectToUserPage() { + // Redirect to proper page + var userName = $("userName").value; + if (typeof(loginSuffix) != "undefined" + && loginSuffix.length > 0 + && !userName.endsWith(loginSuffix)) + userName += loginSuffix; + var address = "" + window.location.href; + var baseAddress = ApplicationBaseURL + encodeURIComponent(userName); + var altBaseAddress; + if (baseAddress[0] == "/") { + var parts = address.split("/"); + var hostpart = parts[2]; + var protocol = parts[0]; + baseAddress = protocol + "//" + hostpart + baseAddress; + } + var altBaseAddress; + var parts = baseAddress.split("/"); + parts.splice(3, 0); + altBaseAddress = parts.join("/"); + + var newAddress; + if ((address.startsWith(baseAddress) + || address.startsWith(altBaseAddress)) + && !address.endsWith("/logoff")) + newAddress = address; + else + newAddress = baseAddress; + window.location.href = newAddress; +} + +function handlePasswordError(jsonResponse) { + var perr = jsonResponse["LDAPPasswordPolicyError"]; + if (perr == PolicyNoError) { + SetLogMessage("errorMessage", _("Wrong username or password.")); + } else if (perr == PolicyAccountLocked) { + SetLogMessage("errorMessage", + _("Your account was locked due to too many" + + " failed attempts.")); + } else if (perr == PolicyChangeAfterReset + || perr == PolicyPasswordExpired) { + showPasswordDialog("change", createPasswordChangeDialog, 5); + } else + SetLogMessage("errorMessage", + _("Login failed due to unhandled error case: " + perr)); +} + +function showPasswordDialog(dialogType, constructor, parameters) { + var dialog = dialogs[dialogType]; + if (!dialog) { + dialog = constructor(parameters); + var form = $("connectForm"); + form.appendChild(dialog); + dialogs[dialogType] = dialog; + } + var password = $("password"); + var offsets = password.cumulativeOffset(); + dialog.show(); + var top = offsets[1] + 5; + var left = offsets[0] + password.clientWidth - dialog.clientWidth; + dialog.setStyle({ "top": top + "px", "left": left + "px"}); +} + +function createPasswordChangeDialog() { + var fields = createElement("p"); + createElement("span", "passwordError", null, null, null, fields); + + var fieldNames = [ "newPassword", "newPassword2" ]; + var fieldLabels = [ _("New password:"), _("Confirmation:") ]; + for (var i = 0; i < fieldNames.length; i++) { + var label = createElement("label", null, null, null, null, fields); + label.appendChild(document.createTextNode(fieldLabels[i])); + createElement("input", fieldNames[i], "textField", + { "name": fieldNames[i], "type": "text" }, + null, label); + createElement("br", null, null, null, null, fields); + } + + var button = createButton("passwordOKButton", _("OK"), passwordDialogOK); + button.addClassName("actionButton"); + fields.appendChild(button); + fields.appendChild(document.createTextNode(" ")); + button = createButton("passwordCancelButton", + _("Cancel"), passwordDialogCancel); + fields.appendChild(button); + + var dialog = createDialog("passwordChangeDialog", + _("Change your Password"), + _("Your password has expired, please" + +" enter a new one below:"), + fields, + "right"); + + return dialog; +} + +function passwordDialogOK(event) { + var field = $("newPassword"); + var confirmationField = $("newPassword2"); + if (field && confirmationField) { + var password = field.value; + if (password == confirmationField.value) { + if (password.length > 0) { + var userName = $("userName"); + var password = $("password"); + var policy = new PasswordPolicy(userName.value, + password.value); + policy.setCallbacks(onPasswordChangeSuccess, + onPasswordChangeFailure); + policy.changePassword(password); + } + else + SetLogMessage("passwordError", + _("Password must not be empty.")); + } + else { + SetLogMessage("passwordError", + _("The passwords do not match. Please try again.")); + field.focus(); + field.select(); + } + } + event.stop(); +} + +function onPasswordChangeSuccess() { + SetLogMessage("passwordError", _("Please wait...")); + redirectToUserPage(); +} + +function onPasswordChangeFailre(code, message) { + SetLogMessage("passwordError", message); +} + +function passwordDialogCancel(event) { + var dialog = $("passwordChangeDialog"); + dialog.hide(); + event.stop(); +} + +function createPasswordGraceDialog(tries) { + var button = createButton("graceOKButton", _("OK")); + button.observe("click", passwordGraceDialogOK); + button.addClassName("actionButton"); + + return createDialog("passwordGraceDialog", + _("Password Grace Period"), + _("You have %{0} logins remaining before your" + + " password expires. Please change your" + + " password in the preference dialog.") + .formatted(tries), + button, + "right"); +} + +function passwordGraceDialogOK(event) { + var dialog = $("passwordGraceDialog"); + dialog.hide(); + event.stop(); +} + document.observe("dom:loaded", initLogin); diff --git a/UI/WebServerResources/UIxPreferences.js b/UI/WebServerResources/UIxPreferences.js index 908bcd344..59180743f 100644 --- a/UI/WebServerResources/UIxPreferences.js +++ b/UI/WebServerResources/UIxPreferences.js @@ -536,14 +536,20 @@ function onChangePasswordClick(event) { if (field && confirmationField) { var password = field.value; if (password == confirmationField.value) { - if (password.length > 0) - changePassword(password); + if (password.length > 0) { + var loginValues = readLoginCookie(); + var policy = new PasswordPolicy(loginValues[0], + loginValues[1]); + policy.setCallbacks(onPasswordChangeSuccess, + onPasswordChangeFailure); + policy.changePassword(password); + } else - showPasswordMessage(_("Password must not be empty."), + SetLogMessage("passwordError", _("Password must not be empty."), "error"); } else { - showPasswordMessage(_("The passwords do not match." + SetLogMessage("passwordError", _("The passwords do not match." + " Please try again."), "error"); field.focus(); @@ -553,103 +559,12 @@ function onChangePasswordClick(event) { event.stop(); } -/* TODO: this method could serve as a basis for a basic text container (for - example the log console. */ -function showPasswordMessage(message, msgType) { - var para = $("passwordError"); - if (para) { - if (!msgType) - msgType = "error"; - var typeClass = msgType + "Message"; - if (!para.typeClass || para.typeClass != typeClass) { - if (para.typeClass) { - para.removeClassName(para.typeClass); - } - para.typeClass = typeClass; - para.addClassName(typeClass); - } - if (!para.message || para.message != message) { - while (para.lastChild) { - para.removeChild(para.lastChild); - } - if (message) { - var sentences = message.split("\n"); - para.appendChild(document.createTextNode(sentences[0])); - for (var i = 1; i < sentences.length; i++) { - para.appendChild(document.createElement("br")); - para.appendChild(document.createTextNode(sentences[i])); - } - para.message = message; - } - } - } +function onPasswordChangeSuccess(message) { + SetLogMessage("passwordError", message, "info"); } -function readCookie(name) { - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - for(var i=0;i < ca.length;i++) { - var c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1,c.length); - if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); - } - return null; -} - -function changePassword(newPassword) { - var loginValues = readLoginCookie(); - if (loginValues) { - var content = Object.toJSON({ userName: loginValues[0], - password: loginValues[1], - newPassword: newPassword }); - var url = ApplicationBaseURL + "../changePassword"; - triggerAjaxRequest(url, changePasswordCallback, loginValues[1], content, - {"content-type": "application/json"} ); - } -} - -function changePasswordCallback(http) { - if (http.readyState == 4) { - if (isHttpStatus204(http.status)) { - log("it worked"); - showPasswordMessage(_("The password was changed successfully."), "info"); - setLoginCookie(UserLogin, http.callbackData); - } else { - var error; - log("header: " + http.header); - switch(http.status) { - case 403: - if (http.getResponseHeader("content-type") == "application/json") { - var jsonResponse = http.responseText.evalJSON(false); - var perr = jsonResponse["LDAPPasswordPolicyError"]; - - // Normal password change failed - if (perr == 65535) { - error = _("Password change failed"); - } else if (perr == 3) { - error = _("Password change failed - Permission denied"); - } else if (perr == 5) { - error = _("Password change failed - Insufficient password quality"); - } else if (perr == 6) { - error = _("Password change failed - Password is too short"); - } else if (perr == 7) { - error = _("Password change failed - Password is too young"); - } else if (perr == 8) { - error = _("Password change failed - Password is in history"); - } - } else { - error = _("Unhandled error code: ") + http.status; - } - break; - case 404: - error = _("Password changing is not supported."); - break; - default: - error = _("Unhandled error code: ") + http.status; - } - showPasswordMessage(error); - } - } +function onPasswordChangeFailure(code, message) { + SetLogMessage("passwordError", message, "error"); } document.observe("dom:loaded", initPreferences); diff --git a/UI/WebServerResources/generic.css b/UI/WebServerResources/generic.css index 6472cae14..c72886558 100644 --- a/UI/WebServerResources/generic.css +++ b/UI/WebServerResources/generic.css @@ -568,14 +568,13 @@ DIV.resize-handle DIV.dialog { position: absolute; - top: 100px; - left: 75px; z-index: 50; } DIV.dialog DIV { border: 1px solid #444; background-color: #fff; padding: 5px; + width: 350px; padding-bottom: 26px; } DIV.dialog.left diff --git a/UI/WebServerResources/generic.js b/UI/WebServerResources/generic.js index 168723060..59596e8b1 100644 --- a/UI/WebServerResources/generic.js +++ b/UI/WebServerResources/generic.js @@ -1637,7 +1637,7 @@ function _(key) { while (topWindow.opener) topWindow = topWindow.opener; } - if (topWindow && topWindow.clabels[key]) + if (topWindow && topWindow.clabels && topWindow.clabels[key]) value = topWindow.clabels[key]; } @@ -1694,18 +1694,58 @@ AIM = { if (typeof(i.onComplete) == 'function') i.onComplete(d.body.innerHTML); } - }; +function createDialog(id, title, legend, content, positionClass) { + if (!positionClass) + positionClass = "left"; + var newDialog = createElement("div", id, ["dialog", positionClass]); + newDialog.setStyle({"display": "none"}); + + var subdiv = createElement("div", null, null, null, null, newDialog); + if (title && title.length > 0) { + var titleh3 = createElement("h3", null, null, null, null, subdiv); + titleh3.appendChild(document.createTextNode(title)); + } + if (legend && legend.length > 0) { + var legendP = createElement("p", null, null, null, null, subdiv); + legendP.appendChild(document.createTextNode(legend)); + } + if (content) + subdiv.appendChild(content); + + return newDialog; +} + +function createButton(id, caption, action) { + var newButton = createElement("a", id, "button", { "href": "#" }); + if (caption && caption.length > 0) { + var span = createElement("span", null, null, null, null, newButton); + span.appendChild(document.createTextNode(caption)); + } + if (action) + newButton.observe("click", action); + + return newButton; +} + function readCookie(name) { - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - for(var i=0;i < ca.length;i++) { - var c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1,c.length); - if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); - } - return null; + var foundCookie = null; + + var prefix = name + "="; + var pairs = document.cookie.split(';'); + for (var i = 0; !foundCookie && i < pairs.length; i++) { + var currentPair = pairs[i]; + var start = 0; + while (currentPair.charAt(start) == " ") + start++; + if (start > 0) + currentPair = currentPair.substr(start); + if (currentPair.indexOf(prefix) == 0) + foundCookie = currentPair.substr(prefix.length); + } + + return foundCookie; } function readLoginCookie() { @@ -1719,10 +1759,35 @@ function readLoginCookie() { return loginValues; } -function setLoginCookie(username, password) { - var value = (username + ":" + password).base64encode(); - var cookieValue = encodeURIComponent("basic " + value); - window.alert("0xHIGHFLYxSOGo=" + cookieValue); +/* logging widgets */ +function SetLogMessage(containerId, message, msgType) { + var container = $(containerId); + if (container) { + if (!msgType) + msgType = "error"; + var typeClass = msgType + "Message"; + if (!container.typeClass || container.typeClass != typeClass) { + if (container.typeClass) { + container.removeClassName(container.typeClass); + } + container.typeClass = typeClass; + container.addClassName(typeClass); + } + if (!container.message || container.message != message) { + while (container.lastChild) { + container.removeChild(container.lastChild); + } + if (message) { + var sentences = message.split("\n"); + container.appendChild(document.createTextNode(sentences[0])); + for (var i = 1; i < sentences.length; i++) { + container.appendChild(document.createElement("br")); + container.appendChild(document.createTextNode(sentences[i])); + } + container.message = message; + } + } + } } document.observe("dom:loaded", onLoadHandler);