Fix UI/UX issues:

Use blur event to instead focusout
Fix mail/ldap server testing spinner and button disabling issues
Fix content area/more info margins and make alert as overlay
fix reset password form issues
fix reset password style issue
fix tootip display inssue on reset form
commit index.html change
This commit is contained in:
Steven Zou 2017-04-06 11:31:20 +08:00
parent 69ebc92f87
commit 8f0285b4cb
15 changed files with 99 additions and 64 deletions

View File

@ -1,5 +1,6 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Harbor</title> <title>Harbor</title>
@ -7,11 +8,20 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico?v=2"> <link rel="icon" type="image/x-icon" href="favicon.ico?v=2">
</head> </head>
<body>
<harbor-app>Loading...</harbor-app> <body style="overflow-y: hidden;">
<script type="text/javascript" src="/static/inline.bundle.js"></script> <harbor-app>
<script type="text/javascript" src="/static/scripts.bundle.js"> <div class="spinner spinner-lg app-loading">
</script><script type="text/javascript" src="/static/styles.bundle.js"> Loading...
</script><script type="text/javascript" src="/static/vendor.bundle.js"></script> </div>
<script type="text/javascript" src="/static/main.bundle.js"></script></body> </harbor-app>
</html> <script type="text/javascript" src="/static/inline.bundle.js"></script>
<script type="text/javascript" src="/static/scripts.bundle.js">
</script>
<script type="text/javascript" src="/static/styles.bundle.js">
</script>
<script type="text/javascript" src="/static/vendor.bundle.js"></script>
<script type="text/javascript" src="/static/main.bundle.js"></script>
</body>
</html>

View File

@ -4,7 +4,7 @@
"description": "Harbor UI with Clarity", "description": "Harbor UI with Clarity",
"angular-cli": {}, "angular-cli": {},
"scripts": { "scripts": {
"start": "ng serve --ssl 1 --ssl-key --ssl-cert --host 0.0.0.0 --proxy-config proxy.config.json", "start": "ng serve --ssl 1 --ssl-key ssl/server.key --ssl-cert ssl/server.crt --host 0.0.0.0 --proxy-config proxy.config.json",
"lint": "tslint \"src/**/*.ts\"", "lint": "tslint \"src/**/*.ts\"",
"test": "ng test --single-run", "test": "ng test --single-run",
"pree2e": "webdriver-manager update", "pree2e": "webdriver-manager update",

View File

@ -16,7 +16,7 @@
email email
id="account_settings_email" size="30" id="account_settings_email" size="30"
(input)='handleValidation("account_settings_email", false)' (input)='handleValidation("account_settings_email", false)'
(focusout)='handleValidation("account_settings_email", true)'> (blur)='handleValidation("account_settings_email", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{emailTooltip | translate}} {{emailTooltip | translate}}
</span> </span>
@ -25,7 +25,7 @@
<div class="form-group form-group-override"> <div class="form-group form-group-override">
<label for="account_settings_full_name" class="required form-group-label-override">{{'PROFILE.FULL_NAME' | translate}}</label> <label for="account_settings_full_name" class="required form-group-label-override">{{'PROFILE.FULL_NAME' | translate}}</label>
<label for="account_settings_full_name" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left" [class.invalid]='!getValidationState("account_settings_full_name")'> <label for="account_settings_full_name" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left" [class.invalid]='!getValidationState("account_settings_full_name")'>
<input type="text" name="account_settings_full_name" #fullNameInput="ngModel" [(ngModel)]="account.realname" required maxLengthExt="20" id="account_settings_full_name" size="30" (input)='handleValidation("account_settings_full_name", false)' (focusout)='handleValidation("account_settings_full_name", true)'> <input type="text" name="account_settings_full_name" #fullNameInput="ngModel" [(ngModel)]="account.realname" required maxLengthExt="20" id="account_settings_full_name" size="30" (input)='handleValidation("account_settings_full_name", false)' (blur)='handleValidation("account_settings_full_name", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.FULL_NAME' | translate}} {{'TOOLTIP.FULL_NAME' | translate}}
</span> </span>

View File

@ -14,7 +14,7 @@
id="reset_pwd_email" id="reset_pwd_email"
size="40" size="40"
(input)="handleValidation(true)" (input)="handleValidation(true)"
(focusout)="handleValidation(false)"> (blur)="handleValidation(false)">
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.EMAIL' | translate}} {{'TOOLTIP.EMAIL' | translate}}
</span> </span>
@ -25,7 +25,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<span class="spinner spinner-inline" style="top:8px;" [hidden]="showProgress === false"></span> <span class="spinner spinner-inline" style="top:8px;" [hidden]="showProgress === false"></span>
<button type="button" class="btn btn-outline" (click)="close()">{{btnCancelCaption | translate}}</button> <button type="button" class="btn" [class.btn-outline]="!isSuccess" [class.btn-primary]="isSuccess" (click)="close()">{{btnCancelCaption | translate}}</button>
<button *ngIf="!isSuccess" type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.SEND' | translate}}</button> <button *ngIf="!isSuccess" type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.SEND' | translate}}</button>
</div> </div>
</clr-modal> </clr-modal>

View File

@ -27,7 +27,7 @@
[(ngModel)]="newPwd" [(ngModel)]="newPwd"
#newPassInput="ngModel" size="42" #newPassInput="ngModel" size="42"
(input)='handleValidation("newPassword", false)' (input)='handleValidation("newPassword", false)'
(focusout)='handleValidation("newPassword", true)'> (blur)='handleValidation("newPassword", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.PASSWORD' | translate}} {{'TOOLTIP.PASSWORD' | translate}}
</span> </span>
@ -44,7 +44,7 @@
[(ngModel)]="reNewPwd" [(ngModel)]="reNewPwd"
#reNewPassInput="ngModel" size="42" #reNewPassInput="ngModel" size="42"
(input)='handleValidation("reNewPassword", false)' (input)='handleValidation("reNewPassword", false)'
(focusout)='handleValidation("reNewPassword", true)'> (blur)='handleValidation("reNewPassword", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.CONFIRM_PWD' | translate}} {{'TOOLTIP.CONFIRM_PWD' | translate}}
</span> </span>

View File

@ -1,12 +1,13 @@
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="true" [clrModalClosable]="false"> <clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="true" [clrModalClosable]="false">
<h3 class="modal-title">{{'RESET_PWD.TITLE' | translate}}</h3> <h3 class="modal-title">{{'RESET_PWD.TITLE' | translate}}</h3>
<label class="modal-title reset-modal-title-override">{{'RESET_PWD.CAPTION2' | translate}}</label> <label class="modal-title reset-modal-title-override">{{'RESET_PWD.CAPTION2' | translate}}</label>
<inline-alert class="modal-title"></inline-alert>
<div class="modal-body" style="overflow-y: hidden;"> <div class="modal-body" style="overflow-y: hidden;">
<form #resetPwdForm="ngForm" class="form"> <form #resetPwdForm="ngForm" class="form">
<section class="form-block"> <section class="form-block">
<div class="form-group"> <div class="form-group">
<label for="newPassword" class="form-group-label-override">{{'CHANGE_PWD.NEW_PWD' | translate}}</label> <label for="newPassword" class="form-group-label-override">{{'CHANGE_PWD.NEW_PWD' | translate}}</label>
<label for="newPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("newPassword") === false'> <label for="newPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='!getValidationState("newPassword")'>
<input [disabled]="resetOk" type="password" id="newPassword" placeholder='{{"PLACEHOLDER.NEW_PWD" | translate}}' <input [disabled]="resetOk" type="password" id="newPassword" placeholder='{{"PLACEHOLDER.NEW_PWD" | translate}}'
required required
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$" pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$"
@ -14,8 +15,8 @@
[(ngModel)]="password" [(ngModel)]="password"
#newPassInput="ngModel" #newPassInput="ngModel"
size="25" size="25"
(input)='handleValidation("newPassword", true)' (input)='handleValidation("newPassword", false)'
(focusout)='handleValidation("newPassword", false)'> (blur)='handleValidation("newPassword", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.PASSWORD' | translate}} {{'TOOLTIP.PASSWORD' | translate}}
</span> </span>
@ -23,7 +24,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="reNewPassword" class="form-group-label-override">{{'CHANGE_PWD.CONFIRM_PWD' | translate}}</label> <label for="reNewPassword" class="form-group-label-override">{{'CHANGE_PWD.CONFIRM_PWD' | translate}}</label>
<label for="reNewPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("reNewPassword") === false'> <label for="reNewPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left" [class.invalid]='!getValidationState("reNewPassword")'>
<input [disabled]="resetOk" type="password" id="reNewPassword" placeholder='{{"PLACEHOLDER.CONFIRM_PWD" | translate}}' <input [disabled]="resetOk" type="password" id="reNewPassword" placeholder='{{"PLACEHOLDER.CONFIRM_PWD" | translate}}'
required required
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$" pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$"
@ -31,21 +32,19 @@
[(ngModel)]="confirmPwd" [(ngModel)]="confirmPwd"
#reNewPassInput #reNewPassInput
size="25" size="25"
(input)='handleValidation("reNewPassword", true)' (input)='handleValidation("reNewPassword", false)'
(focusout)='handleValidation("reNewPassword", false)'> (blur)='handleValidation("reNewPassword", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.CONFIRM_PWD' | translate}} {{'TOOLTIP.CONFIRM_PWD' | translate}}
</span> </span>
</label> </label>
</div> </div>
</section> </section>
<inline-alert></inline-alert>
<div style="height: 30px;"></div>
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<span class="spinner spinner-inline" style="top:8px;" [hidden]="showProgress === false"></span> <span class="spinner spinner-inline" style="top:8px;" [hidden]="showProgress === false"></span>
<button type="button" class="btn btn-outline" (click)="close()">{{btnCancelCaption | translate}}</button> <button type="button" class="btn" [class.btn-outline]="!resetOk" [class.btn-primary]="resetOk" (click)="close()">{{btnCancelCaption | translate}}</button>
<button *ngIf="!resetOk" type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.OK' | translate}}</button> <button *ngIf="!resetOk" type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.OK' | translate}}</button>
</div> </div>
</clr-modal> </clr-modal>

View File

@ -56,8 +56,7 @@ export class ResetPasswordComponent implements OnInit {
public getValidationState(key: string): boolean { public getValidationState(key: string): boolean {
return this.validationState && return this.validationState &&
this.validationState[key] && this.validationState[key];
key === 'reNewPassword' ? this.samePassword() : true;
} }
public open(): void { public open(): void {
@ -109,10 +108,8 @@ export class ResetPasswordComponent implements OnInit {
} }
public handleValidation(key: string, flag: boolean): void { public handleValidation(key: string, flag: boolean): void {
if (flag) { if (!flag) {
if (!this.validationState[key]) { this.validationState[key] = true;
this.validationState[key] = true;
}
} else { } else {
this.validationState[key] = this.getControlValidationState(key); this.validationState[key] = this.getControlValidationState(key);
if (this.validationState[key]) { if (this.validationState[key]) {

View File

@ -38,6 +38,7 @@
.more-info-link { .more-info-link {
position: relative; position: relative;
top: 90px; top: 80px;
left: 330px; left: 294px;
padding-right: 36px;
} }

View File

@ -13,5 +13,15 @@
} }
.content-area-override { .content-area-override {
padding: 24px 36px !important; padding: 36px !important;
padding-right: 21px !important;
}
.global-message-alert {
position: fixed;
top: 55px;
left: 260px;
width: 100%;
z-index: 999;
padding-right: 276px;
} }

View File

@ -3,7 +3,9 @@
<navigator (showAccountSettingsModal)="openModal($event)" (showPwdChangeModal)="openModal($event)"></navigator> <navigator (showAccountSettingsModal)="openModal($event)" (showPwdChangeModal)="openModal($event)"></navigator>
<div class="content-container"> <div class="content-container">
<div class="content-area" [class.container-override]="showSearch" [class.content-area-override]="!shouldOverrideContent" [class.start-content-padding]="shouldOverrideContent"> <div class="content-area" [class.container-override]="showSearch" [class.content-area-override]="!shouldOverrideContent" [class.start-content-padding]="shouldOverrideContent">
<global-message [isAppLevel]="false"></global-message> <div class="global-message-alert">
<global-message [isAppLevel]="false"></global-message>
</div>
<!-- Only appear when searching --> <!-- Only appear when searching -->
<search-result></search-result> <search-result></search-result>
<router-outlet></router-outlet> <router-outlet></router-outlet>

View File

@ -65,7 +65,8 @@
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL' | translate}}</button> <button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-outline" (click)="testMailServer()" *ngIf="showTestServerBtn" [disabled]="!isMailConfigValid()">{{'BUTTON.TEST_MAIL' | translate}}</button> <button type="button" class="btn btn-outline" (click)="testMailServer()" *ngIf="showTestServerBtn" [disabled]="!isMailConfigValid()">{{'BUTTON.TEST_MAIL' | translate}}</button>
<button type="button" class="btn btn-outline" (click)="testLDAPServer()" *ngIf="showLdapServerBtn" [disabled]="!isLDAPConfigValid()">{{'BUTTON.TEST_LDAP' | translate}}</button> <button type="button" class="btn btn-outline" (click)="testLDAPServer()" *ngIf="showLdapServerBtn" [disabled]="!isLDAPConfigValid()">{{'BUTTON.TEST_LDAP' | translate}}</button>
<span class="spinner spinner-inline" [hidden]="!testingInProgress"></span> <span id="forTestingMail" class="spinner spinner-inline" [hidden]="hideMailTestingSpinner"></span>
<span id="forTestingLDAP" class="spinner spinner-inline" [hidden]="hideLDAPTestingSpinner"></span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -17,7 +17,7 @@ import { AppConfigService } from '../app-config.service';
import { SessionService } from '../shared/session.service'; import { SessionService } from '../shared/session.service';
import { MessageHandlerService } from '../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
const fakePass = "fakepassword"; const fakePass = "aWpLOSYkIzJTTU4wMDkx";
const TabLinkContentMap = { const TabLinkContentMap = {
"config-auth": "authentication", "config-auth": "authentication",
"config-replication": "replication", "config-replication": "replication",
@ -36,7 +36,8 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
private currentTabId: string = "config-auth";//default tab private currentTabId: string = "config-auth";//default tab
private originalCopy: Configuration; private originalCopy: Configuration;
private confirmSub: Subscription; private confirmSub: Subscription;
private testingOnGoing: boolean = false; private testingMailOnGoing: boolean = false;
private testingLDAPOnGoing: boolean = false;
@ViewChild("repoConfigFrom") repoConfigForm: NgForm; @ViewChild("repoConfigFrom") repoConfigForm: NgForm;
@ViewChild("systemConfigFrom") systemConfigForm: NgForm; @ViewChild("systemConfigFrom") systemConfigForm: NgForm;
@ -131,10 +132,6 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
return this.onGoing; return this.onGoing;
} }
public get testingInProgress(): boolean {
return this.testingOnGoing;
}
public isValid(): boolean { public isValid(): boolean {
return this.repoConfigForm && return this.repoConfigForm &&
this.repoConfigForm.valid && this.repoConfigForm.valid &&
@ -152,7 +149,8 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
public isMailConfigValid(): boolean { public isMailConfigValid(): boolean {
return this.mailConfig && return this.mailConfig &&
this.mailConfig.isValid(); this.mailConfig.isValid() &&
!this.testingMailOnGoing;
} }
public get showTestServerBtn(): boolean { public get showTestServerBtn(): boolean {
@ -165,8 +163,18 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
this.allConfig.auth_mode.value === "ldap_auth"; this.allConfig.auth_mode.value === "ldap_auth";
} }
public get hideMailTestingSpinner(): boolean {
return !this.testingMailOnGoing || !this.showTestServerBtn;
}
public get hideLDAPTestingSpinner(): boolean {
return !this.testingLDAPOnGoing || !this.showLdapServerBtn;
}
public isLDAPConfigValid(): boolean { public isLDAPConfigValid(): boolean {
return this.authConfig && this.authConfig.isValid(); return this.authConfig &&
this.authConfig.isValid() &&
!this.testingLDAPOnGoing;
} }
public tabLinkClick(tabLink: string) { public tabLinkClick(tabLink: string) {
@ -239,6 +247,9 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
* @memberOf ConfigurationComponent * @memberOf ConfigurationComponent
*/ */
public testMailServer(): void { public testMailServer(): void {
if(this.testingMailOnGoing){
return;//Should not come here
}
let mailSettings = {}; let mailSettings = {};
for (let prop in this.allConfig) { for (let prop in this.allConfig) {
if (prop.startsWith("email_")) { if (prop.startsWith("email_")) {
@ -255,23 +266,27 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
delete mailSettings["email_password"]; delete mailSettings["email_password"];
} }
this.testingOnGoing = true; this.testingMailOnGoing = true;
this.configService.testMailServer(mailSettings) this.configService.testMailServer(mailSettings)
.then(response => { .then(response => {
this.testingOnGoing = false; this.testingMailOnGoing = false;
this.msgHandler.showSuccess("CONFIG.TEST_MAIL_SUCCESS"); this.msgHandler.showSuccess("CONFIG.TEST_MAIL_SUCCESS");
}) })
.catch(error => { .catch(error => {
this.testingOnGoing = false; this.testingMailOnGoing = false;
let err = error._body; let err = error._body;
if(!err){ if (!err) {
err = "UNKNOWN"; err = "UNKNOWN";
} }
this.msgHandler.showError("CONFIG.TEST_MAIL_FAILED", {'param': err}); this.msgHandler.showError("CONFIG.TEST_MAIL_FAILED", { 'param': err });
}); });
} }
public testLDAPServer(): void { public testLDAPServer(): void {
if(this.testingLDAPOnGoing){
return;//Should not come here
}
let ldapSettings = {}; let ldapSettings = {};
for (let prop in this.allConfig) { for (let prop in this.allConfig) {
if (prop.startsWith("ldap_")) { if (prop.startsWith("ldap_")) {
@ -281,25 +296,25 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
let allChanges = this.getChanges(); let allChanges = this.getChanges();
let ldapSearchPwd = allChanges["ldap_search_password"]; let ldapSearchPwd = allChanges["ldap_search_password"];
if(ldapSearchPwd){ if (ldapSearchPwd) {
ldapSettings['ldap_search_password'] = ldapSearchPwd; ldapSettings['ldap_search_password'] = ldapSearchPwd;
}else{ } else {
delete ldapSettings['ldap_search_password']; delete ldapSettings['ldap_search_password'];
} }
this.testingOnGoing = true; this.testingLDAPOnGoing = true;
this.configService.testLDAPServer(ldapSettings) this.configService.testLDAPServer(ldapSettings)
.then(respone => { .then(respone => {
this.testingOnGoing = false; this.testingLDAPOnGoing = false;
this.msgHandler.showSuccess("CONFIG.TEST_LDAP_SUCCESS"); this.msgHandler.showSuccess("CONFIG.TEST_LDAP_SUCCESS");
}) })
.catch(error => { .catch(error => {
this.testingOnGoing = false; this.testingLDAPOnGoing = false;
let err = error._body; let err = error._body;
if(!err){ if (!err) {
err = "UNKNOWN"; err = "UNKNOWN";
} }
this.msgHandler.showError("CONFIG.TEST_LDAP_FAILED", {'param': err}); this.msgHandler.showError("CONFIG.TEST_LDAP_FAILED", { 'param': err });
}); });
} }

View File

@ -53,7 +53,7 @@ export class MessageComponent implements OnInit, OnDestroy {
// Make the message alert bar dismiss after several intervals. // Make the message alert bar dismiss after several intervals.
//Only for this case //Only for this case
this.timer = setTimeout(() => this.onClose(), dismissInterval); //this.timer = setTimeout(() => this.onClose(), dismissInterval);
} }
); );
} }

View File

@ -1,6 +1,6 @@
<div class="row"> <div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="row flex-items-xs-between flex-items-xs-top"> <div class="row flex-items-xs-between flex-items-xs-top" style="padding-left: 15px; padding-right: 15px;">
<h2 class="header-title">{{'PROJECT.PROJECTS' | translate}}</h2> <h2 class="header-title">{{'PROJECT.PROJECTS' | translate}}</h2>
<div> <div>
<statistics-panel></statistics-panel> <statistics-panel></statistics-panel>
@ -13,7 +13,7 @@
</div> </div>
<div class="option-right"> <div class="option-right">
<div class="select" style="float: left;"> <div class="select" style="float: left;">
<select (change)="doFilterProjects($event)"> <select (change)="doFilterProjects($event)">
<option value="0">{{projectTypes[0] | translate}}</option> <option value="0">{{projectTypes[0] | translate}}</option>
<option value="1">{{projectTypes[1] | translate}}</option> <option value="1">{{projectTypes[1] | translate}}</option>
</select> </select>

View File

@ -6,7 +6,7 @@
<label for="username" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("username")'> <label for="username" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("username")'>
<input type="text" required pattern='[^"~#$%]+' maxLengthExt="20" #usernameInput="ngModel" name="username" [(ngModel)]="newUser.username" id="username" size="36" <input type="text" required pattern='[^"~#$%]+' maxLengthExt="20" #usernameInput="ngModel" name="username" [(ngModel)]="newUser.username" id="username" size="36"
(input)='handleValidation("username", false)' (input)='handleValidation("username", false)'
(focusout)='handleValidation("username", true)'> (blur)='handleValidation("username", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{usernameTooltip | translate}} {{usernameTooltip | translate}}
</span> </span>
@ -20,7 +20,7 @@
email email
id="email" size="36" id="email" size="36"
(input)='handleValidation("email", false)' (input)='handleValidation("email", false)'
(focusout)='handleValidation("email", true)'> (blur)='handleValidation("email", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{emailTooltip | translate}} {{emailTooltip | translate}}
</span> </span>
@ -33,7 +33,7 @@
<label for="realname" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("realname")'> <label for="realname" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("realname")'>
<input type="text" name="realname" #fullNameInput="ngModel" [(ngModel)]="newUser.realname" required maxLengthExt="20" id="realname" size="36" <input type="text" name="realname" #fullNameInput="ngModel" [(ngModel)]="newUser.realname" required maxLengthExt="20" id="realname" size="36"
(input)='handleValidation("realname", false)' (input)='handleValidation("realname", false)'
(focusout)='handleValidation("realname", true)'> (blur)='handleValidation("realname", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.FULL_NAME' | translate}} {{'TOOLTIP.FULL_NAME' | translate}}
</span> </span>
@ -49,7 +49,7 @@
[(ngModel)]="newUser.password" [(ngModel)]="newUser.password"
#newPassInput="ngModel" size="36" #newPassInput="ngModel" size="36"
(input)='handleValidation("newPassword", false)' (input)='handleValidation("newPassword", false)'
(focusout)='handleValidation("newPassword", true)'> (blur)='handleValidation("newPassword", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.PASSWORD' | translate}} {{'TOOLTIP.PASSWORD' | translate}}
</span> </span>
@ -66,7 +66,7 @@
[(ngModel)]="confirmedPwd" [(ngModel)]="confirmedPwd"
#confirmPassInput="ngModel" size="36" #confirmPassInput="ngModel" size="36"
(input)='handleValidation("confirmPassword", false)' (input)='handleValidation("confirmPassword", false)'
(focusout)='handleValidation("confirmPassword", true)'> (blur)='handleValidation("confirmPassword", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.CONFIRM_PWD' | translate}} {{'TOOLTIP.CONFIRM_PWD' | translate}}
</span> </span>
@ -77,7 +77,7 @@
<label for="comment" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("comment")'> <label for="comment" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='getValidationState("comment")'>
<input type="text" #commentInput="ngModel" name="comment" [(ngModel)]="newUser.comment" maxLengthExt="20" id="comment" size="36" <input type="text" #commentInput="ngModel" name="comment" [(ngModel)]="newUser.comment" maxLengthExt="20" id="comment" size="36"
(input)='handleValidation("comment", false)' (input)='handleValidation("comment", false)'
(focusout)='handleValidation("comment", true)'> (blur)='handleValidation("comment", true)'>
<span class="tooltip-content"> <span class="tooltip-content">
{{'TOOLTIP.COMMENT' | translate}} {{'TOOLTIP.COMMENT' | translate}}
</span> </span>