working #37
@@ -22,7 +22,7 @@
|
||||
<div class="center">
|
||||
<div class="content-frame">
|
||||
<label>Company Website URL</label>
|
||||
<input class="input-field" name="url" [(ngModel)]="newListing.websiteURL" type="text" placeholder="https://mistox.com/" />
|
||||
<input class="input-field" name="url" [(ngModel)]="newListing.websiteURL" type="text" (blur)="validateURL(newListing.websiteURL)" placeholder="https://mistox.com/" />
|
||||
<button type="button" (click)="prevStep()">Back</button>
|
||||
<button type="button" (click)="nextStep()">Next</button>
|
||||
</div>
|
||||
|
||||
@@ -62,9 +62,12 @@ export class CompanyEditorComponent {
|
||||
|
||||
validateEmail(input: string){
|
||||
let result = this.validator.validateEmail(input);
|
||||
if (result[0]){
|
||||
this.newListing.email = result[1];
|
||||
}
|
||||
|
||||
validateURL(input: string){
|
||||
let result = this.validator.validateURL(input);
|
||||
this.newListing.websiteURL = result[1];
|
||||
}
|
||||
|
||||
@HostListener('window:keydown', ['$event'])
|
||||
@@ -146,6 +149,12 @@ export class CompanyEditorComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.validator.validateURL(company.websiteURL)[0]){
|
||||
this.ErrorMsg = "Website is invalid";
|
||||
this.focusFrame(3, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isNullOrEmpty(company.logo)){
|
||||
this.ErrorMsg = "Logo is blank";
|
||||
this.focusFrame(2, 0);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
</div>
|
||||
<h1>Public: </h1><input [name]="'active' + resume.trackUUID" [(ngModel)]="resume.isActive" type="checkbox" />
|
||||
<h1>Is Veteran: </h1><input [name]="'veteran' + resume.military?.trackUUID" type="checkbox" [checked]="resume.military !== null" (change)="onVeteranChange($event)" />
|
||||
<button type="button" (click)="PrintResume()">Print</button>
|
||||
</div>
|
||||
|
||||
<div class="paper">
|
||||
@@ -140,7 +139,7 @@
|
||||
<div class="resume-sub-section flex-two-row">
|
||||
<div>
|
||||
<input [name]="'certname' + cert.trackUUID" [(ngModel)]="cert.name" type="text" placeholder="Certification Name" />
|
||||
<input [name]="'certverificationURL' + cert.trackUUID" [(ngModel)]="cert.verificationURL" type="text" placeholder="Verification URL" />
|
||||
<input [name]="'certverificationURL' + cert.trackUUID" [(ngModel)]="cert.verificationURL" type="text" (blur)="validateCertURL(cert)" placeholder="Verification URL" />
|
||||
</div>
|
||||
<textarea [name]="'certdescription' + cert.trackUUID" [(ngModel)]="cert.description" placeholder="Description"></textarea>
|
||||
</div>
|
||||
@@ -156,7 +155,7 @@
|
||||
<div class="resume-sub-section flex-two-row">
|
||||
<div>
|
||||
<input [name]="'projname' + proj.trackUUID" [(ngModel)]="proj.name" type="text" placeholder="Project Name" />
|
||||
<input [name]="'projurl' + proj.trackUUID" [(ngModel)]="proj.url" type="text" placeholder="Reference URL" />
|
||||
<input [name]="'projurl' + proj.trackUUID" [(ngModel)]="proj.url" type="text" (blur)="validateProjectURL(proj)" placeholder="Reference URL" />
|
||||
</div>
|
||||
<textarea [name]="'projdescription' + proj.trackUUID" [(ngModel)]="proj.description" placeholder="Description"></textarea>
|
||||
</div>
|
||||
|
||||
@@ -90,32 +90,22 @@ export class ResumesEditorComponent {
|
||||
|
||||
validatePhone(input: string){
|
||||
let result = this.validator.validatePhoneNumber(input);
|
||||
if (result[0]){
|
||||
this.resume.phoneNumber = result[1];
|
||||
}
|
||||
}
|
||||
|
||||
validateEmail(input: string){
|
||||
let result = this.validator.validateEmail(input);
|
||||
if (result[0]){
|
||||
this.resume.email = result[1];
|
||||
}
|
||||
|
||||
validateCertURL(input: ResumeCertification){
|
||||
let result = this.validator.validateURL(input.verificationURL);
|
||||
input.verificationURL = result[1];
|
||||
}
|
||||
|
||||
PrintResume(){
|
||||
const divToPrint = document.getElementsByClassName("paper")[0];
|
||||
|
||||
const printContents = divToPrint.innerHTML;
|
||||
const originalContents = document.body.innerHTML; // Store original body content
|
||||
|
||||
// Temporarily replace the body content with the div's content
|
||||
document.body.innerHTML = printContents;
|
||||
|
||||
// Trigger the print dialog
|
||||
window.print();
|
||||
|
||||
// Restore the original body content
|
||||
document.body.innerHTML = originalContents;
|
||||
validateProjectURL(input: ResumeProject){
|
||||
let result = this.validator.validateURL(input.url);
|
||||
input.url = result[1];
|
||||
}
|
||||
|
||||
addExperience(){
|
||||
|
||||
@@ -25,11 +25,65 @@ export class Validation {
|
||||
}
|
||||
}
|
||||
|
||||
emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
|
||||
emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
validateEmail(input: string): [boolean, string] {
|
||||
const corrected = input.trim().toLowerCase();
|
||||
const trimmed = input.trim();
|
||||
const [local, domain] = trimmed.split('@');
|
||||
const corrected = domain ? `${local}@${domain.toLowerCase()}` : trimmed;
|
||||
|
||||
// Extra checks to avoid invalid formats
|
||||
if ( corrected.includes('..') || corrected.startsWith('.') || corrected.endsWith('.') ) {
|
||||
return [false, corrected];
|
||||
}
|
||||
|
||||
const success = this.emailRegex.test(corrected);
|
||||
return [success, corrected];
|
||||
}
|
||||
|
||||
validateURL(input: string): [boolean, string] {
|
||||
const testUrl = /^https?:\/\//i.test(input) ? input : "http://" + input;
|
||||
var urlToParse = new URL(testUrl);
|
||||
try {
|
||||
|
||||
if (urlToParse.protocol !== 'http:' && urlToParse.protocol !== 'https:') {
|
||||
return [false, urlToParse.href];
|
||||
}
|
||||
|
||||
const hostname = urlToParse.hostname.toLowerCase();
|
||||
if (hostname === 'localhost' || hostname.endsWith('.localhost')) {
|
||||
return [false, urlToParse.href];
|
||||
}
|
||||
|
||||
const privateIpRegex = /^(127\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)/;
|
||||
if (privateIpRegex.test(hostname)) {
|
||||
return [false, urlToParse.href];
|
||||
}
|
||||
|
||||
if (hostname.includes(':')) {
|
||||
if (this.isPrivateIPv6(hostname)) {
|
||||
return [false, urlToParse.href];
|
||||
}
|
||||
}
|
||||
|
||||
return [true, urlToParse.href.substring(0, urlToParse.href.length - 1)];
|
||||
} catch (e) {
|
||||
return [false, urlToParse.href];
|
||||
}
|
||||
}
|
||||
|
||||
///////// HELPER FUNCTIONS /////////
|
||||
|
||||
isPrivateIPv6(ip: string): boolean {
|
||||
try {
|
||||
const normalized = ip.replace(/^\[|\]$/g, '').toLowerCase();
|
||||
if (normalized === '::1') return true;
|
||||
if (normalized.startsWith('fc') || normalized.startsWith('fd')) return true;
|
||||
const first4 = normalized.slice(0, 4);
|
||||
if (first4 >= 'fe80' && first4 <= 'febf') return true;
|
||||
return false;
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user