Created
July 28, 2023 12:43
-
-
Save Pamblam/49fdb7dcb9a8fb90fb234cdf418ecc8d to your computer and use it in GitHub Desktop.
VCard Implementtaion in Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// See: https://www.rfc-editor.org/rfc/rfc6350 | |
class VCard{ | |
constructor(){ | |
this.kind = null; | |
this.name = []; | |
this.nickname = []; | |
this.photo = []; | |
this.bday = null; | |
this.anniversary = null; | |
this.gender = null; | |
this.gender_ident = null; | |
this.address = []; | |
} | |
// see: .rfc6350 3.2 line delimiting and formatting | |
formatTextValue(str){ | |
var chars = [...str]; | |
var max_line_bytes = 75; | |
var lines = []; | |
var curr_line = []; | |
var curr_line_bytes = 0; | |
for (let i = 0; i < chars.length; i++) { | |
var char = chars[i]; | |
if(char === ',') char = '\,'; | |
if(char === "\n") char = '\\n'; | |
var char_bytes = new Blob([char]).size; | |
if(curr_line_bytes + char_bytes > max_line_bytes){ | |
lines.push(curr_line.join('')); | |
curr_line = [' ', char]; | |
curr_line_bytes = 1 + char_bytes; | |
}else{ | |
curr_line.push(char); | |
curr_line_bytes += char_bytes; | |
} | |
} | |
lines.push(curr_line.join('')); | |
return lines.join("\n"); | |
} | |
formatDate(date){ | |
var [y, m, d, h, min, sec, ms] = date.toISOString().split(/[^\d]+/); | |
return `${y}${m}${d}T${h}${min}${sec}Z`; | |
} | |
imgToDataURI(img){ | |
var image = new Image(); | |
image.crossOrigin = 'Anonymous'; | |
image.onload = ()=>{ | |
var canvas = document.createElement('canvas'); | |
var context = canvas.getContext('2d'); | |
canvas.height = image.naturalHeight; | |
canvas.width = image.naturalWidth; | |
context.drawImage(image, 0, 0); | |
done(canvas.toDataURL('image/jpeg')); | |
}; | |
image.src = img.src; | |
} | |
setNickname(nickname){ | |
this.nickname.push(nickname); | |
return this; | |
} | |
setName(name){ | |
this.name.push(name); | |
return this; | |
} | |
setKind(kind){ | |
kind = kind.trim().toLowerCase(); | |
let allowed_values = [ | |
VCard.KIND_IND, | |
VCard.KIND_GRP, | |
VCard.KIND_ORG, | |
VCard.KIND_LOC | |
]; | |
if(!allowed_values.includes(kind)){ | |
throw new Error("Invalid Kind value."); | |
} | |
this.kind = kind; | |
return this; | |
} | |
setPhoto(img){ | |
if(!(img instanceof Image)){ | |
throw new Error('Invalid Image.'); | |
} | |
this.photo.push(img); | |
return this; | |
} | |
setBday(bday){ | |
if(!(bday instanceof Date)){ | |
throw new Error("Invalid Birthday date"); | |
} | |
this.bday = bday; | |
return this; | |
} | |
setAnniversary(anniversary){ | |
if(!(anniversary instanceof Date)){ | |
throw new Error("Invalid Anniversary date"); | |
} | |
this.anniversary = anniversary; | |
return this; | |
} | |
setGender(gender, ident=null){ | |
gender = gender.trim().toLowerCase(); | |
if(ident) ident = ident.trim().toLowerCase(); | |
let allowed_values = [ | |
VCard.GENDER_MAL, | |
VCard.GENDER_FEM, | |
VCard.GENDER_OTH, | |
VCard.GENDER_NON, | |
VCard.GENDER_UNK | |
]; | |
if(!allowed_values.includes(gender)){ | |
throw new Error("Invalid Gender value."); | |
} | |
this.gender = gender; | |
this.gender_ident = ident; | |
return this; | |
} | |
setAddress(){ | |
} | |
async render(){ | |
if(!this.name.length){ | |
throw new Error("Missing Name property."); | |
} | |
var parts = []; | |
parts.push('BEGIN:VCARD'); | |
parts.push('VERSION:4.0'); | |
if(this.kind){ | |
parts.push(`KIND:${this.kind}`); | |
} | |
for(let i=0; i<this.name.length; i++){ | |
parts.push(this.formatTextValue(`FN:${this.name[i]}`)); | |
} | |
if(this.nickname.length){ | |
parts.push(`NICKNAME:${this.formatTextValue(this.nickname.join(','))}`); | |
} | |
for(let i=0; i<this.photo.length; i++){ | |
let photo = await this.imgToDataURI(this.photo[i]); | |
parts.push(this.formatTextValue(`PHOTO:${photo}`)); | |
} | |
if(this.bday){ | |
parts.push(this.formatDate(`BDAY:${this.bday}`)); | |
} | |
if(this.anniversary){ | |
parts.push(this.formatDate(`ANNIVERSARY:${this.anniversary}`)); | |
} | |
if(this.gender){ | |
let gender = this.gender; | |
if(this.gender_ident) gender += `;${this.gender_ident}`; | |
parts.push(this.formatTextValue(`GENDER:${gender}`)); | |
} | |
parts.push('END:VCARD'); | |
} | |
} | |
VCard.KIND_IND = 'individual'; | |
VCard.KIND_GRP = 'group'; | |
VCard.KIND_ORG = 'org'; | |
VCard.KIND_LOC = 'location'; | |
VCard.GENDER_MAL = 'M'; | |
VCard.GENDER_FEM = 'F'; | |
VCard.GENDER_OTH = 'O'; | |
VCard.GENDER_NON = 'N'; | |
VCard.GENDER_UNK = 'U'; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment